#+BEGIN_SRC emacs-lisp
(if (>= emacs-major-version 24)
(progn
- (add-to-list 'load-path "~/.emacs.d/elpa/async-20160108.1249")
+ (add-to-list 'load-path "~/.emacs.d/elpa/async-20161103.1036")
(require 'async)
)
)
(if (>= emacs-major-version 24)
(progn
(add-to-list 'load-path "~/.emacs.d/elpa/smartparens-20160217.1102")
- (add-to-list 'load-path "~/.emacs.d/elpa/dash-20151216.1315")
+ (add-to-list 'load-path "~/.emacs.d/elpa/dash-20161116.920")
(require 'smartparens)
(smartparens-global-mode 1)
(defmacro def-pairs (pairs)
+++ /dev/null
-;;; async-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
-\f
-;;;### (autoloads nil "async" "async.el" (22215 9106 0 0))
-;;; Generated autoloads from async.el
-
-(autoload 'async-start-process "async" "\
-Start the executable PROGRAM asynchronously. See `async-start'.
-PROGRAM is passed PROGRAM-ARGS, calling FINISH-FUNC with the
-process object when done. If FINISH-FUNC is nil, the future
-object will return the process object when the program is
-finished. Set DEFAULT-DIRECTORY to change PROGRAM's current
-working directory.
-
-\(fn NAME PROGRAM FINISH-FUNC &rest PROGRAM-ARGS)" nil nil)
-
-(autoload 'async-start "async" "\
-Execute START-FUNC (often a lambda) in a subordinate Emacs process.
-When done, the return value is passed to FINISH-FUNC. Example:
-
- (async-start
- ;; What to do in the child process
- (lambda ()
- (message \"This is a test\")
- (sleep-for 3)
- 222)
-
- ;; What to do when it finishes
- (lambda (result)
- (message \"Async process done, result should be 222: %s\"
- result)))
-
-If FINISH-FUNC is nil or missing, a future is returned that can
-be inspected using `async-get', blocking until the value is
-ready. Example:
-
- (let ((proc (async-start
- ;; What to do in the child process
- (lambda ()
- (message \"This is a test\")
- (sleep-for 3)
- 222))))
-
- (message \"I'm going to do some work here\") ;; ....
-
- (message \"Waiting on async process, result should be 222: %s\"
- (async-get proc)))
-
-If you don't want to use a callback, and you don't care about any
-return value form the child process, pass the `ignore' symbol as
-the second argument (if you don't, and never call `async-get', it
-will leave *emacs* process buffers hanging around):
-
- (async-start
- (lambda ()
- (delete-file \"a remote file on a slow link\" nil))
- 'ignore)
-
-Note: Even when FINISH-FUNC is present, a future is still
-returned except that it yields no value (since the value is
-passed to FINISH-FUNC). Call `async-get' on such a future always
-returns nil. It can still be useful, however, as an argument to
-`async-ready' or `async-wait'.
-
-\(fn START-FUNC &optional FINISH-FUNC)" nil nil)
-
-;;;***
-\f
-;;;### (autoloads nil "async-bytecomp" "async-bytecomp.el" (22215
-;;;;;; 9106 0 0))
-;;; Generated autoloads from async-bytecomp.el
-
-(autoload 'async-byte-recompile-directory "async-bytecomp" "\
-Compile all *.el files in DIRECTORY asynchronously.
-All *.elc files are systematically deleted before proceeding.
-
-\(fn DIRECTORY &optional QUIET)" nil nil)
-
-(defvar async-bytecomp-package-mode nil "\
-Non-nil if Async-Bytecomp-Package mode is enabled.
-See the command `async-bytecomp-package-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `async-bytecomp-package-mode'.")
-
-(custom-autoload 'async-bytecomp-package-mode "async-bytecomp" nil)
-
-(autoload 'async-bytecomp-package-mode "async-bytecomp" "\
-Byte compile asynchronously packages installed with package.el.
-Async compilation of packages can be controlled by
-`async-bytecomp-allowed-packages'.
-
-\(fn &optional ARG)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "dired-async" "dired-async.el" (22215 9106
-;;;;;; 0 0))
-;;; Generated autoloads from dired-async.el
-
-(defvar dired-async-mode nil "\
-Non-nil if Dired-Async mode is enabled.
-See the command `dired-async-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `dired-async-mode'.")
-
-(custom-autoload 'dired-async-mode "dired-async" nil)
-
-(autoload 'dired-async-mode "dired-async" "\
-Do dired actions asynchronously.
-
-\(fn &optional ARG)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil nil ("async-pkg.el" "smtpmail-async.el") (22215
-;;;;;; 9106 560243 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; End:
-;;; async-autoloads.el ends here
+++ /dev/null
-;;; async-bytecomp.el --- Async functions to compile elisp files async
-
-;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
-
-;; Authors: John Wiegley <jwiegleyNOSPAMgmail.com>
-;; Thierry Volpiatto <thierry.volpiattoNOSPAMgmail.com>
-
-;; Keywords: dired async byte-compile
-;; X-URL: https://github.com/jwiegley/dired-async
-
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2, or (at
-;; your option) any later version.
-
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-;;
-;; This package provide the `async-byte-recompile-directory' function
-;; which allows, as the name says to recompile a directory outside of
-;; your running emacs.
-;; The benefit is your files will be compiled in a clean environment without
-;; the old *.el files loaded.
-;; Among other things, this fix a bug in package.el which recompile
-;; the new files in the current environment with the old files loaded, creating
-;; errors in most packages after upgrades.
-;;
-;; NB: This package is advicing the function `package--compile'.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'async)
-
-(defcustom async-bytecomp-allowed-packages
- '(async helm helm-core helm-ls-git helm-ls-hg magit)
- "Packages in this list will be compiled asynchronously by `package--compile'.
-All the dependencies of these packages will be compiled async too,
-so no need to add dependencies to this list.
-The value of this variable can also be a list with a single element,
-the symbol `all', in this case packages are always compiled asynchronously."
- :group 'async
- :type '(repeat (choice symbol)))
-
-(defvar async-byte-compile-log-file "~/.emacs.d/async-bytecomp.log")
-
-;;;###autoload
-(defun async-byte-recompile-directory (directory &optional quiet)
- "Compile all *.el files in DIRECTORY asynchronously.
-All *.elc files are systematically deleted before proceeding."
- (cl-loop with dir = (directory-files directory t "\\.elc\\'")
- unless dir return nil
- for f in dir
- when (file-exists-p f) do (delete-file f))
- ;; Ensure async is reloaded when async.elc is deleted.
- ;; This happen when recompiling its own directory.
- (load "async")
- (let ((call-back
- `(lambda (&optional ignore)
- (if (file-exists-p async-byte-compile-log-file)
- (let ((buf (get-buffer-create byte-compile-log-buffer))
- (n 0))
- (with-current-buffer buf
- (goto-char (point-max))
- (let ((inhibit-read-only t))
- (insert-file-contents async-byte-compile-log-file)
- (compilation-mode))
- (display-buffer buf)
- (delete-file async-byte-compile-log-file)
- (unless ,quiet
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward "^.*:Error:" nil t)
- (cl-incf n)))
- (if (> n 0)
- (message "Failed to compile %d files in directory `%s'" n ,directory)
- (message "Directory `%s' compiled asynchronously with warnings" ,directory)))))
- (unless ,quiet
- (message "Directory `%s' compiled asynchronously with success" ,directory))))))
- (async-start
- `(lambda ()
- (require 'bytecomp)
- ,(async-inject-variables "\\`\\(load-path\\)\\|byte\\'")
- (let ((default-directory (file-name-as-directory ,directory))
- error-data)
- (add-to-list 'load-path default-directory)
- (byte-recompile-directory ,directory 0 t)
- (when (get-buffer byte-compile-log-buffer)
- (setq error-data (with-current-buffer byte-compile-log-buffer
- (buffer-substring-no-properties (point-min) (point-max))))
- (unless (string= error-data "")
- (with-temp-file ,async-byte-compile-log-file
- (erase-buffer)
- (insert error-data))))))
- call-back)
- (unless quiet (message "Started compiling asynchronously directory %s" directory))))
-
-(defvar package-archive-contents)
-(defvar package-alist)
-(declare-function package-desc-reqs "package.el" (cl-x))
-
-(defun async-bytecomp--get-package-deps (pkg &optional only)
- ;; Same as `package--get-deps' but parse instead `package-archive-contents'
- ;; because PKG is not already installed and not present in `package-alist'.
- ;; However fallback to `package-alist' in case PKG no more present
- ;; in `package-archive-contents' due to modification to `package-archives'.
- ;; See issue #58.
- (let* ((pkg-desc (cadr (or (assq pkg package-archive-contents)
- (assq pkg package-alist))))
- (direct-deps (cl-loop for p in (package-desc-reqs pkg-desc)
- for name = (car p)
- when (or (assq name package-archive-contents)
- (assq name package-alist))
- collect name))
- (indirect-deps (unless (eq only 'direct)
- (delete-dups
- (cl-loop for p in direct-deps append
- (async-bytecomp--get-package-deps p))))))
- (cl-case only
- (direct direct-deps)
- (separate (list direct-deps indirect-deps))
- (indirect indirect-deps)
- (t (delete-dups (append direct-deps indirect-deps))))))
-
-(defun async-bytecomp-get-allowed-pkgs ()
- (when (and async-bytecomp-allowed-packages
- (listp async-bytecomp-allowed-packages))
- (if package-archive-contents
- (cl-loop for p in async-bytecomp-allowed-packages
- when (assq p package-archive-contents)
- append (async-bytecomp--get-package-deps p) into reqs
- finally return
- (delete-dups
- (append async-bytecomp-allowed-packages reqs)))
- async-bytecomp-allowed-packages)))
-
-(defadvice package--compile (around byte-compile-async)
- (let ((cur-package (package-desc-name pkg-desc))
- (pkg-dir (package-desc-dir pkg-desc)))
- (if (or (equal async-bytecomp-allowed-packages '(all))
- (memq cur-package (async-bytecomp-get-allowed-pkgs)))
- (progn
- (when (eq cur-package 'async)
- (fmakunbound 'async-byte-recompile-directory))
- ;; Add to `load-path' the latest version of async and
- ;; reload it when reinstalling async.
- (when (string= cur-package "async")
- (cl-pushnew pkg-dir load-path)
- (load "async-bytecomp"))
- ;; `async-byte-recompile-directory' will add directory
- ;; as needed to `load-path'.
- (async-byte-recompile-directory (package-desc-dir pkg-desc) t))
- ad-do-it)))
-
-;;;###autoload
-(define-minor-mode async-bytecomp-package-mode
- "Byte compile asynchronously packages installed with package.el.
-Async compilation of packages can be controlled by
-`async-bytecomp-allowed-packages'."
- :group 'async
- :global t
- (if async-bytecomp-package-mode
- (ad-activate 'package--compile)
- (ad-deactivate 'package--compile)))
-
-(provide 'async-bytecomp)
-
-;;; async-bytecomp.el ends here
+++ /dev/null
-(define-package "async" "20160108.1249" "Asynchronous processing in Emacs" 'nil :keywords
- '("async")
- :url "http://elpa.gnu.org/packages/async.html")
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; async.el --- Asynchronous processing in Emacs
-
-;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
-
-;; Author: John Wiegley <jwiegleyNOSPAMgmail.com>
-;; Created: 18 Jun 2012
-;; Version: 1.6
-
-;; Keywords: async
-;; X-URL: https://github.com/jwiegley/emacs-async
-
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2, or (at
-;; your option) any later version.
-
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-\f
-;;; Commentary:
-
-;; Adds the ability to call asynchronous functions and process with ease. See
-;; the documentation for `async-start' and `async-start-process'.
-\f
-;;; Code:
-
-(defgroup async nil
- "Simple asynchronous processing in Emacs"
- :group 'emacs)
-
-(defvar async-debug nil)
-(defvar async-send-over-pipe t)
-(defvar async-in-child-emacs nil)
-(defvar async-callback nil)
-(defvar async-callback-for-process nil)
-(defvar async-callback-value nil)
-(defvar async-callback-value-set nil)
-(defvar async-current-process nil)
-(defvar async--procvar nil)
-
-(defun async-inject-variables
- (include-regexp &optional predicate exclude-regexp)
- "Return a `setq' form that replicates part of the calling environment.
-It sets the value for every variable matching INCLUDE-REGEXP and
-also PREDICATE. It will not perform injection for any variable
-matching EXCLUDE-REGEXP (if present). It is intended to be used
-as follows:
-
- (async-start
- `(lambda ()
- (require 'smtpmail)
- (with-temp-buffer
- (insert ,(buffer-substring-no-properties (point-min) (point-max)))
- ;; Pass in the variable environment for smtpmail
- ,(async-inject-variables \"\\`\\(smtpmail\\|\\(user-\\)?mail\\)-\")
- (smtpmail-send-it)))
- 'ignore)"
- `(setq
- ,@(let (bindings)
- (mapatoms
- (lambda (sym)
- (if (and (boundp sym)
- (or (null include-regexp)
- (string-match include-regexp (symbol-name sym)))
- (not (string-match
- (or exclude-regexp "-syntax-table\\'")
- (symbol-name sym))))
- (let ((value (symbol-value sym)))
- (when (or (null predicate)
- (funcall predicate sym))
- (setq bindings (cons `(quote ,value) bindings)
- bindings (cons sym bindings)))))))
- bindings)))
-
-(defalias 'async-inject-environment 'async-inject-variables)
-
-(defun async-handle-result (func result buf)
- (if (null func)
- (progn
- (set (make-local-variable 'async-callback-value) result)
- (set (make-local-variable 'async-callback-value-set) t))
- (unwind-protect
- (if (and (listp result)
- (eq 'async-signal (nth 0 result)))
- (signal (car (nth 1 result))
- (cdr (nth 1 result)))
- (funcall func result))
- (unless async-debug
- (kill-buffer buf)))))
-
-(defun async-when-done (proc &optional change)
- "Process sentinal used to retrieve the value from the child process."
- (when (eq 'exit (process-status proc))
- (with-current-buffer (process-buffer proc)
- (let ((async-current-process proc))
- (if (= 0 (process-exit-status proc))
- (if async-callback-for-process
- (if async-callback
- (prog1
- (funcall async-callback proc)
- (unless async-debug
- (kill-buffer (current-buffer))))
- (set (make-local-variable 'async-callback-value) proc)
- (set (make-local-variable 'async-callback-value-set) t))
- (goto-char (point-max))
- (backward-sexp)
- (async-handle-result async-callback (read (current-buffer))
- (current-buffer)))
- (set (make-local-variable 'async-callback-value)
- (list 'error
- (format "Async process '%s' failed with exit code %d"
- (process-name proc) (process-exit-status proc))))
- (set (make-local-variable 'async-callback-value-set) t))))))
-
-(defun async--receive-sexp (&optional stream)
- (let ((sexp (decode-coding-string (base64-decode-string
- (read stream)) 'utf-8-unix))
- ;; Parent expects UTF-8 encoded text.
- (coding-system-for-write 'utf-8-unix))
- (if async-debug
- (message "Received sexp {{{%s}}}" (pp-to-string sexp)))
- (setq sexp (read sexp))
- (if async-debug
- (message "Read sexp {{{%s}}}" (pp-to-string sexp)))
- (eval sexp)))
-
-(defun async--insert-sexp (sexp)
- (let (print-level
- print-length
- (print-escape-nonascii t)
- (print-circle t))
- (prin1 sexp (current-buffer))
- ;; Just in case the string we're sending might contain EOF
- (encode-coding-region (point-min) (point-max) 'utf-8-unix)
- (base64-encode-region (point-min) (point-max) t)
- (goto-char (point-min)) (insert ?\")
- (goto-char (point-max)) (insert ?\" ?\n)))
-
-(defun async--transmit-sexp (process sexp)
- (with-temp-buffer
- (if async-debug
- (message "Transmitting sexp {{{%s}}}" (pp-to-string sexp)))
- (async--insert-sexp sexp)
- (process-send-region process (point-min) (point-max))))
-
-(defun async-batch-invoke ()
- "Called from the child Emacs process' command-line."
- ;; Make sure 'message' and 'prin1' encode stuff in UTF-8, as parent
- ;; process expects.
- (let ((coding-system-for-write 'utf-8-unix))
- (setq async-in-child-emacs t
- debug-on-error async-debug)
- (if debug-on-error
- (prin1 (funcall
- (async--receive-sexp (unless async-send-over-pipe
- command-line-args-left))))
- (condition-case err
- (prin1 (funcall
- (async--receive-sexp (unless async-send-over-pipe
- command-line-args-left))))
- (error
- (prin1 (list 'async-signal err)))))))
-
-(defun async-ready (future)
- "Query a FUTURE to see if the ready is ready -- i.e., if no blocking
-would result from a call to `async-get' on that FUTURE."
- (and (memq (process-status future) '(exit signal))
- (with-current-buffer (process-buffer future)
- async-callback-value-set)))
-
-(defun async-wait (future)
- "Wait for FUTURE to become ready."
- (while (not (async-ready future))
- (sit-for 0.05)))
-
-(defun async-get (future)
- "Get the value from an asynchronously function when it is ready.
-FUTURE is returned by `async-start' or `async-start-process' when
-its FINISH-FUNC is nil."
- (async-wait future)
- (with-current-buffer (process-buffer future)
- (async-handle-result #'identity async-callback-value (current-buffer))))
-
-(defun async-message-p (value)
- "Return true of VALUE is an async.el message packet."
- (and (listp value)
- (plist-get value :async-message)))
-
-(defun async-send (&rest args)
- "Send the given messages to the asychronous Emacs PROCESS."
- (let ((args (append args '(:async-message t))))
- (if async-in-child-emacs
- (if async-callback
- (funcall async-callback args))
- (async--transmit-sexp (car args) (list 'quote (cdr args))))))
-
-(defun async-receive (&rest args)
- "Send the given messages to the asychronous Emacs PROCESS."
- (async--receive-sexp))
-
-;;;###autoload
-(defun async-start-process (name program finish-func &rest program-args)
- "Start the executable PROGRAM asynchronously. See `async-start'.
-PROGRAM is passed PROGRAM-ARGS, calling FINISH-FUNC with the
-process object when done. If FINISH-FUNC is nil, the future
-object will return the process object when the program is
-finished. Set DEFAULT-DIRECTORY to change PROGRAM's current
-working directory."
- (let* ((buf (generate-new-buffer (concat "*" name "*")))
- (proc (let ((process-connection-type nil))
- (apply #'start-process name buf program program-args))))
- (with-current-buffer buf
- (set (make-local-variable 'async-callback) finish-func)
- (set-process-sentinel proc #'async-when-done)
- (unless (string= name "emacs")
- (set (make-local-variable 'async-callback-for-process) t))
- proc)))
-
-;;;###autoload
-(defun async-start (start-func &optional finish-func)
- "Execute START-FUNC (often a lambda) in a subordinate Emacs process.
-When done, the return value is passed to FINISH-FUNC. Example:
-
- (async-start
- ;; What to do in the child process
- (lambda ()
- (message \"This is a test\")
- (sleep-for 3)
- 222)
-
- ;; What to do when it finishes
- (lambda (result)
- (message \"Async process done, result should be 222: %s\"
- result)))
-
-If FINISH-FUNC is nil or missing, a future is returned that can
-be inspected using `async-get', blocking until the value is
-ready. Example:
-
- (let ((proc (async-start
- ;; What to do in the child process
- (lambda ()
- (message \"This is a test\")
- (sleep-for 3)
- 222))))
-
- (message \"I'm going to do some work here\") ;; ....
-
- (message \"Waiting on async process, result should be 222: %s\"
- (async-get proc)))
-
-If you don't want to use a callback, and you don't care about any
-return value form the child process, pass the `ignore' symbol as
-the second argument (if you don't, and never call `async-get', it
-will leave *emacs* process buffers hanging around):
-
- (async-start
- (lambda ()
- (delete-file \"a remote file on a slow link\" nil))
- 'ignore)
-
-Note: Even when FINISH-FUNC is present, a future is still
-returned except that it yields no value (since the value is
-passed to FINISH-FUNC). Call `async-get' on such a future always
-returns nil. It can still be useful, however, as an argument to
-`async-ready' or `async-wait'."
- (let ((sexp start-func)
- ;; Subordinate Emacs will send text encoded in UTF-8.
- (coding-system-for-read 'utf-8-unix))
- (setq async--procvar
- (async-start-process
- "emacs" (file-truename
- (expand-file-name invocation-name
- invocation-directory))
- finish-func
- "-Q" "-l"
- ;; Using `locate-library' ensure we use the right file
- ;; when the .elc have been deleted.
- (locate-library "async")
- "-batch" "-f" "async-batch-invoke"
- (if async-send-over-pipe
- "<none>"
- (with-temp-buffer
- (async--insert-sexp (list 'quote sexp))
- (buffer-string)))))
- (if async-send-over-pipe
- (async--transmit-sexp async--procvar (list 'quote sexp)))
- async--procvar))
-
-(defmacro async-sandbox(func)
- "Evaluate FUNC in a separate Emacs process, synchronously."
- `(async-get (async-start ,func)))
-
-(provide 'async)
-
-;;; async.el ends here
+++ /dev/null
-;;; dired-async.el --- Copy/move/delete asynchronously in dired.
-
-;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
-
-;; Authors: John Wiegley <jwiegleyNOSPAMgmail.com>
-;; Thierry Volpiatto <thierry.volpiattoNOSPAMgmail.com>
-
-;; Keywords: dired async network
-;; X-URL: https://github.com/jwiegley/dired-async
-
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2, or (at
-;; your option) any later version.
-
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-\f
-;;; Commentary:
-
-;; This file provide a redefinition of `dired-create-file' function,
-;; performs copies, moves and all what is handled by `dired-create-file'
-;; in the background using a slave Emacs process,
-;; by means of the async.el module.
-;; To use it, put this in your .emacs:
-
-;; (dired-async-mode 1)
-
-;; This will enable async copy/rename etc...
-;; in dired and helm.
-
-;;; Code:
-\f
-(require 'cl-lib)
-(require 'dired-aux)
-(require 'async)
-
-(eval-when-compile
- (defvar async-callback))
-(defvar dired-async-operation nil)
-
-(defgroup dired-async nil
- "Copy rename files asynchronously from dired."
- :group 'dired)
-
-(defcustom dired-async-env-variables-regexp
- "\\`\\(tramp-\\(default\\|connection\\|remote\\)\\|ange-ftp\\)-.*"
- "Variables matching this regexp will be loaded on Child Emacs."
- :type 'regexp
- :group 'dired-async)
-
-(defcustom dired-async-message-function 'dired-async-mode-line-message
- "Function to use to notify result when operation finish.
-Should take same args as `message'."
- :group 'dired-async
- :type 'function)
-
-(defcustom dired-async-log-file "/tmp/dired-async.log"
- "File use to communicate errors from Child Emacs to host Emacs."
- :group 'dired-async
- :type 'string)
-
-(defface dired-async-message
- '((t (:foreground "yellow")))
- "Face used for mode-line message."
- :group 'dired-async)
-
-(defface dired-async-mode-message
- '((t (:foreground "Gold")))
- "Face used for `dired-async--modeline-mode' lighter."
- :group 'dired-async)
-
-(define-minor-mode dired-async--modeline-mode
- "Notify mode-line that an async process run."
- :group 'dired-async
- :global t
- :lighter (:eval (propertize (format " [%s Async job(s) running]"
- (length (dired-async-processes)))
- 'face 'dired-async-mode-message))
- (unless dired-async--modeline-mode
- (let ((visible-bell t)) (ding))))
-
-(defun dired-async-mode-line-message (text &rest args)
- "Notify end of operation in `mode-line'."
- (message nil)
- (let ((mode-line-format (concat
- " " (propertize
- (if args
- (apply #'format text args)
- text)
- 'face 'dired-async-message))))
- (force-mode-line-update)
- (sit-for 3)
- (force-mode-line-update)))
-
-(defun dired-async-processes ()
- (cl-loop for p in (process-list)
- when (cl-loop for c in (process-command p) thereis
- (string= "async-batch-invoke" c))
- collect p))
-
-(defun dired-async-kill-process ()
- (interactive)
- (let* ((processes (dired-async-processes))
- (proc (car (last processes))))
- (delete-process proc)
- (unless (> (length processes) 1)
- (dired-async--modeline-mode -1))))
-
-(defun dired-async-after-file-create (len-flist)
- "Callback function used for operation handled by `dired-create-file'."
- (unless (dired-async-processes)
- ;; Turn off mode-line notification
- ;; only when last process end.
- (dired-async--modeline-mode -1))
- (when dired-async-operation
- (if (file-exists-p dired-async-log-file)
- (progn
- (pop-to-buffer (get-buffer-create "*dired async*"))
- (erase-buffer)
- (insert "Error: ")
- (insert-file-contents dired-async-log-file)
- (delete-file dired-async-log-file))
- (run-with-timer
- 0.1 nil
- dired-async-message-function "Asynchronous %s of %s file(s) on %s file(s) done"
- (car dired-async-operation) (cadr dired-async-operation) len-flist))))
-
-(defun dired-async-maybe-kill-ftp ()
- "Return a form to kill ftp process in child emacs."
- (quote
- (progn
- (require 'cl-lib)
- (let ((buf (cl-loop for b in (buffer-list)
- thereis (and (string-match
- "\\`\\*ftp.*"
- (buffer-name b)) b))))
- (when buf (kill-buffer buf))))))
-
-(defun dired-async-create-files (file-creator operation fn-list name-constructor
- &optional marker-char)
- "Same as `dired-create-files' but asynchronous.
-
-See `dired-create-files' for the behavior of arguments."
- (setq dired-async-operation nil)
- (let (dired-create-files-failures
- failures async-fn-list
- skipped (success-count 0)
- (total (length fn-list))
- callback)
- (let (to overwrite-query
- overwrite-backup-query) ; for dired-handle-overwrite
- (dolist (from fn-list)
- (setq to (funcall name-constructor from))
- (if (equal to from)
- (progn
- (setq to nil)
- (dired-log "Cannot %s to same file: %s\n"
- (downcase operation) from)))
- (if (not to)
- (setq skipped (cons (dired-make-relative from) skipped))
- (let* ((overwrite (file-exists-p to))
- (dired-overwrite-confirmed ; for dired-handle-overwrite
- (and overwrite
- (let ((help-form '(format "\
-Type SPC or `y' to overwrite file `%s',
-DEL or `n' to skip to next,
-ESC or `q' to not overwrite any of the remaining files,
-`!' to overwrite all remaining files with no more questions." to)))
- (dired-query 'overwrite-query
- "Overwrite `%s'?" to))))
- ;; must determine if FROM is marked before file-creator
- ;; gets a chance to delete it (in case of a move).
- (actual-marker-char
- (cond ((integerp marker-char) marker-char)
- (marker-char (dired-file-marker from)) ; slow
- (t nil))))
- ;; Handle the `dired-copy-file' file-creator specially
- ;; When copying a directory to another directory or
- ;; possibly to itself or one of its subdirectories.
- ;; e.g "~/foo/" => "~/test/"
- ;; or "~/foo/" =>"~/foo/"
- ;; or "~/foo/ => ~/foo/bar/")
- ;; In this case the 'name-constructor' have set the destination
- ;; TO to "~/test/foo" because the old emacs23 behavior
- ;; of `copy-directory' was to not create the subdirectory
- ;; and instead copy the contents.
- ;; With the new behavior of `copy-directory'
- ;; (similar to the `cp' shell command) we don't
- ;; need such a construction of the target directory,
- ;; so modify the destination TO to "~/test/" instead of "~/test/foo/".
- (let ((destname (file-name-directory to)))
- (when (and (file-directory-p from)
- (file-directory-p to)
- (eq file-creator 'dired-copy-file))
- (setq to destname))
- ;; If DESTNAME is a subdirectory of FROM, not a symlink,
- ;; and the method in use is copying, signal an error.
- (and (eq t (car (file-attributes destname)))
- (eq file-creator 'dired-copy-file)
- (file-in-directory-p destname from)
- (error "Cannot copy `%s' into its subdirectory `%s'"
- from to)))
- (if overwrite
- (or (and dired-overwrite-confirmed
- (push (cons from to) async-fn-list))
- (progn
- (push (dired-make-relative from) failures)
- (dired-log "%s `%s' to `%s' failed"
- operation from to)))
- (push (cons from to) async-fn-list)))))
- (setq callback
- `(lambda (&optional ignore)
- (dired-async-after-file-create ,total)
- (when (string= ,(downcase operation) "rename")
- (cl-loop for (file . to) in ',async-fn-list
- do (and (get-file-buffer file)
- (with-current-buffer (get-file-buffer file)
- (set-visited-file-name to nil t))))))))
- ;; Handle error happening in host emacs.
- (cond
- (dired-create-files-failures
- (setq failures (nconc failures dired-create-files-failures))
- (dired-log-summary
- (format "%s failed for %d file%s in %d requests"
- operation (length failures)
- (dired-plural-s (length failures))
- total)
- failures))
- (failures
- (dired-log-summary
- (format "%s failed for %d of %d file%s"
- operation (length failures)
- total (dired-plural-s total))
- failures))
- (skipped
- (dired-log-summary
- (format "%s: %d of %d file%s skipped"
- operation (length skipped) total
- (dired-plural-s total))
- skipped))
- (t (message "%s: %s file%s"
- operation success-count (dired-plural-s success-count))))
- ;; Start async process.
- (when async-fn-list
- (async-start `(lambda ()
- (require 'cl-lib) (require 'dired-aux) (require 'dired-x)
- ,(async-inject-variables dired-async-env-variables-regexp)
- (condition-case err
- (let ((dired-recursive-copies (quote always)))
- (cl-loop for (f . d) in (quote ,async-fn-list)
- do (funcall (quote ,file-creator) f d t)))
- (file-error
- (with-temp-file ,dired-async-log-file
- (insert (format "%S" err)))))
- ,(dired-async-maybe-kill-ftp))
- callback)
- ;; Run mode-line notifications while process running.
- (dired-async--modeline-mode 1)
- (setq dired-async-operation (list operation (length async-fn-list)))
- (message "%s proceeding asynchronously..." operation))))
-
-(defadvice dired-create-files (around dired-async)
- (dired-async-create-files file-creator operation fn-list
- name-constructor marker-char))
-
-;;;###autoload
-(define-minor-mode dired-async-mode
- "Do dired actions asynchronously."
- :group 'dired-async
- :global t
- (if dired-async-mode
- (if (fboundp 'advice-add)
- (advice-add 'dired-create-files :override #'dired-async-create-files)
- (ad-activate 'dired-create-files))
- (if (fboundp 'advice-remove)
- (advice-remove 'dired-create-files #'dired-async-create-files)
- (ad-deactivate 'dired-create-files))))
-
-
-(provide 'dired-async)
-
-;;; dired-async.el ends here
+++ /dev/null
-;;; smtpmail-async.el --- Send e-mail with smtpmail.el asynchronously
-
-;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
-
-;; Author: John Wiegley <jwiegleyNOSPAMgmail.com>
-;; Created: 18 Jun 2012
-
-;; Keywords: email async
-;; X-URL: https://github.com/jwiegley/emacs-async
-
-;; This program is free software; you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation; either version 2, or (at
-;; your option) any later version.
-
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-\f
-;;; Commentary:
-
-;; Send e-mail with smtpmail.el asynchronously. To use:
-;;
-;; (require 'smtpmail-async)
-;;
-;; (setq send-mail-function 'async-smtpmail-send-it
-;; message-send-mail-function 'async-smtpmail-send-it)
-;;
-;; This assumes you already have smtpmail.el working.
-
-;;; Code:
-
-(defgroup smtpmail-async nil
- "Send e-mail with smtpmail.el asynchronously"
- :group 'smptmail)
-
-(require 'async)
-(require 'smtpmail)
-(require 'message)
-
-(defvar async-smtpmail-before-send-hook nil
- "Hook running in the child emacs in `async-smtpmail-send-it'.
-It is called just before calling `smtpmail-send-it'.")
-
-(defun async-smtpmail-send-it ()
- (let ((to (message-field-value "To"))
- (buf-content (buffer-substring-no-properties
- (point-min) (point-max))))
- (message "Delivering message to %s..." to)
- (async-start
- `(lambda ()
- (require 'smtpmail)
- (with-temp-buffer
- (insert ,buf-content)
- (set-buffer-multibyte nil)
- ;; Pass in the variable environment for smtpmail
- ,(async-inject-variables
- "\\`\\(smtpmail\\|async-smtpmail\\|\\(user-\\)?mail\\)-\\|auth-sources\\|epg"
- nil "\\`\\(mail-header-format-function\\|smtpmail-address-buffer\\|mail-mode-abbrev-table\\)")
- (run-hooks 'async-smtpmail-before-send-hook)
- (smtpmail-send-it)))
- `(lambda (&optional ignore)
- (message "Delivering message to %s...done" ,to)))))
-
-(provide 'smtpmail-async)
-
-;;; smtpmail-async.el ends here
--- /dev/null
+;;; async-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+\f
+;;;### (autoloads nil "async" "async.el" (22576 8239 0 0))
+;;; Generated autoloads from async.el
+
+(autoload 'async-start-process "async" "\
+Start the executable PROGRAM asynchronously. See `async-start'.
+PROGRAM is passed PROGRAM-ARGS, calling FINISH-FUNC with the
+process object when done. If FINISH-FUNC is nil, the future
+object will return the process object when the program is
+finished. Set DEFAULT-DIRECTORY to change PROGRAM's current
+working directory.
+
+\(fn NAME PROGRAM FINISH-FUNC &rest PROGRAM-ARGS)" nil nil)
+
+(autoload 'async-start "async" "\
+Execute START-FUNC (often a lambda) in a subordinate Emacs process.
+When done, the return value is passed to FINISH-FUNC. Example:
+
+ (async-start
+ ;; What to do in the child process
+ (lambda ()
+ (message \"This is a test\")
+ (sleep-for 3)
+ 222)
+
+ ;; What to do when it finishes
+ (lambda (result)
+ (message \"Async process done, result should be 222: %s\"
+ result)))
+
+If FINISH-FUNC is nil or missing, a future is returned that can
+be inspected using `async-get', blocking until the value is
+ready. Example:
+
+ (let ((proc (async-start
+ ;; What to do in the child process
+ (lambda ()
+ (message \"This is a test\")
+ (sleep-for 3)
+ 222))))
+
+ (message \"I'm going to do some work here\") ;; ....
+
+ (message \"Waiting on async process, result should be 222: %s\"
+ (async-get proc)))
+
+If you don't want to use a callback, and you don't care about any
+return value from the child process, pass the `ignore' symbol as
+the second argument (if you don't, and never call `async-get', it
+will leave *emacs* process buffers hanging around):
+
+ (async-start
+ (lambda ()
+ (delete-file \"a remote file on a slow link\" nil))
+ 'ignore)
+
+Note: Even when FINISH-FUNC is present, a future is still
+returned except that it yields no value (since the value is
+passed to FINISH-FUNC). Call `async-get' on such a future always
+returns nil. It can still be useful, however, as an argument to
+`async-ready' or `async-wait'.
+
+\(fn START-FUNC &optional FINISH-FUNC)" nil nil)
+
+;;;***
+\f
+;;;### (autoloads nil "async-bytecomp" "async-bytecomp.el" (22576
+;;;;;; 8239 0 0))
+;;; Generated autoloads from async-bytecomp.el
+
+(autoload 'async-byte-recompile-directory "async-bytecomp" "\
+Compile all *.el files in DIRECTORY asynchronously.
+All *.elc files are systematically deleted before proceeding.
+
+\(fn DIRECTORY &optional QUIET)" nil nil)
+
+(defvar async-bytecomp-package-mode nil "\
+Non-nil if Async-Bytecomp-Package mode is enabled.
+See the `async-bytecomp-package-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `async-bytecomp-package-mode'.")
+
+(custom-autoload 'async-bytecomp-package-mode "async-bytecomp" nil)
+
+(autoload 'async-bytecomp-package-mode "async-bytecomp" "\
+Byte compile asynchronously packages installed with package.el.
+Async compilation of packages can be controlled by
+`async-bytecomp-allowed-packages'.
+
+\(fn &optional ARG)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "dired-async" "dired-async.el" (22576 8239
+;;;;;; 0 0))
+;;; Generated autoloads from dired-async.el
+
+(defvar dired-async-mode nil "\
+Non-nil if Dired-Async mode is enabled.
+See the `dired-async-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `dired-async-mode'.")
+
+(custom-autoload 'dired-async-mode "dired-async" nil)
+
+(autoload 'dired-async-mode "dired-async" "\
+Do dired actions asynchronously.
+
+\(fn &optional ARG)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil nil ("async-pkg.el" "smtpmail-async.el") (22576
+;;;;;; 8239 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; async-autoloads.el ends here
--- /dev/null
+;;; async-bytecomp.el --- Compile elisp files asynchronously -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
+
+;; Authors: John Wiegley <jwiegleyNOSPAMgmail.com>
+;; Thierry Volpiatto <thierry.volpiattoNOSPAMgmail.com>
+
+;; Keywords: dired async byte-compile
+;; X-URL: https://github.com/jwiegley/dired-async
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+;;
+;; This package provide the `async-byte-recompile-directory' function
+;; which allows, as the name says to recompile a directory outside of
+;; your running emacs.
+;; The benefit is your files will be compiled in a clean environment without
+;; the old *.el files loaded.
+;; Among other things, this fix a bug in package.el which recompile
+;; the new files in the current environment with the old files loaded, creating
+;; errors in most packages after upgrades.
+;;
+;; NB: This package is advicing the function `package--compile'.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'async)
+
+(defcustom async-bytecomp-allowed-packages
+ '(async helm helm-core helm-ls-git helm-ls-hg magit)
+ "Packages in this list will be compiled asynchronously by `package--compile'.
+All the dependencies of these packages will be compiled async too,
+so no need to add dependencies to this list.
+The value of this variable can also be a list with a single element,
+the symbol `all', in this case packages are always compiled asynchronously."
+ :group 'async
+ :type '(repeat (choice symbol)))
+
+(defvar async-byte-compile-log-file "~/.emacs.d/async-bytecomp.log")
+
+;;;###autoload
+(defun async-byte-recompile-directory (directory &optional quiet)
+ "Compile all *.el files in DIRECTORY asynchronously.
+All *.elc files are systematically deleted before proceeding."
+ (cl-loop with dir = (directory-files directory t "\\.elc\\'")
+ unless dir return nil
+ for f in dir
+ when (file-exists-p f) do (delete-file f))
+ ;; Ensure async is reloaded when async.elc is deleted.
+ ;; This happen when recompiling its own directory.
+ (load "async")
+ (let ((call-back
+ (lambda (&optional _ignore)
+ (if (file-exists-p async-byte-compile-log-file)
+ (let ((buf (get-buffer-create byte-compile-log-buffer))
+ (n 0))
+ (with-current-buffer buf
+ (goto-char (point-max))
+ (let ((inhibit-read-only t))
+ (insert-file-contents async-byte-compile-log-file)
+ (compilation-mode))
+ (display-buffer buf)
+ (delete-file async-byte-compile-log-file)
+ (unless quiet
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^.*:Error:" nil t)
+ (cl-incf n)))
+ (if (> n 0)
+ (message "Failed to compile %d files in directory `%s'" n directory)
+ (message "Directory `%s' compiled asynchronously with warnings" directory)))))
+ (unless quiet
+ (message "Directory `%s' compiled asynchronously with success" directory))))))
+ (async-start
+ `(lambda ()
+ (require 'bytecomp)
+ ,(async-inject-variables "\\`\\(load-path\\)\\|byte\\'")
+ (let ((default-directory (file-name-as-directory ,directory))
+ error-data)
+ (add-to-list 'load-path default-directory)
+ (byte-recompile-directory ,directory 0 t)
+ (when (get-buffer byte-compile-log-buffer)
+ (setq error-data (with-current-buffer byte-compile-log-buffer
+ (buffer-substring-no-properties (point-min) (point-max))))
+ (unless (string= error-data "")
+ (with-temp-file ,async-byte-compile-log-file
+ (erase-buffer)
+ (insert error-data))))))
+ call-back)
+ (unless quiet (message "Started compiling asynchronously directory %s" directory))))
+
+(defvar package-archive-contents)
+(defvar package-alist)
+(declare-function package-desc-reqs "package.el" (cl-x))
+
+(defun async-bytecomp--get-package-deps (pkg &optional only)
+ ;; Same as `package--get-deps' but parse instead `package-archive-contents'
+ ;; because PKG is not already installed and not present in `package-alist'.
+ ;; However fallback to `package-alist' in case PKG no more present
+ ;; in `package-archive-contents' due to modification to `package-archives'.
+ ;; See issue #58.
+ (let* ((pkg-desc (cadr (or (assq pkg package-archive-contents)
+ (assq pkg package-alist))))
+ (direct-deps (cl-loop for p in (package-desc-reqs pkg-desc)
+ for name = (car p)
+ when (or (assq name package-archive-contents)
+ (assq name package-alist))
+ collect name))
+ (indirect-deps (unless (eq only 'direct)
+ (delete-dups
+ (cl-loop for p in direct-deps append
+ (async-bytecomp--get-package-deps p))))))
+ (cl-case only
+ (direct direct-deps)
+ (separate (list direct-deps indirect-deps))
+ (indirect indirect-deps)
+ (t (delete-dups (append direct-deps indirect-deps))))))
+
+(defun async-bytecomp-get-allowed-pkgs ()
+ (when (and async-bytecomp-allowed-packages
+ (listp async-bytecomp-allowed-packages))
+ (if package-archive-contents
+ (cl-loop for p in async-bytecomp-allowed-packages
+ when (assq p package-archive-contents)
+ append (async-bytecomp--get-package-deps p) into reqs
+ finally return
+ (delete-dups
+ (append async-bytecomp-allowed-packages reqs)))
+ async-bytecomp-allowed-packages)))
+
+(defadvice package--compile (around byte-compile-async)
+ (let ((cur-package (package-desc-name pkg-desc))
+ (pkg-dir (package-desc-dir pkg-desc)))
+ (if (or (equal async-bytecomp-allowed-packages '(all))
+ (memq cur-package (async-bytecomp-get-allowed-pkgs)))
+ (progn
+ (when (eq cur-package 'async)
+ (fmakunbound 'async-byte-recompile-directory))
+ ;; Add to `load-path' the latest version of async and
+ ;; reload it when reinstalling async.
+ (when (string= cur-package "async")
+ (cl-pushnew pkg-dir load-path)
+ (load "async-bytecomp"))
+ ;; `async-byte-recompile-directory' will add directory
+ ;; as needed to `load-path'.
+ (async-byte-recompile-directory (package-desc-dir pkg-desc) t))
+ ad-do-it)))
+
+;;;###autoload
+(define-minor-mode async-bytecomp-package-mode
+ "Byte compile asynchronously packages installed with package.el.
+Async compilation of packages can be controlled by
+`async-bytecomp-allowed-packages'."
+ :group 'async
+ :global t
+ (if async-bytecomp-package-mode
+ (ad-activate 'package--compile)
+ (ad-deactivate 'package--compile)))
+
+(provide 'async-bytecomp)
+
+;;; async-bytecomp.el ends here
--- /dev/null
+(define-package "async" "20161103.1036" "Asynchronous processing in Emacs" 'nil :keywords
+ '("async")
+ :url "https://github.com/jwiegley/emacs-async")
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; async.el --- Asynchronous processing in Emacs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <jwiegleyNOSPAMgmail.com>
+;; Created: 18 Jun 2012
+;; Version: 1.9
+
+;; Keywords: async
+;; X-URL: https://github.com/jwiegley/emacs-async
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+\f
+;;; Commentary:
+
+;; Adds the ability to call asynchronous functions and process with ease. See
+;; the documentation for `async-start' and `async-start-process'.
+\f
+;;; Code:
+
+(defgroup async nil
+ "Simple asynchronous processing in Emacs"
+ :group 'emacs)
+
+(defvar async-debug nil)
+(defvar async-send-over-pipe t)
+(defvar async-in-child-emacs nil)
+(defvar async-callback nil)
+(defvar async-callback-for-process nil)
+(defvar async-callback-value nil)
+(defvar async-callback-value-set nil)
+(defvar async-current-process nil)
+(defvar async--procvar nil)
+
+(defun async-inject-variables
+ (include-regexp &optional predicate exclude-regexp)
+ "Return a `setq' form that replicates part of the calling environment.
+It sets the value for every variable matching INCLUDE-REGEXP and
+also PREDICATE. It will not perform injection for any variable
+matching EXCLUDE-REGEXP (if present). It is intended to be used
+as follows:
+
+ (async-start
+ `(lambda ()
+ (require 'smtpmail)
+ (with-temp-buffer
+ (insert ,(buffer-substring-no-properties (point-min) (point-max)))
+ ;; Pass in the variable environment for smtpmail
+ ,(async-inject-variables \"\\`\\(smtpmail\\|\\(user-\\)?mail\\)-\")
+ (smtpmail-send-it)))
+ 'ignore)"
+ `(setq
+ ,@(let (bindings)
+ (mapatoms
+ (lambda (sym)
+ (if (and (boundp sym)
+ (or (null include-regexp)
+ (string-match include-regexp (symbol-name sym)))
+ (not (string-match
+ (or exclude-regexp "-syntax-table\\'")
+ (symbol-name sym))))
+ (let ((value (symbol-value sym)))
+ (when (or (null predicate)
+ (funcall predicate sym))
+ (setq bindings (cons `(quote ,value) bindings)
+ bindings (cons sym bindings)))))))
+ bindings)))
+
+(defalias 'async-inject-environment 'async-inject-variables)
+
+(defun async-handle-result (func result buf)
+ (if (null func)
+ (progn
+ (set (make-local-variable 'async-callback-value) result)
+ (set (make-local-variable 'async-callback-value-set) t))
+ (unwind-protect
+ (if (and (listp result)
+ (eq 'async-signal (nth 0 result)))
+ (signal (car (nth 1 result))
+ (cdr (nth 1 result)))
+ (funcall func result))
+ (unless async-debug
+ (kill-buffer buf)))))
+
+(defun async-when-done (proc &optional _change)
+ "Process sentinel used to retrieve the value from the child process."
+ (when (eq 'exit (process-status proc))
+ (with-current-buffer (process-buffer proc)
+ (let ((async-current-process proc))
+ (if (= 0 (process-exit-status proc))
+ (if async-callback-for-process
+ (if async-callback
+ (prog1
+ (funcall async-callback proc)
+ (unless async-debug
+ (kill-buffer (current-buffer))))
+ (set (make-local-variable 'async-callback-value) proc)
+ (set (make-local-variable 'async-callback-value-set) t))
+ (goto-char (point-max))
+ (backward-sexp)
+ (async-handle-result async-callback (read (current-buffer))
+ (current-buffer)))
+ (set (make-local-variable 'async-callback-value)
+ (list 'error
+ (format "Async process '%s' failed with exit code %d"
+ (process-name proc) (process-exit-status proc))))
+ (set (make-local-variable 'async-callback-value-set) t))))))
+
+(defun async--receive-sexp (&optional stream)
+ (let ((sexp (decode-coding-string (base64-decode-string
+ (read stream)) 'utf-8-unix))
+ ;; Parent expects UTF-8 encoded text.
+ (coding-system-for-write 'utf-8-unix))
+ (if async-debug
+ (message "Received sexp {{{%s}}}" (pp-to-string sexp)))
+ (setq sexp (read sexp))
+ (if async-debug
+ (message "Read sexp {{{%s}}}" (pp-to-string sexp)))
+ (eval sexp)))
+
+(defun async--insert-sexp (sexp)
+ (let (print-level
+ print-length
+ (print-escape-nonascii t)
+ (print-circle t))
+ (prin1 sexp (current-buffer))
+ ;; Just in case the string we're sending might contain EOF
+ (encode-coding-region (point-min) (point-max) 'utf-8-unix)
+ (base64-encode-region (point-min) (point-max) t)
+ (goto-char (point-min)) (insert ?\")
+ (goto-char (point-max)) (insert ?\" ?\n)))
+
+(defun async--transmit-sexp (process sexp)
+ (with-temp-buffer
+ (if async-debug
+ (message "Transmitting sexp {{{%s}}}" (pp-to-string sexp)))
+ (async--insert-sexp sexp)
+ (process-send-region process (point-min) (point-max))))
+
+(defun async-batch-invoke ()
+ "Called from the child Emacs process' command-line."
+ ;; Make sure 'message' and 'prin1' encode stuff in UTF-8, as parent
+ ;; process expects.
+ (let ((coding-system-for-write 'utf-8-unix))
+ (setq async-in-child-emacs t
+ debug-on-error async-debug)
+ (if debug-on-error
+ (prin1 (funcall
+ (async--receive-sexp (unless async-send-over-pipe
+ command-line-args-left))))
+ (condition-case err
+ (prin1 (funcall
+ (async--receive-sexp (unless async-send-over-pipe
+ command-line-args-left))))
+ (error
+ (prin1 (list 'async-signal err)))))))
+
+(defun async-ready (future)
+ "Query a FUTURE to see if the ready is ready -- i.e., if no blocking
+would result from a call to `async-get' on that FUTURE."
+ (and (memq (process-status future) '(exit signal))
+ (with-current-buffer (process-buffer future)
+ async-callback-value-set)))
+
+(defun async-wait (future)
+ "Wait for FUTURE to become ready."
+ (while (not (async-ready future))
+ (sit-for 0.05)))
+
+(defun async-get (future)
+ "Get the value from an asynchronously function when it is ready.
+FUTURE is returned by `async-start' or `async-start-process' when
+its FINISH-FUNC is nil."
+ (async-wait future)
+ (with-current-buffer (process-buffer future)
+ (async-handle-result #'identity async-callback-value (current-buffer))))
+
+(defun async-message-p (value)
+ "Return true of VALUE is an async.el message packet."
+ (and (listp value)
+ (plist-get value :async-message)))
+
+(defun async-send (&rest args)
+ "Send the given messages to the asychronous Emacs PROCESS."
+ (let ((args (append args '(:async-message t))))
+ (if async-in-child-emacs
+ (if async-callback
+ (funcall async-callback args))
+ (async--transmit-sexp (car args) (list 'quote (cdr args))))))
+
+(defun async-receive ()
+ "Send the given messages to the asychronous Emacs PROCESS."
+ (async--receive-sexp))
+
+;;;###autoload
+(defun async-start-process (name program finish-func &rest program-args)
+ "Start the executable PROGRAM asynchronously. See `async-start'.
+PROGRAM is passed PROGRAM-ARGS, calling FINISH-FUNC with the
+process object when done. If FINISH-FUNC is nil, the future
+object will return the process object when the program is
+finished. Set DEFAULT-DIRECTORY to change PROGRAM's current
+working directory."
+ (let* ((buf (generate-new-buffer (concat "*" name "*")))
+ (proc (let ((process-connection-type nil))
+ (apply #'start-process name buf program program-args))))
+ (with-current-buffer buf
+ (set (make-local-variable 'async-callback) finish-func)
+ (set-process-sentinel proc #'async-when-done)
+ (unless (string= name "emacs")
+ (set (make-local-variable 'async-callback-for-process) t))
+ proc)))
+
+;;;###autoload
+(defun async-start (start-func &optional finish-func)
+ "Execute START-FUNC (often a lambda) in a subordinate Emacs process.
+When done, the return value is passed to FINISH-FUNC. Example:
+
+ (async-start
+ ;; What to do in the child process
+ (lambda ()
+ (message \"This is a test\")
+ (sleep-for 3)
+ 222)
+
+ ;; What to do when it finishes
+ (lambda (result)
+ (message \"Async process done, result should be 222: %s\"
+ result)))
+
+If FINISH-FUNC is nil or missing, a future is returned that can
+be inspected using `async-get', blocking until the value is
+ready. Example:
+
+ (let ((proc (async-start
+ ;; What to do in the child process
+ (lambda ()
+ (message \"This is a test\")
+ (sleep-for 3)
+ 222))))
+
+ (message \"I'm going to do some work here\") ;; ....
+
+ (message \"Waiting on async process, result should be 222: %s\"
+ (async-get proc)))
+
+If you don't want to use a callback, and you don't care about any
+return value from the child process, pass the `ignore' symbol as
+the second argument (if you don't, and never call `async-get', it
+will leave *emacs* process buffers hanging around):
+
+ (async-start
+ (lambda ()
+ (delete-file \"a remote file on a slow link\" nil))
+ 'ignore)
+
+Note: Even when FINISH-FUNC is present, a future is still
+returned except that it yields no value (since the value is
+passed to FINISH-FUNC). Call `async-get' on such a future always
+returns nil. It can still be useful, however, as an argument to
+`async-ready' or `async-wait'."
+ (let ((sexp start-func)
+ ;; Subordinate Emacs will send text encoded in UTF-8.
+ (coding-system-for-read 'utf-8-unix))
+ (setq async--procvar
+ (async-start-process
+ "emacs" (file-truename
+ (expand-file-name invocation-name
+ invocation-directory))
+ finish-func
+ "-Q" "-l"
+ ;; Using `locate-library' ensure we use the right file
+ ;; when the .elc have been deleted.
+ (locate-library "async")
+ "-batch" "-f" "async-batch-invoke"
+ (if async-send-over-pipe
+ "<none>"
+ (with-temp-buffer
+ (async--insert-sexp (list 'quote sexp))
+ (buffer-string)))))
+ (if async-send-over-pipe
+ (async--transmit-sexp async--procvar (list 'quote sexp)))
+ async--procvar))
+
+(defmacro async-sandbox(func)
+ "Evaluate FUNC in a separate Emacs process, synchronously."
+ `(async-get (async-start ,func)))
+
+(defun async--fold-left (fn forms bindings)
+ (let ((res forms))
+ (dolist (binding bindings)
+ (setq res (funcall fn res
+ (if (listp binding)
+ binding
+ (list binding)))))
+ res))
+
+(defmacro async-let (bindings &rest forms)
+ "Implements `let', but each binding is established asynchronously.
+For example:
+
+ (async-let ((x (foo))
+ (y (bar)))
+ (message \"%s %s\" x y))
+
+ expands to ==>
+
+ (async-start (foo)
+ (lambda (x)
+ (async-start (bar)
+ (lambda (y)
+ (message \"%s %s\" x y)))))"
+ (declare (indent 1))
+ (async--fold-left
+ (lambda (acc binding)
+ (let ((fun (pcase (cadr binding)
+ ((and (pred functionp) f) f)
+ (f `(lambda () ,f)))))
+ `(async-start ,fun
+ (lambda (,(car binding))
+ ,acc))))
+ `(progn ,@forms)
+ (reverse bindings)))
+
+(provide 'async)
+
+;;; async.el ends here
--- /dev/null
+;;; dired-async.el --- Asynchronous dired actions -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Authors: John Wiegley <jwiegley@gmail.com>
+;; Thierry Volpiatto <thierry.volpiattoNOSPAMgmail.com>
+
+;; Keywords: dired async network
+;; X-URL: https://github.com/jwiegley/dired-async
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+\f
+;;; Commentary:
+
+;; This file provide a redefinition of `dired-create-file' function,
+;; performs copies, moves and all what is handled by `dired-create-file'
+;; in the background using a slave Emacs process,
+;; by means of the async.el module.
+;; To use it, put this in your .emacs:
+
+;; (dired-async-mode 1)
+
+;; This will enable async copy/rename etc...
+;; in dired and helm.
+
+;;; Code:
+\f
+(require 'cl-lib)
+(require 'dired-aux)
+(require 'async)
+
+(eval-when-compile
+ (defvar async-callback))
+
+(defgroup dired-async nil
+ "Copy rename files asynchronously from dired."
+ :group 'dired)
+
+(defcustom dired-async-env-variables-regexp
+ "\\`\\(tramp-\\(default\\|connection\\|remote\\)\\|ange-ftp\\)-.*"
+ "Variables matching this regexp will be loaded on Child Emacs."
+ :type 'regexp
+ :group 'dired-async)
+
+(defcustom dired-async-message-function 'dired-async-mode-line-message
+ "Function to use to notify result when operation finish.
+Should take same args as `message'."
+ :group 'dired-async
+ :type 'function)
+
+(defcustom dired-async-log-file "/tmp/dired-async.log"
+ "File use to communicate errors from Child Emacs to host Emacs."
+ :group 'dired-async
+ :type 'string)
+
+(defface dired-async-message
+ '((t (:foreground "yellow")))
+ "Face used for mode-line message."
+ :group 'dired-async)
+
+(defface dired-async-failures
+ '((t (:foreground "red")))
+ "Face used for mode-line message."
+ :group 'dired-async)
+
+(defface dired-async-mode-message
+ '((t (:foreground "Gold")))
+ "Face used for `dired-async--modeline-mode' lighter."
+ :group 'dired-async)
+
+(define-minor-mode dired-async--modeline-mode
+ "Notify mode-line that an async process run."
+ :group 'dired-async
+ :global t
+ :lighter (:eval (propertize (format " [%s Async job(s) running]"
+ (length (dired-async-processes)))
+ 'face 'dired-async-mode-message))
+ (unless dired-async--modeline-mode
+ (let ((visible-bell t)) (ding))))
+
+(defun dired-async-mode-line-message (text face &rest args)
+ "Notify end of operation in `mode-line'."
+ (message nil)
+ (let ((mode-line-format (concat
+ " " (propertize
+ (if args
+ (apply #'format text args)
+ text)
+ 'face face))))
+ (force-mode-line-update)
+ (sit-for 3)
+ (force-mode-line-update)))
+
+(defun dired-async-processes ()
+ (cl-loop for p in (process-list)
+ when (cl-loop for c in (process-command p) thereis
+ (string= "async-batch-invoke" c))
+ collect p))
+
+(defun dired-async-kill-process ()
+ (interactive)
+ (let* ((processes (dired-async-processes))
+ (proc (car (last processes))))
+ (and proc (delete-process proc))
+ (unless (> (length processes) 1)
+ (dired-async--modeline-mode -1))))
+
+(defun dired-async-after-file-create (total operation failures skipped)
+ "Callback function used for operation handled by `dired-create-file'."
+ (unless (dired-async-processes)
+ ;; Turn off mode-line notification
+ ;; only when last process end.
+ (dired-async--modeline-mode -1))
+ (when operation
+ (if (file-exists-p dired-async-log-file)
+ (progn
+ (pop-to-buffer (get-buffer-create dired-log-buffer))
+ (goto-char (point-max))
+ (setq inhibit-read-only t)
+ (insert "Error: ")
+ (insert-file-contents dired-async-log-file)
+ (special-mode)
+ (shrink-window-if-larger-than-buffer)
+ (delete-file dired-async-log-file))
+ (run-with-timer
+ 0.1 nil
+ (lambda ()
+ ;; First send error messages.
+ (cond (failures
+ (funcall dired-async-message-function
+ "%s failed for %d of %d file%s -- See *Dired log* buffer"
+ 'dired-async-failures
+ (car operation) (length failures)
+ total (dired-plural-s total)))
+ (skipped
+ (funcall dired-async-message-function
+ "%s: %d of %d file%s skipped -- See *Dired log* buffer"
+ 'dired-async-failures
+ (car operation) (length skipped) total
+ (dired-plural-s total))))
+ ;; Finally send the success message.
+ (funcall dired-async-message-function
+ "Asynchronous %s of %s on %s file%s done"
+ 'dired-async-message
+ (car operation) (cadr operation)
+ total (dired-plural-s total)))))))
+
+(defun dired-async-maybe-kill-ftp ()
+ "Return a form to kill ftp process in child emacs."
+ (quote
+ (progn
+ (require 'cl-lib)
+ (let ((buf (cl-loop for b in (buffer-list)
+ thereis (and (string-match
+ "\\`\\*ftp.*"
+ (buffer-name b)) b))))
+ (when buf (kill-buffer buf))))))
+
+(defvar overwrite-query)
+(defun dired-async-create-files (file-creator operation fn-list name-constructor
+ &optional _marker-char)
+ "Same as `dired-create-files' but asynchronous.
+
+See `dired-create-files' for the behavior of arguments."
+ (setq overwrite-query nil)
+ (let ((total (length fn-list))
+ failures async-fn-list skipped callback)
+ (let (to)
+ (dolist (from fn-list)
+ (setq to (funcall name-constructor from))
+ (if (equal to from)
+ (progn
+ (setq to nil)
+ (dired-log "Cannot %s to same file: %s\n"
+ (downcase operation) from)))
+ (if (not to)
+ (setq skipped (cons (dired-make-relative from) skipped))
+ (let* ((overwrite (and (null (eq file-creator 'backup-file))
+ (file-exists-p to)))
+ (dired-overwrite-confirmed ; for dired-handle-overwrite
+ (and overwrite
+ (let ((help-form `(format "\
+Type SPC or `y' to overwrite file `%s',
+DEL or `n' to skip to next,
+ESC or `q' to not overwrite any of the remaining files,
+`!' to overwrite all remaining files with no more questions." ,to)))
+ (dired-query 'overwrite-query "Overwrite `%s'?" to)))))
+ ;; Handle the `dired-copy-file' file-creator specially
+ ;; When copying a directory to another directory or
+ ;; possibly to itself or one of its subdirectories.
+ ;; e.g "~/foo/" => "~/test/"
+ ;; or "~/foo/" =>"~/foo/"
+ ;; or "~/foo/ => ~/foo/bar/")
+ ;; In this case the 'name-constructor' have set the destination
+ ;; TO to "~/test/foo" because the old emacs23 behavior
+ ;; of `copy-directory' was to not create the subdirectory
+ ;; and instead copy the contents.
+ ;; With the new behavior of `copy-directory'
+ ;; (similar to the `cp' shell command) we don't
+ ;; need such a construction of the target directory,
+ ;; so modify the destination TO to "~/test/" instead of "~/test/foo/".
+ (let ((destname (file-name-directory to)))
+ (when (and (file-directory-p from)
+ (file-directory-p to)
+ (eq file-creator 'dired-copy-file))
+ (setq to destname))
+ ;; If DESTNAME is a subdirectory of FROM, not a symlink,
+ ;; and the method in use is copying, signal an error.
+ (and (eq t (car (file-attributes destname)))
+ (eq file-creator 'dired-copy-file)
+ (file-in-directory-p destname from)
+ (error "Cannot copy `%s' into its subdirectory `%s'"
+ from to)))
+ (if overwrite
+ (or (and dired-overwrite-confirmed
+ (push (cons from to) async-fn-list))
+ (progn
+ (push (dired-make-relative from) failures)
+ (dired-log "%s `%s' to `%s' failed\n"
+ operation from to)))
+ (push (cons from to) async-fn-list)))))
+ ;; When failures have been printed to dired log add the date at bob.
+ (when (or failures skipped) (dired-log t))
+ ;; When async-fn-list is empty that's mean only one file
+ ;; had to be copied and user finally answer NO.
+ ;; In this case async process will never start and callback
+ ;; will have no chance to run, so notify failures here.
+ (unless async-fn-list
+ (cond (failures
+ (funcall dired-async-message-function
+ "%s failed for %d of %d file%s -- See *Dired log* buffer"
+ 'dired-async-failures
+ operation (length failures)
+ total (dired-plural-s total)))
+ (skipped
+ (funcall dired-async-message-function
+ "%s: %d of %d file%s skipped -- See *Dired log* buffer"
+ 'dired-async-failures
+ operation (length skipped) total
+ (dired-plural-s total)))))
+ ;; Setup callback.
+ (setq callback
+ (lambda (&optional _ignore)
+ (dired-async-after-file-create
+ total (list operation (length async-fn-list)) failures skipped)
+ (when (string= (downcase operation) "rename")
+ (cl-loop for (file . to) in async-fn-list
+ for bf = (get-file-buffer file)
+ for destp = (file-exists-p to)
+ do (and bf destp
+ (with-current-buffer bf
+ (set-visited-file-name to t t))))))))
+ ;; Start async process.
+ (when async-fn-list
+ (async-start `(lambda ()
+ (require 'cl-lib) (require 'dired-aux) (require 'dired-x)
+ ,(async-inject-variables dired-async-env-variables-regexp)
+ (let ((dired-recursive-copies (quote always))
+ (dired-copy-preserve-time
+ ,dired-copy-preserve-time))
+ (setq overwrite-backup-query nil)
+ ;; Inline `backup-file' as long as it is not
+ ;; available in emacs.
+ (defalias 'backup-file
+ ;; Same feature as "cp --backup=numbered from to"
+ ;; Symlinks are copied as file from source unlike
+ ;; `dired-copy-file' which is same as cp -d.
+ ;; Directories are omitted.
+ (lambda (from to ok)
+ (cond ((file-directory-p from) (ignore))
+ (t (let ((count 0))
+ (while (let ((attrs (file-attributes to)))
+ (and attrs (null (nth 0 attrs))))
+ (cl-incf count)
+ (setq to (concat (file-name-sans-versions to)
+ (format ".~%s~" count)))))
+ (condition-case err
+ (copy-file from to ok dired-copy-preserve-time)
+ (file-date-error
+ (dired-log "Can't set date on %s:\n%s\n" from err)))))))
+ ;; Now run the FILE-CREATOR function on files.
+ (cl-loop with fn = (quote ,file-creator)
+ for (from . dest) in (quote ,async-fn-list)
+ do (condition-case err
+ (funcall fn from dest t)
+ (file-error
+ (dired-log "%s: %s\n" (car err) (cdr err)))
+ nil))
+ (when (get-buffer dired-log-buffer)
+ (dired-log t)
+ (with-current-buffer dired-log-buffer
+ (write-region (point-min) (point-max)
+ ,dired-async-log-file))))
+ ,(dired-async-maybe-kill-ftp))
+ callback)
+ ;; Run mode-line notifications while process running.
+ (dired-async--modeline-mode 1)
+ (message "%s proceeding asynchronously..." operation))))
+
+(defadvice dired-create-files (around dired-async)
+ (dired-async-create-files file-creator operation fn-list
+ name-constructor marker-char))
+
+;;;###autoload
+(define-minor-mode dired-async-mode
+ "Do dired actions asynchronously."
+ :group 'dired-async
+ :global t
+ (if dired-async-mode
+ (if (fboundp 'advice-add)
+ (advice-add 'dired-create-files :override #'dired-async-create-files)
+ (ad-activate 'dired-create-files))
+ (if (fboundp 'advice-remove)
+ (advice-remove 'dired-create-files #'dired-async-create-files)
+ (ad-deactivate 'dired-create-files))))
+
+
+(provide 'dired-async)
+
+;;; dired-async.el ends here
--- /dev/null
+;;; smtpmail-async.el --- Send e-mail with smtpmail.el asynchronously -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <jwiegleyNOSPAMgmail.com>
+;; Created: 18 Jun 2012
+
+;; Keywords: email async
+;; X-URL: https://github.com/jwiegley/emacs-async
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2, or (at
+;; your option) any later version.
+
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to the
+;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+\f
+;;; Commentary:
+
+;; Send e-mail with smtpmail.el asynchronously. To use:
+;;
+;; (require 'smtpmail-async)
+;;
+;; (setq send-mail-function 'async-smtpmail-send-it
+;; message-send-mail-function 'async-smtpmail-send-it)
+;;
+;; This assumes you already have smtpmail.el working.
+
+;;; Code:
+
+(defgroup smtpmail-async nil
+ "Send e-mail with smtpmail.el asynchronously"
+ :group 'smptmail)
+
+(require 'async)
+(require 'smtpmail)
+(require 'message)
+
+(defvar async-smtpmail-before-send-hook nil
+ "Hook running in the child emacs in `async-smtpmail-send-it'.
+It is called just before calling `smtpmail-send-it'.")
+
+(defun async-smtpmail-send-it ()
+ (let ((to (message-field-value "To"))
+ (buf-content (buffer-substring-no-properties
+ (point-min) (point-max))))
+ (message "Delivering message to %s..." to)
+ (async-start
+ `(lambda ()
+ (require 'smtpmail)
+ (with-temp-buffer
+ (insert ,buf-content)
+ (set-buffer-multibyte nil)
+ ;; Pass in the variable environment for smtpmail
+ ,(async-inject-variables
+ "\\`\\(smtpmail\\|async-smtpmail\\|\\(user-\\)?mail\\)-\\|auth-sources\\|epg"
+ nil "\\`\\(mail-header-format-function\\|smtpmail-address-buffer\\|mail-mode-abbrev-table\\)")
+ (run-hooks 'async-smtpmail-before-send-hook)
+ (smtpmail-send-it)))
+ (lambda (&optional _ignore)
+ (message "Delivering message to %s...done" to)))))
+
+(provide 'smtpmail-async)
+
+;;; smtpmail-async.el ends here
+++ /dev/null
-;;; dash-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
-\f
-;;;### (autoloads nil nil ("dash.el") (22215 9211 926426 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; End:
-;;; dash-autoloads.el ends here
+++ /dev/null
-(define-package "dash" "20151216.1315" "A modern list library for Emacs" 'nil :keywords '("lists"))
+++ /dev/null
-;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2012-2015 Free Software Foundation, Inc.
-
-;; Author: Magnar Sveen <magnarsNOSPAMgmail.com>
-;; Version: 2.12.1
-;; Package-Version: 20151216.1315
-;; Keywords: lists
-
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; A modern list api for Emacs.
-;;
-;; See documentation on https://github.com/magnars/dash.el#functions
-;;
-;; **Please note** The lexical binding in this file is not utilised at the
-;; moment. We will take full advantage of lexical binding in an upcoming 3.0
-;; release of Dash. In the meantime, we've added the pragma to avoid a bug that
-;; you can read more about in https://github.com/magnars/dash.el/issues/130.
-;;
-
-;;; Code:
-
-(defgroup dash ()
- "Customize group for dash.el"
- :group 'lisp
- :prefix "dash-")
-
-(defun dash--enable-fontlock (symbol value)
- (when value
- (dash-enable-font-lock))
- (set-default symbol value))
-
-(defcustom dash-enable-fontlock nil
- "If non-nil, enable fontification of dash functions, macros and
-special values."
- :type 'boolean
- :set 'dash--enable-fontlock
- :group 'dash)
-
-(defmacro !cons (car cdr)
- "Destructive: Set CDR to the cons of CAR and CDR."
- `(setq ,cdr (cons ,car ,cdr)))
-
-(defmacro !cdr (list)
- "Destructive: Set LIST to the cdr of LIST."
- `(setq ,list (cdr ,list)))
-
-(defmacro --each (list &rest body)
- "Anaphoric form of `-each'."
- (declare (debug (form body))
- (indent 1))
- (let ((l (make-symbol "list")))
- `(let ((,l ,list)
- (it-index 0))
- (while ,l
- (let ((it (car ,l)))
- ,@body)
- (setq it-index (1+ it-index))
- (!cdr ,l)))))
-
-(defun -each (list fn)
- "Call FN with every item in LIST. Return nil, used for side-effects only."
- (--each list (funcall fn it)))
-
-(put '-each 'lisp-indent-function 1)
-
-(defmacro --each-while (list pred &rest body)
- "Anaphoric form of `-each-while'."
- (declare (debug (form form body))
- (indent 2))
- (let ((l (make-symbol "list"))
- (c (make-symbol "continue")))
- `(let ((,l ,list)
- (,c t)
- (it-index 0))
- (while (and ,l ,c)
- (let ((it (car ,l)))
- (if (not ,pred) (setq ,c nil) ,@body))
- (setq it-index (1+ it-index))
- (!cdr ,l)))))
-
-(defun -each-while (list pred fn)
- "Call FN with every item in LIST while (PRED item) is non-nil.
-Return nil, used for side-effects only."
- (--each-while list (funcall pred it) (funcall fn it)))
-
-(put '-each-while 'lisp-indent-function 2)
-
-(defmacro --dotimes (num &rest body)
- "Repeatedly executes BODY (presumably for side-effects) with `it` bound to integers from 0 through NUM-1."
- (declare (debug (form body))
- (indent 1))
- (let ((n (make-symbol "num")))
- `(let ((,n ,num)
- (it 0))
- (while (< it ,n)
- ,@body
- (setq it (1+ it))))))
-
-(defun -dotimes (num fn)
- "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1."
- (--dotimes num (funcall fn it)))
-
-(put '-dotimes 'lisp-indent-function 1)
-
-(defun -map (fn list)
- "Return a new list consisting of the result of applying FN to the items in LIST."
- (mapcar fn list))
-
-(defmacro --map (form list)
- "Anaphoric form of `-map'."
- (declare (debug (form form)))
- `(mapcar (lambda (it) ,form) ,list))
-
-(defmacro --reduce-from (form initial-value list)
- "Anaphoric form of `-reduce-from'."
- (declare (debug (form form form)))
- `(let ((acc ,initial-value))
- (--each ,list (setq acc ,form))
- acc))
-
-(defun -reduce-from (fn initial-value list)
- "Return the result of applying FN to INITIAL-VALUE and the
-first item in LIST, then applying FN to that result and the 2nd
-item, etc. If LIST contains no items, return INITIAL-VALUE and
-FN is not called.
-
-In the anaphoric form `--reduce-from', the accumulated value is
-exposed as `acc`.
-
-See also: `-reduce', `-reduce-r'"
- (--reduce-from (funcall fn acc it) initial-value list))
-
-(defmacro --reduce (form list)
- "Anaphoric form of `-reduce'."
- (declare (debug (form form)))
- (let ((lv (make-symbol "list-value")))
- `(let ((,lv ,list))
- (if ,lv
- (--reduce-from ,form (car ,lv) (cdr ,lv))
- (let (acc it) ,form)))))
-
-(defun -reduce (fn list)
- "Return the result of applying FN to the first 2 items in LIST,
-then applying FN to that result and the 3rd item, etc. If LIST
-contains no items, FN must accept no arguments as well, and
-reduce return the result of calling FN with no arguments. If
-LIST has only 1 item, it is returned and FN is not called.
-
-In the anaphoric form `--reduce', the accumulated value is
-exposed as `acc`.
-
-See also: `-reduce-from', `-reduce-r'"
- (if list
- (-reduce-from fn (car list) (cdr list))
- (funcall fn)))
-
-(defun -reduce-r-from (fn initial-value list)
- "Replace conses with FN, nil with INITIAL-VALUE and evaluate
-the resulting expression. If LIST is empty, INITIAL-VALUE is
-returned and FN is not called.
-
-Note: this function works the same as `-reduce-from' but the
-operation associates from right instead of from left.
-
-See also: `-reduce-r', `-reduce'"
- (if (not list) initial-value
- (funcall fn (car list) (-reduce-r-from fn initial-value (cdr list)))))
-
-(defmacro --reduce-r-from (form initial-value list)
- "Anaphoric version of `-reduce-r-from'."
- (declare (debug (form form form)))
- `(-reduce-r-from (lambda (&optional it acc) ,form) ,initial-value ,list))
-
-(defun -reduce-r (fn list)
- "Replace conses with FN and evaluate the resulting expression.
-The final nil is ignored. If LIST contains no items, FN must
-accept no arguments as well, and reduce return the result of
-calling FN with no arguments. If LIST has only 1 item, it is
-returned and FN is not called.
-
-The first argument of FN is the new item, the second is the
-accumulated value.
-
-Note: this function works the same as `-reduce' but the operation
-associates from right instead of from left.
-
-See also: `-reduce-r-from', `-reduce'"
- (cond
- ((not list) (funcall fn))
- ((not (cdr list)) (car list))
- (t (funcall fn (car list) (-reduce-r fn (cdr list))))))
-
-(defmacro --reduce-r (form list)
- "Anaphoric version of `-reduce-r'."
- (declare (debug (form form)))
- `(-reduce-r (lambda (&optional it acc) ,form) ,list))
-
-(defmacro --filter (form list)
- "Anaphoric form of `-filter'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each ,list (when ,form (!cons it ,r)))
- (nreverse ,r))))
-
-(defun -filter (pred list)
- "Return a new list of the items in LIST for which PRED returns a non-nil value.
-
-Alias: `-select'
-
-See also: `-keep'"
- (--filter (funcall pred it) list))
-
-(defalias '-select '-filter)
-(defalias '--select '--filter)
-
-(defmacro --remove (form list)
- "Anaphoric form of `-remove'."
- (declare (debug (form form)))
- `(--filter (not ,form) ,list))
-
-(defun -remove (pred list)
- "Return a new list of the items in LIST for which PRED returns nil.
-
-Alias: `-reject'"
- (--remove (funcall pred it) list))
-
-(defalias '-reject '-remove)
-(defalias '--reject '--remove)
-
-(defun -remove-first (pred list)
- "Return a new list with the first item matching PRED removed.
-
-Alias: `-reject-first'
-
-See also: `-remove', `-map-first'"
- (let (front)
- (while (and list (not (funcall pred (car list))))
- (push (car list) front)
- (!cdr list))
- (if list
- (-concat (nreverse front) (cdr list))
- (nreverse front))))
-
-(defmacro --remove-first (form list)
- "Anaphoric form of `-remove-first'."
- (declare (debug (form form)))
- `(-remove-first (lambda (it) ,form) ,list))
-
-(defalias '-reject-first '-remove-first)
-(defalias '--reject-first '--remove-first)
-
-(defun -remove-last (pred list)
- "Return a new list with the last item matching PRED removed.
-
-Alias: `-reject-last'
-
-See also: `-remove', `-map-last'"
- (nreverse (-remove-first pred (nreverse list))))
-
-(defmacro --remove-last (form list)
- "Anaphoric form of `-remove-last'."
- (declare (debug (form form)))
- `(-remove-last (lambda (it) ,form) ,list))
-
-(defalias '-reject-last '-remove-last)
-(defalias '--reject-last '--remove-last)
-
-(defun -remove-item (item list)
- "Remove all occurences of ITEM from LIST.
-
-Comparison is done with `equal'."
- (--remove (equal it item) list))
-
-(defmacro --keep (form list)
- "Anaphoric form of `-keep'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result"))
- (m (make-symbol "mapped")))
- `(let (,r)
- (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r))))
- (nreverse ,r))))
-
-(defun -keep (fn list)
- "Return a new list of the non-nil results of applying FN to the items in LIST.
-
-If you want to select the original items satisfying a predicate use `-filter'."
- (--keep (funcall fn it) list))
-
-(defun -non-nil (list)
- "Return all non-nil elements of LIST."
- (-remove 'null list))
-
-(defmacro --map-indexed (form list)
- "Anaphoric form of `-map-indexed'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each ,list
- (!cons ,form ,r))
- (nreverse ,r))))
-
-(defun -map-indexed (fn list)
- "Return a new list consisting of the result of (FN index item) for each item in LIST.
-
-In the anaphoric form `--map-indexed', the index is exposed as `it-index`."
- (--map-indexed (funcall fn it-index it) list))
-
-(defmacro --map-when (pred rep list)
- "Anaphoric form of `-map-when'."
- (declare (debug (form form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each ,list (!cons (if ,pred ,rep it) ,r))
- (nreverse ,r))))
-
-(defun -map-when (pred rep list)
- "Return a new list where the elements in LIST that does not match the PRED function
-are unchanged, and where the elements in LIST that do match the PRED function are mapped
-through the REP function.
-
-Alias: `-replace-where'
-
-See also: `-update-at'"
- (--map-when (funcall pred it) (funcall rep it) list))
-
-(defalias '-replace-where '-map-when)
-(defalias '--replace-where '--map-when)
-
-(defun -map-first (pred rep list)
- "Replace first item in LIST satisfying PRED with result of REP called on this item.
-
-See also: `-map-when', `-replace-first'"
- (let (front)
- (while (and list (not (funcall pred (car list))))
- (push (car list) front)
- (!cdr list))
- (if list
- (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list)))
- (nreverse front))))
-
-(defmacro --map-first (pred rep list)
- "Anaphoric form of `-map-first'."
- `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
-
-(defun -map-last (pred rep list)
- "Replace first item in LIST satisfying PRED with result of REP called on this item.
-
-See also: `-map-when', `-replace-last'"
- (nreverse (-map-first pred rep (nreverse list))))
-
-(defmacro --map-last (pred rep list)
- "Anaphoric form of `-map-last'."
- `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
-
-(defun -replace (old new list)
- "Replace all OLD items in LIST with NEW.
-
-Elements are compared using `equal'.
-
-See also: `-replace-at'"
- (--map-when (equal it old) new list))
-
-(defun -replace-first (old new list)
- "Replace the first occurence of OLD with NEW in LIST.
-
-Elements are compared using `equal'.
-
-See also: `-map-first'"
- (--map-first (equal old it) new list))
-
-(defun -replace-last (old new list)
- "Replace the last occurence of OLD with NEW in LIST.
-
-Elements are compared using `equal'.
-
-See also: `-map-last'"
- (--map-last (equal old it) new list))
-
-(defmacro --mapcat (form list)
- "Anaphoric form of `-mapcat'."
- (declare (debug (form form)))
- `(apply 'append (--map ,form ,list)))
-
-(defun -mapcat (fn list)
- "Return the concatenation of the result of mapping FN over LIST.
-Thus function FN should return a list."
- (--mapcat (funcall fn it) list))
-
-(defun -flatten (l)
- "Take a nested list L and return its contents as a single, flat list.
-
-Note that because `nil' represents a list of zero elements (an
-empty list), any mention of nil in L will disappear after
-flattening. If you need to preserve nils, consider `-flatten-n'
-or map them to some unique symbol and then map them back.
-
-Conses of two atoms are considered \"terminals\", that is, they
-aren't flattened further.
-
-See also: `-flatten-n'"
- (if (and (listp l) (listp (cdr l)))
- (-mapcat '-flatten l)
- (list l)))
-
-(defmacro --iterate (form init n)
- "Anaphoric version of `-iterate'."
- (declare (debug (form form form)))
- `(-iterate (lambda (it) ,form) ,init ,n))
-
-(defun -flatten-n (num list)
- "Flatten NUM levels of a nested LIST.
-
-See also: `-flatten'"
- (-last-item (--iterate (--mapcat (-list it) it) list (1+ num))))
-
-(defun -concat (&rest lists)
- "Return a new list with the concatenation of the elements in the supplied LISTS."
- (apply 'append lists))
-
-(defalias '-copy 'copy-sequence
- "Create a shallow copy of LIST.")
-
-(defun -splice (pred fun list)
- "Splice lists generated by FUN in place of elements matching PRED in LIST.
-
-FUN takes the element matching PRED as input.
-
-This function can be used as replacement for `,@' in case you
-need to splice several lists at marked positions (for example
-with keywords).
-
-See also: `-splice-list', `-insert-at'"
- (let (r)
- (--each list
- (if (funcall pred it)
- (let ((new (funcall fun it)))
- (--each new (!cons it r)))
- (!cons it r)))
- (nreverse r)))
-
-(defmacro --splice (pred form list)
- "Anaphoric form of `-splice'."
- `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list))
-
-(defun -splice-list (pred new-list list)
- "Splice NEW-LIST in place of elements matching PRED in LIST.
-
-See also: `-splice', `-insert-at'"
- (-splice pred (lambda (_) new-list) list))
-
-(defmacro --splice-list (pred new-list list)
- "Anaphoric form of `-splice-list'."
- `(-splice-list (lambda (it) ,pred) ,new-list ,list))
-
-(defun -cons* (&rest args)
- "Make a new list from the elements of ARGS.
-
-The last 2 members of ARGS are used as the final cons of the
-result so if the final member of ARGS is not a list the result is
-a dotted list."
- (-reduce-r 'cons args))
-
-(defun -snoc (list elem &rest elements)
- "Append ELEM to the end of the list.
-
-This is like `cons', but operates on the end of list.
-
-If ELEMENTS is non nil, append these to the list as well."
- (-concat list (list elem) elements))
-
-(defmacro --first (form list)
- "Anaphoric form of `-first'."
- (declare (debug (form form)))
- (let ((n (make-symbol "needle")))
- `(let (,n)
- (--each-while ,list (not ,n)
- (when ,form (setq ,n it)))
- ,n)))
-
-(defun -first (pred list)
- "Return the first x in LIST where (PRED x) is non-nil, else nil.
-
-To get the first item in the list no questions asked, use `car'.
-
-Alias: `-find'"
- (--first (funcall pred it) list))
-
-(defalias '-find '-first)
-(defalias '--find '--first)
-
-(defmacro --some (form list)
- "Anaphoric form of `-some'."
- (declare (debug (form form)))
- (let ((n (make-symbol "needle")))
- `(let (,n)
- (--each-while ,list (not ,n)
- (setq ,n ,form))
- ,n)))
-
-(defun -some (pred list)
- "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil.
-
-Alias: `-any'"
- (--some (funcall pred it) list))
-
-(defalias '-any '-some)
-(defalias '--any '--some)
-
-(defmacro --last (form list)
- "Anaphoric form of `-last'."
- (declare (debug (form form)))
- (let ((n (make-symbol "needle")))
- `(let (,n)
- (--each ,list
- (when ,form (setq ,n it)))
- ,n)))
-
-(defun -last (pred list)
- "Return the last x in LIST where (PRED x) is non-nil, else nil."
- (--last (funcall pred it) list))
-
-(defalias '-first-item 'car
- "Return the first item of LIST, or nil on an empty list.")
-
-(defun -last-item (list)
- "Return the last item of LIST, or nil on an empty list."
- (car (last list)))
-
-(defun -butlast (list)
- "Return a list of all items in list except for the last."
- (let (result)
- (while (cdr list)
- (!cons (car list) result)
- (!cdr list))
- (nreverse result)))
-
-(defmacro --count (pred list)
- "Anaphoric form of `-count'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let ((,r 0))
- (--each ,list (when ,pred (setq ,r (1+ ,r))))
- ,r)))
-
-(defun -count (pred list)
- "Counts the number of items in LIST where (PRED item) is non-nil."
- (--count (funcall pred it) list))
-
-(defun ---truthy? (val)
- (not (null val)))
-
-(defmacro --any? (form list)
- "Anaphoric form of `-any?'."
- (declare (debug (form form)))
- `(---truthy? (--first ,form ,list)))
-
-(defun -any? (pred list)
- "Return t if (PRED x) is non-nil for any x in LIST, else nil.
-
-Alias: `-any-p', `-some?', `-some-p'"
- (--any? (funcall pred it) list))
-
-(defalias '-some? '-any?)
-(defalias '--some? '--any?)
-(defalias '-any-p '-any?)
-(defalias '--any-p '--any?)
-(defalias '-some-p '-any?)
-(defalias '--some-p '--any?)
-
-(defmacro --all? (form list)
- "Anaphoric form of `-all?'."
- (declare (debug (form form)))
- (let ((a (make-symbol "all")))
- `(let ((,a t))
- (--each-while ,list ,a (setq ,a ,form))
- (---truthy? ,a))))
-
-(defun -all? (pred list)
- "Return t if (PRED x) is non-nil for all x in LIST, else nil.
-
-Alias: `-all-p', `-every?', `-every-p'"
- (--all? (funcall pred it) list))
-
-(defalias '-every? '-all?)
-(defalias '--every? '--all?)
-(defalias '-all-p '-all?)
-(defalias '--all-p '--all?)
-(defalias '-every-p '-all?)
-(defalias '--every-p '--all?)
-
-(defmacro --none? (form list)
- "Anaphoric form of `-none?'."
- (declare (debug (form form)))
- `(--all? (not ,form) ,list))
-
-(defun -none? (pred list)
- "Return t if (PRED x) is nil for all x in LIST, else nil.
-
-Alias: `-none-p'"
- (--none? (funcall pred it) list))
-
-(defalias '-none-p '-none?)
-(defalias '--none-p '--none?)
-
-(defmacro --only-some? (form list)
- "Anaphoric form of `-only-some?'."
- (declare (debug (form form)))
- (let ((y (make-symbol "yes"))
- (n (make-symbol "no")))
- `(let (,y ,n)
- (--each-while ,list (not (and ,y ,n))
- (if ,form (setq ,y t) (setq ,n t)))
- (---truthy? (and ,y ,n)))))
-
-(defun -only-some? (pred list)
- "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED.
-Return `nil` both if all items match the predicate or if none of the items match the predicate.
-
-Alias: `-only-some-p'"
- (--only-some? (funcall pred it) list))
-
-(defalias '-only-some-p '-only-some?)
-(defalias '--only-some-p '--only-some?)
-
-(defun -slice (list from &optional to step)
- "Return copy of LIST, starting from index FROM to index TO.
-
-FROM or TO may be negative. These values are then interpreted
-modulo the length of the list.
-
-If STEP is a number, only each STEPth item in the resulting
-section is returned. Defaults to 1."
- (let ((length (length list))
- (new-list nil))
- ;; to defaults to the end of the list
- (setq to (or to length))
- (setq step (or step 1))
- ;; handle negative indices
- (when (< from 0)
- (setq from (mod from length)))
- (when (< to 0)
- (setq to (mod to length)))
-
- ;; iterate through the list, keeping the elements we want
- (--each-while list (< it-index to)
- (when (and (>= it-index from)
- (= (mod (- from it-index) step) 0))
- (push it new-list)))
- (nreverse new-list)))
-
-(defun -take (n list)
- "Return a new list of the first N items in LIST, or all items if there are fewer than N."
- (let (result)
- (--dotimes n
- (when list
- (!cons (car list) result)
- (!cdr list)))
- (nreverse result)))
-
-(defalias '-drop 'nthcdr "Return the tail of LIST without the first N items.")
-
-(defmacro --take-while (form list)
- "Anaphoric form of `-take-while'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result")))
- `(let (,r)
- (--each-while ,list ,form (!cons it ,r))
- (nreverse ,r))))
-
-(defun -take-while (pred list)
- "Return a new list of successive items from LIST while (PRED item) returns a non-nil value."
- (--take-while (funcall pred it) list))
-
-(defmacro --drop-while (form list)
- "Anaphoric form of `-drop-while'."
- (declare (debug (form form)))
- (let ((l (make-symbol "list")))
- `(let ((,l ,list))
- (while (and ,l (let ((it (car ,l))) ,form))
- (!cdr ,l))
- ,l)))
-
-(defun -drop-while (pred list)
- "Return the tail of LIST starting from the first item for which (PRED item) returns nil."
- (--drop-while (funcall pred it) list))
-
-(defun -split-at (n list)
- "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list."
- (let (result)
- (--dotimes n
- (when list
- (!cons (car list) result)
- (!cdr list)))
- (list (nreverse result) list)))
-
-(defun -rotate (n list)
- "Rotate LIST N places to the right. With N negative, rotate to the left.
-The time complexity is O(n)."
- (if (> n 0)
- (append (last list n) (butlast list n))
- (append (-drop (- n) list) (-take (- n) list))))
-
-(defun -insert-at (n x list)
- "Return a list with X inserted into LIST at position N.
-
-See also: `-splice', `-splice-list'"
- (let ((split-list (-split-at n list)))
- (nconc (car split-list) (cons x (cadr split-list)))))
-
-(defun -replace-at (n x list)
- "Return a list with element at Nth position in LIST replaced with X.
-
-See also: `-replace'"
- (let ((split-list (-split-at n list)))
- (nconc (car split-list) (cons x (cdr (cadr split-list))))))
-
-(defun -update-at (n func list)
- "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`.
-
-See also: `-map-when'"
- (let ((split-list (-split-at n list)))
- (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list))))))
-
-(defmacro --update-at (n form list)
- "Anaphoric version of `-update-at'."
- (declare (debug (form form form)))
- `(-update-at ,n (lambda (it) ,form) ,list))
-
-(defun -remove-at (n list)
- "Return a list with element at Nth position in LIST removed.
-
-See also: `-remove-at-indices', `-remove'"
- (-remove-at-indices (list n) list))
-
-(defun -remove-at-indices (indices list)
- "Return a list whose elements are elements from LIST without
-elements selected as `(nth i list)` for all i
-from INDICES.
-
-See also: `-remove-at', `-remove'"
- (let* ((indices (-sort '< indices))
- (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices))))
- r)
- (--each diffs
- (let ((split (-split-at it list)))
- (!cons (car split) r)
- (setq list (cdr (cadr split)))))
- (!cons list r)
- (apply '-concat (nreverse r))))
-
-(defmacro --split-with (pred list)
- "Anaphoric form of `-split-with'."
- (declare (debug (form form)))
- (let ((l (make-symbol "list"))
- (r (make-symbol "result"))
- (c (make-symbol "continue")))
- `(let ((,l ,list)
- (,r nil)
- (,c t))
- (while (and ,l ,c)
- (let ((it (car ,l)))
- (if (not ,pred)
- (setq ,c nil)
- (!cons it ,r)
- (!cdr ,l))))
- (list (nreverse ,r) ,l))))
-
-(defun -split-with (pred list)
- "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list."
- (--split-with (funcall pred it) list))
-
-(defmacro -split-on (item list)
- "Split the LIST each time ITEM is found.
-
-Unlike `-partition-by', the ITEM is discarded from the results.
-Empty lists are also removed from the result.
-
-Comparison is done by `equal'.
-
-See also `-split-when'"
- (declare (debug (form form)))
- `(-split-when (lambda (it) (equal it ,item)) ,list))
-
-(defmacro --split-when (form list)
- "Anaphoric version of `-split-when'."
- (declare (debug (form form)))
- `(-split-when (lambda (it) ,form) ,list))
-
-(defun -split-when (fn list)
- "Split the LIST on each element where FN returns non-nil.
-
-Unlike `-partition-by', the \"matched\" element is discarded from
-the results. Empty lists are also removed from the result.
-
-This function can be thought of as a generalization of
-`split-string'."
- (let (r s)
- (while list
- (if (not (funcall fn (car list)))
- (push (car list) s)
- (when s (push (nreverse s) r))
- (setq s nil))
- (!cdr list))
- (when s (push (nreverse s) r))
- (nreverse r)))
-
-(defmacro --separate (form list)
- "Anaphoric form of `-separate'."
- (declare (debug (form form)))
- (let ((y (make-symbol "yes"))
- (n (make-symbol "no")))
- `(let (,y ,n)
- (--each ,list (if ,form (!cons it ,y) (!cons it ,n)))
- (list (nreverse ,y) (nreverse ,n)))))
-
-(defun -separate (pred list)
- "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list."
- (--separate (funcall pred it) list))
-
-(defun ---partition-all-in-steps-reversed (n step list)
- "Private: Used by -partition-all-in-steps and -partition-in-steps."
- (when (< step 1)
- (error "Step must be a positive number, or you're looking at some juicy infinite loops."))
- (let ((result nil))
- (while list
- (!cons (-take n list) result)
- (setq list (-drop step list)))
- result))
-
-(defun -partition-all-in-steps (n step list)
- "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
-The last groups may contain less than N items."
- (nreverse (---partition-all-in-steps-reversed n step list)))
-
-(defun -partition-in-steps (n step list)
- "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
-If there are not enough items to make the last group N-sized,
-those items are discarded."
- (let ((result (---partition-all-in-steps-reversed n step list)))
- (while (and result (< (length (car result)) n))
- (!cdr result))
- (nreverse result)))
-
-(defun -partition-all (n list)
- "Return a new list with the items in LIST grouped into N-sized sublists.
-The last group may contain less than N items."
- (-partition-all-in-steps n n list))
-
-(defun -partition (n list)
- "Return a new list with the items in LIST grouped into N-sized sublists.
-If there are not enough items to make the last group N-sized,
-those items are discarded."
- (-partition-in-steps n n list))
-
-(defmacro --partition-by (form list)
- "Anaphoric form of `-partition-by'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result"))
- (s (make-symbol "sublist"))
- (v (make-symbol "value"))
- (n (make-symbol "new-value"))
- (l (make-symbol "list")))
- `(let ((,l ,list))
- (when ,l
- (let* ((,r nil)
- (it (car ,l))
- (,s (list it))
- (,v ,form)
- (,l (cdr ,l)))
- (while ,l
- (let* ((it (car ,l))
- (,n ,form))
- (unless (equal ,v ,n)
- (!cons (nreverse ,s) ,r)
- (setq ,s nil)
- (setq ,v ,n))
- (!cons it ,s)
- (!cdr ,l)))
- (!cons (nreverse ,s) ,r)
- (nreverse ,r))))))
-
-(defun -partition-by (fn list)
- "Apply FN to each item in LIST, splitting it each time FN returns a new value."
- (--partition-by (funcall fn it) list))
-
-(defmacro --partition-by-header (form list)
- "Anaphoric form of `-partition-by-header'."
- (declare (debug (form form)))
- (let ((r (make-symbol "result"))
- (s (make-symbol "sublist"))
- (h (make-symbol "header-value"))
- (b (make-symbol "seen-body?"))
- (n (make-symbol "new-value"))
- (l (make-symbol "list")))
- `(let ((,l ,list))
- (when ,l
- (let* ((,r nil)
- (it (car ,l))
- (,s (list it))
- (,h ,form)
- (,b nil)
- (,l (cdr ,l)))
- (while ,l
- (let* ((it (car ,l))
- (,n ,form))
- (if (equal ,h ,n)
- (when ,b
- (!cons (nreverse ,s) ,r)
- (setq ,s nil)
- (setq ,b nil))
- (setq ,b t))
- (!cons it ,s)
- (!cdr ,l)))
- (!cons (nreverse ,s) ,r)
- (nreverse ,r))))))
-
-(defun -partition-by-header (fn list)
- "Apply FN to the first item in LIST. That is the header
-value. Apply FN to each item in LIST, splitting it each time FN
-returns the header value, but only after seeing at least one
-other value (the body)."
- (--partition-by-header (funcall fn it) list))
-
-(defmacro --group-by (form list)
- "Anaphoric form of `-group-by'."
- (declare (debug t))
- (let ((n (make-symbol "n"))
- (k (make-symbol "k"))
- (grp (make-symbol "grp")))
- `(nreverse
- (-map
- (lambda (,n)
- (cons (car ,n)
- (nreverse (cdr ,n))))
- (--reduce-from
- (let* ((,k (,@form))
- (,grp (assoc ,k acc)))
- (if ,grp
- (setcdr ,grp (cons it (cdr ,grp)))
- (push
- (list ,k it)
- acc))
- acc)
- nil ,list)))))
-
-(defun -group-by (fn list)
- "Separate LIST into an alist whose keys are FN applied to the
-elements of LIST. Keys are compared by `equal'."
- (--group-by (funcall fn it) list))
-
-(defun -interpose (sep list)
- "Return a new list of all elements in LIST separated by SEP."
- (let (result)
- (when list
- (!cons (car list) result)
- (!cdr list))
- (while list
- (setq result (cons (car list) (cons sep result)))
- (!cdr list))
- (nreverse result)))
-
-(defun -interleave (&rest lists)
- "Return a new list of the first item in each list, then the second etc."
- (let (result)
- (while (-none? 'null lists)
- (--each lists (!cons (car it) result))
- (setq lists (-map 'cdr lists)))
- (nreverse result)))
-
-(defmacro --zip-with (form list1 list2)
- "Anaphoric form of `-zip-with'.
-
-The elements in list1 is bound as `it`, the elements in list2 as `other`."
- (declare (debug (form form form)))
- (let ((r (make-symbol "result"))
- (l1 (make-symbol "list1"))
- (l2 (make-symbol "list2")))
- `(let ((,r nil)
- (,l1 ,list1)
- (,l2 ,list2))
- (while (and ,l1 ,l2)
- (let ((it (car ,l1))
- (other (car ,l2)))
- (!cons ,form ,r)
- (!cdr ,l1)
- (!cdr ,l2)))
- (nreverse ,r))))
-
-(defun -zip-with (fn list1 list2)
- "Zip the two lists LIST1 and LIST2 using a function FN. This
-function is applied pairwise taking as first argument element of
-LIST1 and as second argument element of LIST2 at corresponding
-position.
-
-The anaphoric form `--zip-with' binds the elements from LIST1 as `it`,
-and the elements from LIST2 as `other`."
- (--zip-with (funcall fn it other) list1 list2))
-
-(defun -zip (&rest lists)
- "Zip LISTS together. Group the head of each list, followed by the
-second elements of each list, and so on. The lengths of the returned
-groupings are equal to the length of the shortest input list.
-
-If two lists are provided as arguments, return the groupings as a list
-of cons cells. Otherwise, return the groupings as a list of lists.
-
-Please note! This distinction is being removed in an upcoming 2.0
-release of Dash. If you rely on this behavior, use -zip-pair instead."
- (let (results)
- (while (-none? 'null lists)
- (setq results (cons (mapcar 'car lists) results))
- (setq lists (mapcar 'cdr lists)))
- (setq results (nreverse results))
- (if (= (length lists) 2)
- ;; to support backward compatability, return
- ;; a cons cell if two lists were provided
- (--map (cons (car it) (cadr it)) results)
- results)))
-
-(defalias '-zip-pair '-zip)
-
-(defun -zip-fill (fill-value &rest lists)
- "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The
-lengths of the returned groupings are equal to the length of the
-longest input list."
- (apply '-zip (apply '-pad (cons fill-value lists))))
-
-(defun -cycle (list)
- "Return an infinite copy of LIST that will cycle through the
-elements and repeat from the beginning."
- (let ((newlist (-map 'identity list)))
- (nconc newlist newlist)))
-
-(defun -pad (fill-value &rest lists)
- "Appends FILL-VALUE to the end of each list in LISTS such that they
-will all have the same length."
- (let* ((annotations (-annotate 'length lists))
- (n (-max (-map 'car annotations))))
- (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations)))
-
-(defun -annotate (fn list)
- "Return a list of cons cells where each cell is FN applied to each
-element of LIST paired with the unmodified element of LIST."
- (-zip (-map fn list) list))
-
-(defmacro --annotate (form list)
- "Anaphoric version of `-annotate'."
- (declare (debug (form form)))
- `(-annotate (lambda (it) ,form) ,list))
-
-(defun dash--table-carry (lists restore-lists &optional re)
- "Helper for `-table' and `-table-flat'.
-
-If a list overflows, carry to the right and reset the list."
- (while (not (or (car lists)
- (equal lists '(nil))))
- (setcar lists (car restore-lists))
- (pop (cadr lists))
- (!cdr lists)
- (!cdr restore-lists)
- (when re
- (push (nreverse (car re)) (cadr re))
- (setcar re nil)
- (!cdr re))))
-
-(defun -table (fn &rest lists)
- "Compute outer product of LISTS using function FN.
-
-The function FN should have the same arity as the number of
-supplied lists.
-
-The outer product is computed by applying fn to all possible
-combinations created by taking one element from each list in
-order. The dimension of the result is (length lists).
-
-See also: `-table-flat'"
- (let ((restore-lists (copy-sequence lists))
- (last-list (last lists))
- (re (make-list (length lists) nil)))
- (while (car last-list)
- (let ((item (apply fn (-map 'car lists))))
- (push item (car re))
- (setcar lists (cdar lists)) ;; silence byte compiler
- (dash--table-carry lists restore-lists re)))
- (nreverse (car (last re)))))
-
-(defun -table-flat (fn &rest lists)
- "Compute flat outer product of LISTS using function FN.
-
-The function FN should have the same arity as the number of
-supplied lists.
-
-The outer product is computed by applying fn to all possible
-combinations created by taking one element from each list in
-order. The results are flattened, ignoring the tensor structure
-of the result. This is equivalent to calling:
-
- (-flatten-n (1- (length lists)) (-table fn lists))
-
-but the implementation here is much more efficient.
-
-See also: `-flatten-n', `-table'"
- (when lists ;Just in case.
- (let* ((list1 (pop lists))
- (restore-lists (copy-sequence lists))
- (last-list (last lists))
- re)
- (while (car last-list)
- (let ((tail (-map #'car lists)))
- (dolist (head list1)
- (push (apply fn head tail) re)))
- (pop (car lists))
- (dash--table-carry lists restore-lists))
- (nreverse re))))
-
-(defun -partial (fn &rest args)
- "Take a function FN and fewer than the normal arguments to FN,
-and return a fn that takes a variable number of additional ARGS.
-When called, the returned function calls FN with ARGS first and
-then additional args."
- (apply 'apply-partially fn args))
-
-(defun -elem-index (elem list)
- "Return the index of the first element in the given LIST which
-is equal to the query element ELEM, or nil if there is no
-such element."
- (car (-elem-indices elem list)))
-
-(defun -elem-indices (elem list)
- "Return the indices of all elements in LIST equal to the query
-element ELEM, in ascending order."
- (-find-indices (-partial 'equal elem) list))
-
-(defun -find-indices (pred list)
- "Return the indices of all elements in LIST satisfying the
-predicate PRED, in ascending order."
- (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list)))
-
-(defmacro --find-indices (form list)
- "Anaphoric version of `-find-indices'."
- (declare (debug (form form)))
- `(-find-indices (lambda (it) ,form) ,list))
-
-(defun -find-index (pred list)
- "Take a predicate PRED and a LIST and return the index of the
-first element in the list satisfying the predicate, or nil if
-there is no such element."
- (car (-find-indices pred list)))
-
-(defmacro --find-index (form list)
- "Anaphoric version of `-find-index'."
- (declare (debug (form form)))
- `(-find-index (lambda (it) ,form) ,list))
-
-(defun -find-last-index (pred list)
- "Take a predicate PRED and a LIST and return the index of the
-last element in the list satisfying the predicate, or nil if
-there is no such element."
- (-last-item (-find-indices pred list)))
-
-(defmacro --find-last-index (form list)
- "Anaphoric version of `-find-last-index'."
- `(-find-last-index (lambda (it) ,form) ,list))
-
-(defun -select-by-indices (indices list)
- "Return a list whose elements are elements from LIST selected
-as `(nth i list)` for all i from INDICES."
- (let (r)
- (--each indices
- (!cons (nth it list) r))
- (nreverse r)))
-
-(defmacro -> (x &optional form &rest more)
- "Thread the expr through the forms. Insert X as the second item
-in the first form, making a list of it if it is not a list
-already. If there are more forms, insert the first form as the
-second item in second form, etc."
- (cond
- ((null form) x)
- ((null more) (if (listp form)
- `(,(car form) ,x ,@(cdr form))
- (list form x)))
- (:else `(-> (-> ,x ,form) ,@more))))
-
-(defmacro ->> (x &optional form &rest more)
- "Thread the expr through the forms. Insert X as the last item
-in the first form, making a list of it if it is not a list
-already. If there are more forms, insert the first form as the
-last item in second form, etc."
- (cond
- ((null form) x)
- ((null more) (if (listp form)
- `(,@form ,x)
- (list form x)))
- (:else `(->> (->> ,x ,form) ,@more))))
-
-(defmacro --> (x form &rest more)
- "Thread the expr through the forms. Insert X at the position
-signified by the token `it' in the first form. If there are more
-forms, insert the first form at the position signified by `it' in
-in second form, etc."
- (if (null more)
- (if (listp form)
- (--map-when (eq it 'it) x form)
- (list form x))
- `(--> (--> ,x ,form) ,@more)))
-
-(defmacro -some-> (x &optional form &rest more)
- "When expr is non-nil, thread it through the first form (via `->'),
-and when that result is non-nil, through the next form, etc."
- (if (null form) x
- (let ((result (make-symbol "result")))
- `(-some-> (-when-let (,result ,x)
- (-> ,result ,form))
- ,@more))))
-
-(defmacro -some->> (x &optional form &rest more)
- "When expr is non-nil, thread it through the first form (via `->>'),
-and when that result is non-nil, through the next form, etc."
- (if (null form) x
- (let ((result (make-symbol "result")))
- `(-some->> (-when-let (,result ,x)
- (->> ,result ,form))
- ,@more))))
-
-(defmacro -some--> (x &optional form &rest more)
- "When expr in non-nil, thread it through the first form (via `-->'),
-and when that result is non-nil, through the next form, etc."
- (if (null form) x
- (let ((result (make-symbol "result")))
- `(-some--> (-when-let (,result ,x)
- (--> ,result ,form))
- ,@more))))
-
-(defun -grade-up (comparator list)
- "Grade elements of LIST using COMPARATOR relation, yielding a
-permutation vector such that applying this permutation to LIST
-sorts it in ascending order."
- ;; ugly hack to "fix" lack of lexical scope
- (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other)))))
- (->> (--map-indexed (cons it it-index) list)
- (-sort comp)
- (-map 'cdr))))
-
-(defun -grade-down (comparator list)
- "Grade elements of LIST using COMPARATOR relation, yielding a
-permutation vector such that applying this permutation to LIST
-sorts it in descending order."
- ;; ugly hack to "fix" lack of lexical scope
- (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it)))))
- (->> (--map-indexed (cons it it-index) list)
- (-sort comp)
- (-map 'cdr))))
-
-(defvar dash--source-counter 0
- "Monotonic counter for generated symbols.")
-
-(defun dash--match-make-source-symbol ()
- "Generate a new dash-source symbol.
-
-All returned symbols are guaranteed to be unique."
- (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter))
- (setq dash--source-counter (1+ dash--source-counter))))
-
-(defun dash--match-ignore-place-p (symbol)
- "Return non-nil if SYMBOL is a symbol and starts with _."
- (and (symbolp symbol)
- (eq (aref (symbol-name symbol) 0) ?_)))
-
-(defun dash--match-cons-skip-cdr (skip-cdr source)
- "Helper function generating idiomatic shifting code."
- (cond
- ((= skip-cdr 0)
- `(pop ,source))
- (t
- `(prog1 ,(dash--match-cons-get-car skip-cdr source)
- (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source))))))
-
-(defun dash--match-cons-get-car (skip-cdr source)
- "Helper function generating idiomatic code to get nth car."
- (cond
- ((= skip-cdr 0)
- `(car ,source))
- ((= skip-cdr 1)
- `(cadr ,source))
- (t
- `(nth ,skip-cdr ,source))))
-
-(defun dash--match-cons-get-cdr (skip-cdr source)
- "Helper function generating idiomatic code to get nth cdr."
- (cond
- ((= skip-cdr 0)
- source)
- ((= skip-cdr 1)
- `(cdr ,source))
- (t
- `(nthcdr ,skip-cdr ,source))))
-
-(defun dash--match-cons (match-form source)
- "Setup a cons matching environment and call the real matcher."
- (let ((s (dash--match-make-source-symbol))
- (n 0)
- (m match-form))
- (while (and (consp m)
- (dash--match-ignore-place-p (car m)))
- (setq n (1+ n)) (!cdr m))
- (cond
- ;; when we only have one pattern in the list, we don't have to
- ;; create a temporary binding (--dash-source--) for the source
- ;; and just use the input directly
- ((and (consp m)
- (not (cdr m)))
- (dash--match (car m) (dash--match-cons-get-car n source)))
- ;; handle other special types
- ((> n 0)
- (dash--match m (dash--match-cons-get-cdr n source)))
- ;; this is the only entry-point for dash--match-cons-1, that's
- ;; why we can't simply use the above branch, it would produce
- ;; infinite recursion
- (t
- (cons (list s source) (dash--match-cons-1 match-form s))))))
-
-(defun dash--match-cons-1 (match-form source &optional props)
- "Match MATCH-FORM against SOURCE.
-
-MATCH-FORM is a proper or improper list. Each element of
-MATCH-FORM is either a symbol, which gets bound to the respective
-value in source or another match form which gets destructured
-recursively.
-
-If the cdr of last cons cell in the list is `nil', matching stops
-there.
-
-SOURCE is a proper or improper list."
- (let ((skip-cdr (or (plist-get props :skip-cdr) 0)))
- (cond
- ((consp match-form)
- (cond
- ((cdr match-form)
- (cond
- ((and (symbolp (car match-form))
- (memq (car match-form) '(&keys &plist &alist &hash)))
- (dash--match-kv match-form (dash--match-cons-get-cdr skip-cdr source)))
- ((dash--match-ignore-place-p (car match-form))
- (dash--match-cons-1 (cdr match-form) source
- (plist-put props :skip-cdr (1+ skip-cdr))))
- (t
- (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source))
- (dash--match-cons-1 (cdr match-form) source)))))
- (t ;; Last matching place, no need for shift
- (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source)))))
- ((eq match-form nil)
- nil)
- (t ;; Handle improper lists. Last matching place, no need for shift
- (dash--match match-form (dash--match-cons-get-cdr skip-cdr source))))))
-
-(defun dash--vector-tail (seq start)
- "Return the tail of SEQ starting at START."
- (cond
- ((vectorp seq)
- (let* ((re-length (- (length seq) start))
- (re (make-vector re-length 0)))
- (--dotimes re-length (aset re it (aref seq (+ it start))))
- re))
- ((stringp seq)
- (substring seq start))))
-
-(defun dash--match-vector (match-form source)
- "Setup a vector matching environment and call the real matcher."
- (let ((s (dash--match-make-source-symbol)))
- (cond
- ;; don't bind `s' if we only have one sub-pattern
- ((= (length match-form) 1)
- (dash--match (aref match-form 0) `(aref ,source 0)))
- ;; if the source is a symbol, we don't need to re-bind it
- ((symbolp source)
- (dash--match-vector-1 match-form source))
- ;; don't bind `s' if we only have one sub-pattern which is not ignored
- ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form))
- (ignored-places-n (length (-remove 'null ignored-places))))
- (when (= ignored-places-n (1- (length match-form)))
- (let ((n (-find-index 'null ignored-places)))
- (dash--match (aref match-form n) `(aref ,source ,n))))))
- (t
- (cons (list s source) (dash--match-vector-1 match-form s))))))
-
-(defun dash--match-vector-1 (match-form source)
- "Match MATCH-FORM against SOURCE.
-
-MATCH-FORM is a vector. Each element of MATCH-FORM is either a
-symbol, which gets bound to the respective value in source or
-another match form which gets destructured recursively.
-
-If second-from-last place in MATCH-FORM is the symbol &rest, the
-next element of the MATCH-FORM is matched against the tail of
-SOURCE, starting at index of the &rest symbol. This is
-conceptually the same as the (head . tail) match for improper
-lists, where dot plays the role of &rest.
-
-SOURCE is a vector.
-
-If the MATCH-FORM vector is shorter than SOURCE vector, only
-the (length MATCH-FORM) places are bound, the rest of the SOURCE
-is discarded."
- (let ((i 0)
- (l (length match-form))
- (re))
- (while (< i l)
- (let ((m (aref match-form i)))
- (push (cond
- ((and (symbolp m)
- (eq m '&rest))
- (prog1 (dash--match
- (aref match-form (1+ i))
- `(dash--vector-tail ,source ,i))
- (setq i l)))
- ((and (symbolp m)
- ;; do not match symbols starting with _
- (not (eq (aref (symbol-name m) 0) ?_)))
- (list (list m `(aref ,source ,i))))
- ((not (symbolp m))
- (dash--match m `(aref ,source ,i))))
- re)
- (setq i (1+ i))))
- (-flatten-n 1 (nreverse re))))
-
-(defun dash--match-kv (match-form source)
- "Setup a kv matching environment and call the real matcher.
-
-kv can be any key-value store, such as plist, alist or hash-table."
- (let ((s (dash--match-make-source-symbol)))
- (cond
- ;; don't bind `s' if we only have one sub-pattern (&type key val)
- ((= (length match-form) 3)
- (dash--match-kv-1 (cdr match-form) source (car match-form)))
- ;; if the source is a symbol, we don't need to re-bind it
- ((symbolp source)
- (dash--match-kv-1 (cdr match-form) source (car match-form)))
- (t
- (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form)))))))
-
-(defun dash--match-kv-1 (match-form source type)
- "Match MATCH-FORM against SOURCE of type TYPE.
-
-MATCH-FORM is a proper list of the form (key1 place1 ... keyN
-placeN). Each placeK is either a symbol, which gets bound to the
-value of keyK retrieved from the key-value store, or another
-match form which gets destructured recursively.
-
-SOURCE is a key-value store of type TYPE, which can be a plist,
-an alist or a hash table.
-
-TYPE is a token specifying the type of the key-value store.
-Valid values are &plist, &alist and &hash."
- (-flatten-n 1 (-map
- (lambda (kv)
- (let* ((k (car kv))
- (v (cadr kv))
- (getter (cond
- ((or (eq type '&plist) (eq type '&keys))
- `(plist-get ,source ,k))
- ((eq type '&alist)
- `(cdr (assoc ,k ,source)))
- ((eq type '&hash)
- `(gethash ,k ,source)))))
- (cond
- ((symbolp v)
- (list (list v getter)))
- (t (dash--match v getter)))))
- (-partition 2 match-form))))
-
-(defun dash--match-symbol (match-form source)
- "Bind a symbol.
-
-This works just like `let', there is no destructuring."
- (list (list match-form source)))
-
-(defun dash--match (match-form source)
- "Match MATCH-FORM against SOURCE.
-
-This function tests the MATCH-FORM and dispatches to specific
-matchers based on the type of the expression.
-
-Key-value stores are disambiguated by placing a token &plist,
-&alist or &hash as a first item in the MATCH-FORM."
- (cond
- ((symbolp match-form)
- (dash--match-symbol match-form source))
- ((consp match-form)
- (cond
- ;; Handle the "x &as" bindings first.
- ((and (consp (cdr match-form))
- (symbolp (car match-form))
- (eq '&as (cadr match-form)))
- (let ((s (car match-form)))
- (cons (list s source)
- (dash--match (cddr match-form) s))))
- ((memq (car match-form) '(&keys &plist &alist &hash))
- (dash--match-kv match-form source))
- (t (dash--match-cons match-form source))))
- ((vectorp match-form)
- ;; We support the &as binding in vectors too
- (cond
- ((and (> (length match-form) 2)
- (symbolp (aref match-form 0))
- (eq '&as (aref match-form 1)))
- (let ((s (aref match-form 0)))
- (cons (list s source)
- (dash--match (dash--vector-tail match-form 2) s))))
- (t (dash--match-vector match-form source))))))
-
-(defmacro -let* (varlist &rest body)
- "Bind variables according to VARLIST then eval BODY.
-
-VARLIST is a list of lists of the form (PATTERN SOURCE). Each
-PATTERN is matched against the SOURCE structurally. SOURCE is
-only evaluated once for each PATTERN.
-
-Each SOURCE can refer to the symbols already bound by this
-VARLIST. This is useful if you want to destructure SOURCE
-recursively but also want to name the intermediate structures.
-
-See `-let' for the list of all possible patterns."
- (declare (debug ((&rest (sexp form)) body))
- (indent 1))
- (let ((bindings (--mapcat (dash--match (car it) (cadr it)) varlist)))
- `(let* ,bindings
- ,@body)))
-
-(defmacro -let (varlist &rest body)
- "Bind variables according to VARLIST then eval BODY.
-
-VARLIST is a list of lists of the form (PATTERN SOURCE). Each
-PATTERN is matched against the SOURCE \"structurally\". SOURCE
-is only evaluated once for each PATTERN. Each PATTERN is matched
-recursively, and can therefore contain sub-patterns which are
-matched against corresponding sub-expressions of SOURCE.
-
-All the SOURCEs are evalled before any symbols are
-bound (i.e. \"in parallel\").
-
-If VARLIST only contains one (PATTERN SOURCE) element, you can
-optionally specify it using a vector and discarding the
-outer-most parens. Thus
-
- (-let ((PATTERN SOURCE)) ..)
-
-becomes
-
- (-let [PATTERN SOURCE] ..).
-
-`-let' uses a convention of not binding places (symbols) starting
-with _ whenever it's possible. You can use this to skip over
-entries you don't care about. However, this is not *always*
-possible (as a result of implementation) and these symbols might
-get bound to undefined values.
-
-Following is the overview of supported patterns. Remember that
-patterns can be matched recursively, so every a, b, aK in the
-following can be a matching construct and not necessarily a
-symbol/variable.
-
-Symbol:
-
- a - bind the SOURCE to A. This is just like regular `let'.
-
-Conses and lists:
-
- (a) - bind `car' of cons/list to A
-
- (a . b) - bind car of cons to A and `cdr' to B
-
- (a b) - bind car of list to A and `cadr' to B
-
- (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ...
-
- (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST.
-
-Vectors:
-
- [a] - bind 0th element of a non-list sequence to A (works with
- vectors, strings, bit arrays...)
-
- [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to
- A1, 2nd to A2, ...
- If the PATTERN is shorter than SOURCE, the values at
- places not in PATTERN are ignored.
- If the PATTERN is longer than SOURCE, an `error' is
- thrown.
-
- [a1 a2 a3 ... &rest rest] - as above, but bind the rest of
- the sequence to REST. This is
- conceptually the same as improper list
- matching (a1 a2 ... aN . rest)
-
-Key/value stores:
-
- (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE plist to aK. If the
- value is not found, aK is nil.
-
- (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE alist to aK. If the
- value is not found, aK is nil.
-
- (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the
- SOURCE hash table to aK. If the
- value is not found, aK is nil.
-
-Further, special keyword &keys supports \"inline\" matching of
-plist-like key-value pairs, similarly to &keys keyword of
-`cl-defun'.
-
- (a1 a2 ... aN &keys key1 b1 ... keyN bK)
-
-This binds N values from the list to a1 ... aN, then interprets
-the cdr as a plist (see key/value matching above).
-
-You can name the source using the syntax SYMBOL &as PATTERN.
-This syntax works with lists (proper or improper), vectors and
-all types of maps.
-
- (list &as a b c) (list 1 2 3)
-
-binds A to 1, B to 2, C to 3 and LIST to (1 2 3).
-
-Similarly:
-
- (bounds &as beg . end) (cons 1 2)
-
-binds BEG to 1, END to 2 and BOUNDS to (1 . 2).
-
- (items &as first . rest) (list 1 2 3)
-
-binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3)
-
- [vect &as _ b c] [1 2 3]
-
-binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual).
-
- (plist &as &plist :b b) (list :a 1 :b 2 :c 3)
-
-binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash.
-
-This is especially useful when we want to capture the result of a
-computation and destructure at the same time. Consider the
-form (function-returning-complex-structure) returning a list of
-two vectors with two items each. We want to capture this entire
-result and pass it to another computation, but at the same time
-we want to get the second item from each vector. We can achieve
-it with pattern
-
- (result &as [_ a] [_ b]) (function-returning-complex-structure)
-
-Note: Clojure programmers may know this feature as the \":as
-binding\". The difference is that we put the &as at the front
-because we need to support improper list binding."
- (declare (debug ([&or (&rest (sexp form))
- (vector [&rest [sexp form]])]
- body))
- (indent 1))
- (if (vectorp varlist)
- `(let* ,(dash--match (aref varlist 0) (aref varlist 1))
- ,@body)
- (let* ((inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist))
- (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs))))
- `(let ,inputs
- (-let* ,new-varlist ,@body)))))
-
-(defmacro -lambda (match-form &rest body)
- "Return a lambda which destructures its input as MATCH-FORM and executes BODY.
-
-Note that you have to enclose the MATCH-FORM in a pair of parens,
-such that:
-
- (-lambda (x) body)
- (-lambda (x y ...) body)
-
-has the usual semantics of `lambda'. Furthermore, these get
-translated into normal lambda, so there is no performance
-penalty.
-
-See `-let' for the description of destructuring mechanism."
- (declare (doc-string 2) (indent defun)
- (debug (&define sexp
- [&optional stringp]
- [&optional ("interactive" interactive)]
- def-body)))
- (cond
- ((not (consp match-form))
- (signal 'wrong-type-argument "match-form must be a list"))
- ;; no destructuring, so just return regular lambda to make things faster
- ((-all? 'symbolp match-form)
- `(lambda ,match-form ,@body))
- (t
- (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form)))
- ;; TODO: because inputs to the lambda are evaluated only once,
- ;; -let* need not to create the extra bindings to ensure that.
- ;; We should find a way to optimize that. Not critical however.
- `(lambda ,(--map (cadr it) inputs)
- (-let* ,inputs ,@body))))))
-
-(defmacro -if-let* (vars-vals then &rest else)
- "If all VALS evaluate to true, bind them to their corresponding
-VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list
-of (VAR VAL) pairs.
-
-Note: binding is done according to `-let*'. VALS are evaluated
-sequentially, and evaluation stops after the first nil VAL is
-encountered."
- (declare (debug ((&rest (sexp form)) form body))
- (indent 2))
- (->> vars-vals
- (--mapcat (dash--match (car it) (cadr it)))
- (--reduce-r-from
- (let ((var (car it))
- (val (cadr it)))
- `(let ((,var ,val))
- (if ,var ,acc ,@else)))
- then)))
-
-(defmacro -if-let (var-val then &rest else)
- "If VAL evaluates to non-nil, bind it to VAR and do THEN,
-otherwise do ELSE. VAR-VAL should be a (VAR VAL) pair.
-
-Note: binding is done according to `-let'."
- (declare (debug ((sexp form) form body))
- (indent 2))
- `(-if-let* (,var-val) ,then ,@else))
-
-(defmacro --if-let (val then &rest else)
- "If VAL evaluates to non-nil, bind it to `it' and do THEN,
-otherwise do ELSE."
- (declare (debug (form form body))
- (indent 2))
- `(-if-let (it ,val) ,then ,@else))
-
-(defmacro -when-let* (vars-vals &rest body)
- "If all VALS evaluate to true, bind them to their corresponding
-VARS and execute body. VARS-VALS should be a list of (VAR VAL)
-pairs.
-
-Note: binding is done according to `-let*'. VALS are evaluated
-sequentially, and evaluation stops after the first nil VAL is
-encountered."
- (declare (debug ((&rest (sexp form)) body))
- (indent 1))
- `(-if-let* ,vars-vals (progn ,@body)))
-
-(defmacro -when-let (var-val &rest body)
- "If VAL evaluates to non-nil, bind it to VAR and execute body.
-VAR-VAL should be a (VAR VAL) pair.
-
-Note: binding is done according to `-let'."
- (declare (debug ((sexp form) body))
- (indent 1))
- `(-if-let ,var-val (progn ,@body)))
-
-(defmacro --when-let (val &rest body)
- "If VAL evaluates to non-nil, bind it to `it' and execute
-body."
- (declare (debug (form body))
- (indent 1))
- `(--if-let ,val (progn ,@body)))
-
-(defvar -compare-fn nil
- "Tests for equality use this function or `equal' if this is nil.
-It should only be set using dynamic scope with a let, like:
-
- (let ((-compare-fn #'=)) (-union numbers1 numbers2 numbers3)")
-
-(defun -distinct (list)
- "Return a new list with all duplicates removed.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil.
-
-Alias: `-uniq'"
- (let (result)
- (--each list (unless (-contains? result it) (!cons it result)))
- (nreverse result)))
-
-(defalias '-uniq '-distinct)
-
-(defun -union (list list2)
- "Return a new list containing the elements of LIST1 and elements of LIST2 that are not in LIST1.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil."
- ;; We fall back to iteration implementation if the comparison
- ;; function isn't one of `eq', `eql' or `equal'.
- (let* ((result (reverse list))
- ;; TODO: get rid of this dynamic variable, pass it as an
- ;; argument instead.
- (-compare-fn (if (bound-and-true-p -compare-fn)
- -compare-fn
- 'equal)))
- (if (memq -compare-fn '(eq eql equal))
- (let ((ht (make-hash-table :test -compare-fn)))
- (--each list (puthash it t ht))
- (--each list2 (unless (gethash it ht) (!cons it result))))
- (--each list2 (unless (-contains? result it) (!cons it result))))
- (nreverse result)))
-
-(defun -intersection (list list2)
- "Return a new list containing only the elements that are members of both LIST and LIST2.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil."
- (--filter (-contains? list2 it) list))
-
-(defun -difference (list list2)
- "Return a new list with only the members of LIST that are not in LIST2.
-The test for equality is done with `equal',
-or with `-compare-fn' if that's non-nil."
- (--filter (not (-contains? list2 it)) list))
-
-(defun -contains? (list element)
- "Return non-nil if LIST contains ELEMENT.
-
-The test for equality is done with `equal', or with `-compare-fn'
-if that's non-nil.
-
-Alias: `-contains-p'"
- (not
- (null
- (cond
- ((null -compare-fn) (member element list))
- ((eq -compare-fn 'eq) (memq element list))
- ((eq -compare-fn 'eql) (memql element list))
- (t
- (let ((lst list))
- (while (and lst
- (not (funcall -compare-fn element (car lst))))
- (setq lst (cdr lst)))
- lst))))))
-
-(defalias '-contains-p '-contains?)
-
-(defun -same-items? (list list2)
- "Return true if LIST and LIST2 has the same items.
-
-The order of the elements in the lists does not matter.
-
-Alias: `-same-items-p'"
- (let ((length-a (length list))
- (length-b (length list2)))
- (and
- (= length-a length-b)
- (= length-a (length (-intersection list list2))))))
-
-(defalias '-same-items-p '-same-items?)
-
-(defun -is-prefix? (prefix list)
- "Return non-nil if PREFIX is prefix of LIST.
-
-Alias: `-is-prefix-p'"
- (--each-while list (equal (car prefix) it)
- (!cdr prefix))
- (not prefix))
-
-(defun -is-suffix? (suffix list)
- "Return non-nil if SUFFIX is suffix of LIST.
-
-Alias: `-is-suffix-p'"
- (-is-prefix? (reverse suffix) (reverse list)))
-
-(defun -is-infix? (infix list)
- "Return non-nil if INFIX is infix of LIST.
-
-This operation runs in O(n^2) time
-
-Alias: `-is-infix-p'"
- (let (done)
- (while (and (not done) list)
- (setq done (-is-prefix? infix list))
- (!cdr list))
- done))
-
-(defalias '-is-prefix-p '-is-prefix?)
-(defalias '-is-suffix-p '-is-suffix?)
-(defalias '-is-infix-p '-is-infix?)
-
-(defun -sort (comparator list)
- "Sort LIST, stably, comparing elements using COMPARATOR.
-Return the sorted list. LIST is NOT modified by side effects.
-COMPARATOR is called with two elements of LIST, and should return non-nil
-if the first element should sort before the second."
- (sort (copy-sequence list) comparator))
-
-(defmacro --sort (form list)
- "Anaphoric form of `-sort'."
- (declare (debug (form form)))
- `(-sort (lambda (it other) ,form) ,list))
-
-(defun -list (&rest args)
- "Return a list with ARGS.
-
-If first item of ARGS is already a list, simply return ARGS. If
-not, return a list with ARGS as elements."
- (let ((arg (car args)))
- (if (listp arg) arg args)))
-
-(defun -repeat (n x)
- "Return a list with X repeated N times.
-Return nil if N is less than 1."
- (let (ret)
- (--dotimes n (!cons x ret))
- ret))
-
-(defun -sum (list)
- "Return the sum of LIST."
- (apply '+ list))
-
-(defun -product (list)
- "Return the product of LIST."
- (apply '* list))
-
-(defun -max (list)
- "Return the largest value from LIST of numbers or markers."
- (apply 'max list))
-
-(defun -min (list)
- "Return the smallest value from LIST of numbers or markers."
- (apply 'min list))
-
-(defun -max-by (comparator list)
- "Take a comparison function COMPARATOR and a LIST and return
-the greatest element of the list by the comparison function.
-
-See also combinator `-on' which can transform the values before
-comparing them."
- (--reduce (if (funcall comparator it acc) it acc) list))
-
-(defun -min-by (comparator list)
- "Take a comparison function COMPARATOR and a LIST and return
-the least element of the list by the comparison function.
-
-See also combinator `-on' which can transform the values before
-comparing them."
- (--reduce (if (funcall comparator it acc) acc it) list))
-
-(defmacro --max-by (form list)
- "Anaphoric version of `-max-by'.
-
-The items for the comparator form are exposed as \"it\" and \"other\"."
- (declare (debug (form form)))
- `(-max-by (lambda (it other) ,form) ,list))
-
-(defmacro --min-by (form list)
- "Anaphoric version of `-min-by'.
-
-The items for the comparator form are exposed as \"it\" and \"other\"."
- (declare (debug (form form)))
- `(-min-by (lambda (it other) ,form) ,list))
-
-(defun -iterate (fun init n)
- "Return a list of iterated applications of FUN to INIT.
-
-This means a list of form:
-
- (init (fun init) (fun (fun init)) ...)
-
-N is the length of the returned list."
- (if (= n 0) nil
- (let ((r (list init)))
- (--dotimes (1- n)
- (push (funcall fun (car r)) r))
- (nreverse r))))
-
-(defun -fix (fn list)
- "Compute the (least) fixpoint of FN with initial input LIST.
-
-FN is called at least once, results are compared with `equal'."
- (let ((re (funcall fn list)))
- (while (not (equal list re))
- (setq list re)
- (setq re (funcall fn re)))
- re))
-
-(defmacro --fix (form list)
- "Anaphoric form of `-fix'."
- `(-fix (lambda (it) ,form) ,list))
-
-(defun -unfold (fun seed)
- "Build a list from SEED using FUN.
-
-This is \"dual\" operation to `-reduce-r': while -reduce-r
-consumes a list to produce a single value, `-unfold' takes a
-seed value and builds a (potentially infinite!) list.
-
-FUN should return `nil' to stop the generating process, or a
-cons (A . B), where A will be prepended to the result and B is
-the new seed."
- (let ((last (funcall fun seed)) r)
- (while last
- (push (car last) r)
- (setq last (funcall fun (cdr last))))
- (nreverse r)))
-
-(defmacro --unfold (form seed)
- "Anaphoric version of `-unfold'."
- (declare (debug (form form)))
- `(-unfold (lambda (it) ,form) ,seed))
-
-(defun -cons-pair? (con)
- "Return non-nil if CON is true cons pair.
-That is (A . B) where B is not a list."
- (and (listp con)
- (not (listp (cdr con)))))
-
-(defun -cons-to-list (con)
- "Convert a cons pair to a list with `car' and `cdr' of the pair respectively."
- (list (car con) (cdr con)))
-
-(defun -value-to-list (val)
- "Convert a value to a list.
-
-If the value is a cons pair, make a list with two elements, `car'
-and `cdr' of the pair respectively.
-
-If the value is anything else, wrap it in a list."
- (cond
- ((-cons-pair? val) (-cons-to-list val))
- (t (list val))))
-
-(defun -tree-mapreduce-from (fn folder init-value tree)
- "Apply FN to each element of TREE, and make a list of the results.
-If elements of TREE are lists themselves, apply FN recursively to
-elements of these nested lists.
-
-Then reduce the resulting lists using FOLDER and initial value
-INIT-VALUE. See `-reduce-r-from'.
-
-This is the same as calling `-tree-reduce-from' after `-tree-map'
-but is twice as fast as it only traverse the structure once."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) (funcall fn tree))
- ((listp tree)
- (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree)))
- (t (funcall fn tree))))
-
-(defmacro --tree-mapreduce-from (form folder init-value tree)
- "Anaphoric form of `-tree-mapreduce-from'."
- (declare (debug (form form form form)))
- `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree))
-
-(defun -tree-mapreduce (fn folder tree)
- "Apply FN to each element of TREE, and make a list of the results.
-If elements of TREE are lists themselves, apply FN recursively to
-elements of these nested lists.
-
-Then reduce the resulting lists using FOLDER and initial value
-INIT-VALUE. See `-reduce-r-from'.
-
-This is the same as calling `-tree-reduce' after `-tree-map'
-but is twice as fast as it only traverse the structure once."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) (funcall fn tree))
- ((listp tree)
- (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree)))
- (t (funcall fn tree))))
-
-(defmacro --tree-mapreduce (form folder tree)
- "Anaphoric form of `-tree-mapreduce'."
- (declare (debug (form form form)))
- `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree))
-
-(defun -tree-map (fn tree)
- "Apply FN to each element of TREE while preserving the tree structure."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) (funcall fn tree))
- ((listp tree)
- (mapcar (lambda (x) (-tree-map fn x)) tree))
- (t (funcall fn tree))))
-
-(defmacro --tree-map (form tree)
- "Anaphoric form of `-tree-map'."
- (declare (debug (form form)))
- `(-tree-map (lambda (it) ,form) ,tree))
-
-(defun -tree-reduce-from (fn init-value tree)
- "Use FN to reduce elements of list TREE.
-If elements of TREE are lists themselves, apply the reduction recursively.
-
-FN is first applied to INIT-VALUE and first element of the list,
-then on this result and second element from the list etc.
-
-The initial value is ignored on cons pairs as they always contain
-two elements."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) tree)
- ((listp tree)
- (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree)))
- (t tree)))
-
-(defmacro --tree-reduce-from (form init-value tree)
- "Anaphoric form of `-tree-reduce-from'."
- (declare (debug (form form form)))
- `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree))
-
-(defun -tree-reduce (fn tree)
- "Use FN to reduce elements of list TREE.
-If elements of TREE are lists themselves, apply the reduction recursively.
-
-FN is first applied to first element of the list and second
-element, then on this result and third element from the list etc.
-
-See `-reduce-r' for how exactly are lists of zero or one element handled."
- (cond
- ((not tree) nil)
- ((-cons-pair? tree) tree)
- ((listp tree)
- (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree)))
- (t tree)))
-
-(defmacro --tree-reduce (form tree)
- "Anaphoric form of `-tree-reduce'."
- (declare (debug (form form)))
- `(-tree-reduce (lambda (it acc) ,form) ,tree))
-
-(defun -tree-map-nodes (pred fun tree)
- "Call FUN on each node of TREE that satisfies PRED.
-
-If PRED returns nil, continue descending down this node. If PRED
-returns non-nil, apply FUN to this node and do not descend
-further."
- (if (funcall pred tree)
- (funcall fun tree)
- (if (and (listp tree)
- (not (-cons-pair? tree)))
- (-map (lambda (x) (-tree-map-nodes pred fun x)) tree)
- tree)))
-
-(defmacro --tree-map-nodes (pred form tree)
- "Anaphoric form of `-tree-map-nodes'."
- `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree))
-
-(defun -tree-seq (branch children tree)
- "Return a sequence of the nodes in TREE, in depth-first search order.
-
-BRANCH is a predicate of one argument that returns non-nil if the
-passed argument is a branch, that is, a node that can have children.
-
-CHILDREN is a function of one argument that returns the children
-of the passed branch node.
-
-Non-branch nodes are simply copied."
- (cons tree
- (when (funcall branch tree)
- (-mapcat (lambda (x) (-tree-seq branch children x))
- (funcall children tree)))))
-
-(defmacro --tree-seq (branch children tree)
- "Anaphoric form of `-tree-seq'."
- `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree))
-
-(defun -clone (list)
- "Create a deep copy of LIST.
-The new list has the same elements and structure but all cons are
-replaced with new ones. This is useful when you need to clone a
-structure such as plist or alist."
- (-tree-map 'identity list))
-
-(defun dash-enable-font-lock ()
- "Add syntax highlighting to dash functions, macros and magic values."
- (eval-after-load "lisp-mode"
- '(progn
- (let ((new-keywords '(
- "-each"
- "--each"
- "-each-while"
- "--each-while"
- "-dotimes"
- "--dotimes"
- "-map"
- "--map"
- "-reduce-from"
- "--reduce-from"
- "-reduce"
- "--reduce"
- "-reduce-r-from"
- "--reduce-r-from"
- "-reduce-r"
- "--reduce-r"
- "-filter"
- "--filter"
- "-select"
- "--select"
- "-remove"
- "--remove"
- "-reject"
- "--reject"
- "-remove-first"
- "--remove-first"
- "-reject-first"
- "--reject-first"
- "-remove-last"
- "--remove-last"
- "-reject-last"
- "--reject-last"
- "-remove-item"
- "-non-nil"
- "-keep"
- "--keep"
- "-map-indexed"
- "--map-indexed"
- "-splice"
- "--splice"
- "-splice-list"
- "--splice-list"
- "-map-when"
- "--map-when"
- "-replace-where"
- "--replace-where"
- "-map-first"
- "--map-first"
- "-map-last"
- "--map-last"
- "-replace"
- "-replace-first"
- "-replace-last"
- "-flatten"
- "-flatten-n"
- "-concat"
- "-mapcat"
- "--mapcat"
- "-copy"
- "-cons*"
- "-snoc"
- "-first"
- "--first"
- "-find"
- "--find"
- "-some"
- "--some"
- "-any"
- "--any"
- "-last"
- "--last"
- "-first-item"
- "-last-item"
- "-butlast"
- "-count"
- "--count"
- "-any?"
- "--any?"
- "-some?"
- "--some?"
- "-any-p"
- "--any-p"
- "-some-p"
- "--some-p"
- "-all?"
- "--all?"
- "-every?"
- "--every?"
- "-all-p"
- "--all-p"
- "-every-p"
- "--every-p"
- "-none?"
- "--none?"
- "-none-p"
- "--none-p"
- "-only-some?"
- "--only-some?"
- "-only-some-p"
- "--only-some-p"
- "-slice"
- "-take"
- "-drop"
- "-take-while"
- "--take-while"
- "-drop-while"
- "--drop-while"
- "-split-at"
- "-rotate"
- "-insert-at"
- "-replace-at"
- "-update-at"
- "--update-at"
- "-remove-at"
- "-remove-at-indices"
- "-split-with"
- "--split-with"
- "-split-on"
- "-split-when"
- "--split-when"
- "-separate"
- "--separate"
- "-partition-all-in-steps"
- "-partition-in-steps"
- "-partition-all"
- "-partition"
- "-partition-by"
- "--partition-by"
- "-partition-by-header"
- "--partition-by-header"
- "-group-by"
- "--group-by"
- "-interpose"
- "-interleave"
- "-zip-with"
- "--zip-with"
- "-zip"
- "-zip-fill"
- "-cycle"
- "-pad"
- "-annotate"
- "--annotate"
- "-table"
- "-table-flat"
- "-partial"
- "-elem-index"
- "-elem-indices"
- "-find-indices"
- "--find-indices"
- "-find-index"
- "--find-index"
- "-find-last-index"
- "--find-last-index"
- "-select-by-indices"
- "-grade-up"
- "-grade-down"
- "->"
- "->>"
- "-->"
- "-when-let"
- "-when-let*"
- "--when-let"
- "-if-let"
- "-if-let*"
- "--if-let"
- "-let*"
- "-let"
- "-lambda"
- "-distinct"
- "-uniq"
- "-union"
- "-intersection"
- "-difference"
- "-contains?"
- "-contains-p"
- "-same-items?"
- "-same-items-p"
- "-is-prefix-p"
- "-is-prefix?"
- "-is-suffix-p"
- "-is-suffix?"
- "-is-infix-p"
- "-is-infix?"
- "-sort"
- "--sort"
- "-list"
- "-repeat"
- "-sum"
- "-product"
- "-max"
- "-min"
- "-max-by"
- "--max-by"
- "-min-by"
- "--min-by"
- "-iterate"
- "--iterate"
- "-fix"
- "--fix"
- "-unfold"
- "--unfold"
- "-cons-pair?"
- "-cons-to-list"
- "-value-to-list"
- "-tree-mapreduce-from"
- "--tree-mapreduce-from"
- "-tree-mapreduce"
- "--tree-mapreduce"
- "-tree-map"
- "--tree-map"
- "-tree-reduce-from"
- "--tree-reduce-from"
- "-tree-reduce"
- "--tree-reduce"
- "-tree-seq"
- "--tree-seq"
- "-tree-map-nodes"
- "--tree-map-nodes"
- "-clone"
- "-rpartial"
- "-juxt"
- "-applify"
- "-on"
- "-flip"
- "-const"
- "-cut"
- "-orfn"
- "-andfn"
- "-iteratefn"
- "-fixfn"
- "-prodfn"
- ))
- (special-variables '(
- "it"
- "it-index"
- "acc"
- "other"
- )))
- (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\_<" (regexp-opt special-variables 'paren) "\\_>")
- 1 font-lock-variable-name-face)) 'append)
- (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\_>")
- 1 font-lock-keyword-face)) 'append))
- (--each (buffer-list)
- (with-current-buffer it
- (when (and (eq major-mode 'emacs-lisp-mode)
- (boundp 'font-lock-mode)
- font-lock-mode)
- (font-lock-refresh-defaults)))))))
-
-(provide 'dash)
-;;; dash.el ends here
--- /dev/null
+;;; dash-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+\f
+;;;### (autoloads nil nil ("dash.el") (22576 8238 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; dash-autoloads.el ends here
--- /dev/null
+;;; -*- no-byte-compile: t -*-
+(define-package "dash" "20161116.920" "A modern list library for Emacs" 'nil :keywords '("lists"))
--- /dev/null
+;;; dash.el --- A modern list library for Emacs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012-2016 Free Software Foundation, Inc.
+
+;; Author: Magnar Sveen <magnarsNOSPAMgmail.com>
+;; Version: 2.13.0
+;; Package-Version: 20161116.920
+;; Keywords: lists
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; A modern list api for Emacs.
+;;
+;; See documentation on https://github.com/magnars/dash.el#functions
+;;
+;; **Please note** The lexical binding in this file is not utilised at the
+;; moment. We will take full advantage of lexical binding in an upcoming 3.0
+;; release of Dash. In the meantime, we've added the pragma to avoid a bug that
+;; you can read more about in https://github.com/magnars/dash.el/issues/130.
+;;
+
+;;; Code:
+
+(defgroup dash ()
+ "Customize group for dash.el"
+ :group 'lisp
+ :prefix "dash-")
+
+(defun dash--enable-fontlock (symbol value)
+ (when value
+ (dash-enable-font-lock))
+ (set-default symbol value))
+
+(defcustom dash-enable-fontlock nil
+ "If non-nil, enable fontification of dash functions, macros and
+special values."
+ :type 'boolean
+ :set 'dash--enable-fontlock
+ :group 'dash)
+
+(defmacro !cons (car cdr)
+ "Destructive: Set CDR to the cons of CAR and CDR."
+ `(setq ,cdr (cons ,car ,cdr)))
+
+(defmacro !cdr (list)
+ "Destructive: Set LIST to the cdr of LIST."
+ `(setq ,list (cdr ,list)))
+
+(defmacro --each (list &rest body)
+ "Anaphoric form of `-each'."
+ (declare (debug (form body))
+ (indent 1))
+ (let ((l (make-symbol "list")))
+ `(let ((,l ,list)
+ (it-index 0))
+ (while ,l
+ (let ((it (car ,l)))
+ ,@body)
+ (setq it-index (1+ it-index))
+ (!cdr ,l)))))
+
+(defmacro -doto (eval-initial-value &rest forms)
+ "Eval a form, then insert that form as the 2nd argument to other forms.
+The EVAL-INITIAL-VALUE form is evaluated once. Its result is
+passed to FORMS, which are then evaluated sequentially. Returns
+the target form."
+ (declare (indent 1))
+ (let ((retval (make-symbol "value")))
+ `(let ((,retval ,eval-initial-value))
+ ,@(mapcar (lambda (form)
+ (if (sequencep form)
+ `(,(-first-item form) ,retval ,@(cdr form))
+ `(funcall form ,retval)))
+ forms)
+ ,retval)))
+
+(defun -each (list fn)
+ "Call FN with every item in LIST. Return nil, used for side-effects only."
+ (--each list (funcall fn it)))
+
+(put '-each 'lisp-indent-function 1)
+
+(defalias '--each-indexed '--each)
+
+(defun -each-indexed (list fn)
+ "Call (FN index item) for each item in LIST.
+
+In the anaphoric form `--each-indexed', the index is exposed as `it-index`.
+
+See also: `-map-indexed'."
+ (--each list (funcall fn it-index it)))
+(put '-each-indexed 'lisp-indent-function 1)
+
+(defmacro --each-while (list pred &rest body)
+ "Anaphoric form of `-each-while'."
+ (declare (debug (form form body))
+ (indent 2))
+ (let ((l (make-symbol "list"))
+ (c (make-symbol "continue")))
+ `(let ((,l ,list)
+ (,c t)
+ (it-index 0))
+ (while (and ,l ,c)
+ (let ((it (car ,l)))
+ (if (not ,pred) (setq ,c nil) ,@body))
+ (setq it-index (1+ it-index))
+ (!cdr ,l)))))
+
+(defun -each-while (list pred fn)
+ "Call FN with every item in LIST while (PRED item) is non-nil.
+Return nil, used for side-effects only."
+ (--each-while list (funcall pred it) (funcall fn it)))
+
+(put '-each-while 'lisp-indent-function 2)
+
+(defmacro --dotimes (num &rest body)
+ "Repeatedly executes BODY (presumably for side-effects) with `it` bound to integers from 0 through NUM-1."
+ (declare (debug (form body))
+ (indent 1))
+ (let ((n (make-symbol "num")))
+ `(let ((,n ,num)
+ (it 0))
+ (while (< it ,n)
+ ,@body
+ (setq it (1+ it))))))
+
+(defun -dotimes (num fn)
+ "Repeatedly calls FN (presumably for side-effects) passing in integers from 0 through NUM-1."
+ (--dotimes num (funcall fn it)))
+
+(put '-dotimes 'lisp-indent-function 1)
+
+(defun -map (fn list)
+ "Return a new list consisting of the result of applying FN to the items in LIST."
+ (mapcar fn list))
+
+(defmacro --map (form list)
+ "Anaphoric form of `-map'."
+ (declare (debug (form form)))
+ `(mapcar (lambda (it) ,form) ,list))
+
+(defmacro --reduce-from (form initial-value list)
+ "Anaphoric form of `-reduce-from'."
+ (declare (debug (form form form)))
+ `(let ((acc ,initial-value))
+ (--each ,list (setq acc ,form))
+ acc))
+
+(defun -reduce-from (fn initial-value list)
+ "Return the result of applying FN to INITIAL-VALUE and the
+first item in LIST, then applying FN to that result and the 2nd
+item, etc. If LIST contains no items, return INITIAL-VALUE and
+FN is not called.
+
+In the anaphoric form `--reduce-from', the accumulated value is
+exposed as `acc`.
+
+See also: `-reduce', `-reduce-r'"
+ (--reduce-from (funcall fn acc it) initial-value list))
+
+(defmacro --reduce (form list)
+ "Anaphoric form of `-reduce'."
+ (declare (debug (form form)))
+ (let ((lv (make-symbol "list-value")))
+ `(let ((,lv ,list))
+ (if ,lv
+ (--reduce-from ,form (car ,lv) (cdr ,lv))
+ (let (acc it) ,form)))))
+
+(defun -reduce (fn list)
+ "Return the result of applying FN to the first 2 items in LIST,
+then applying FN to that result and the 3rd item, etc. If LIST
+contains no items, FN must accept no arguments as well, and
+reduce return the result of calling FN with no arguments. If
+LIST has only 1 item, it is returned and FN is not called.
+
+In the anaphoric form `--reduce', the accumulated value is
+exposed as `acc`.
+
+See also: `-reduce-from', `-reduce-r'"
+ (if list
+ (-reduce-from fn (car list) (cdr list))
+ (funcall fn)))
+
+(defun -reduce-r-from (fn initial-value list)
+ "Replace conses with FN, nil with INITIAL-VALUE and evaluate
+the resulting expression. If LIST is empty, INITIAL-VALUE is
+returned and FN is not called.
+
+Note: this function works the same as `-reduce-from' but the
+operation associates from right instead of from left.
+
+See also: `-reduce-r', `-reduce'"
+ (if (not list) initial-value
+ (funcall fn (car list) (-reduce-r-from fn initial-value (cdr list)))))
+
+(defmacro --reduce-r-from (form initial-value list)
+ "Anaphoric version of `-reduce-r-from'."
+ (declare (debug (form form form)))
+ `(-reduce-r-from (lambda (&optional it acc) ,form) ,initial-value ,list))
+
+(defun -reduce-r (fn list)
+ "Replace conses with FN and evaluate the resulting expression.
+The final nil is ignored. If LIST contains no items, FN must
+accept no arguments as well, and reduce return the result of
+calling FN with no arguments. If LIST has only 1 item, it is
+returned and FN is not called.
+
+The first argument of FN is the new item, the second is the
+accumulated value.
+
+Note: this function works the same as `-reduce' but the operation
+associates from right instead of from left.
+
+See also: `-reduce-r-from', `-reduce'"
+ (cond
+ ((not list) (funcall fn))
+ ((not (cdr list)) (car list))
+ (t (funcall fn (car list) (-reduce-r fn (cdr list))))))
+
+(defmacro --reduce-r (form list)
+ "Anaphoric version of `-reduce-r'."
+ (declare (debug (form form)))
+ `(-reduce-r (lambda (&optional it acc) ,form) ,list))
+
+(defmacro --filter (form list)
+ "Anaphoric form of `-filter'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each ,list (when ,form (!cons it ,r)))
+ (nreverse ,r))))
+
+(defun -filter (pred list)
+ "Return a new list of the items in LIST for which PRED returns a non-nil value.
+
+Alias: `-select'
+
+See also: `-keep'"
+ (--filter (funcall pred it) list))
+
+(defalias '-select '-filter)
+(defalias '--select '--filter)
+
+(defmacro --remove (form list)
+ "Anaphoric form of `-remove'."
+ (declare (debug (form form)))
+ `(--filter (not ,form) ,list))
+
+(defun -remove (pred list)
+ "Return a new list of the items in LIST for which PRED returns nil.
+
+Alias: `-reject'"
+ (--remove (funcall pred it) list))
+
+(defalias '-reject '-remove)
+(defalias '--reject '--remove)
+
+(defun -remove-first (pred list)
+ "Return a new list with the first item matching PRED removed.
+
+Alias: `-reject-first'
+
+See also: `-remove', `-map-first'"
+ (let (front)
+ (while (and list (not (funcall pred (car list))))
+ (push (car list) front)
+ (!cdr list))
+ (if list
+ (-concat (nreverse front) (cdr list))
+ (nreverse front))))
+
+(defmacro --remove-first (form list)
+ "Anaphoric form of `-remove-first'."
+ (declare (debug (form form)))
+ `(-remove-first (lambda (it) ,form) ,list))
+
+(defalias '-reject-first '-remove-first)
+(defalias '--reject-first '--remove-first)
+
+(defun -remove-last (pred list)
+ "Return a new list with the last item matching PRED removed.
+
+Alias: `-reject-last'
+
+See also: `-remove', `-map-last'"
+ (nreverse (-remove-first pred (reverse list))))
+
+(defmacro --remove-last (form list)
+ "Anaphoric form of `-remove-last'."
+ (declare (debug (form form)))
+ `(-remove-last (lambda (it) ,form) ,list))
+
+(defalias '-reject-last '-remove-last)
+(defalias '--reject-last '--remove-last)
+
+(defun -remove-item (item list)
+ "Remove all occurences of ITEM from LIST.
+
+Comparison is done with `equal'."
+ (declare (pure t) (side-effect-free t))
+ (--remove (equal it item) list))
+
+(defmacro --keep (form list)
+ "Anaphoric form of `-keep'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result"))
+ (m (make-symbol "mapped")))
+ `(let (,r)
+ (--each ,list (let ((,m ,form)) (when ,m (!cons ,m ,r))))
+ (nreverse ,r))))
+
+(defun -keep (fn list)
+ "Return a new list of the non-nil results of applying FN to the items in LIST.
+
+If you want to select the original items satisfying a predicate use `-filter'."
+ (--keep (funcall fn it) list))
+
+(defun -non-nil (list)
+ "Return all non-nil elements of LIST."
+ (declare (pure t) (side-effect-free t))
+ (-remove 'null list))
+
+(defmacro --map-indexed (form list)
+ "Anaphoric form of `-map-indexed'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each ,list
+ (!cons ,form ,r))
+ (nreverse ,r))))
+
+(defun -map-indexed (fn list)
+ "Return a new list consisting of the result of (FN index item) for each item in LIST.
+
+In the anaphoric form `--map-indexed', the index is exposed as `it-index`.
+
+See also: `-each-indexed'."
+ (--map-indexed (funcall fn it-index it) list))
+
+(defmacro --map-when (pred rep list)
+ "Anaphoric form of `-map-when'."
+ (declare (debug (form form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each ,list (!cons (if ,pred ,rep it) ,r))
+ (nreverse ,r))))
+
+(defun -map-when (pred rep list)
+ "Return a new list where the elements in LIST that do not match the PRED function
+are unchanged, and where the elements in LIST that do match the PRED function are mapped
+through the REP function.
+
+Alias: `-replace-where'
+
+See also: `-update-at'"
+ (--map-when (funcall pred it) (funcall rep it) list))
+
+(defalias '-replace-where '-map-when)
+(defalias '--replace-where '--map-when)
+
+(defun -map-first (pred rep list)
+ "Replace first item in LIST satisfying PRED with result of REP called on this item.
+
+See also: `-map-when', `-replace-first'"
+ (let (front)
+ (while (and list (not (funcall pred (car list))))
+ (push (car list) front)
+ (!cdr list))
+ (if list
+ (-concat (nreverse front) (cons (funcall rep (car list)) (cdr list)))
+ (nreverse front))))
+
+(defmacro --map-first (pred rep list)
+ "Anaphoric form of `-map-first'."
+ `(-map-first (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
+
+(defun -map-last (pred rep list)
+ "Replace first item in LIST satisfying PRED with result of REP called on this item.
+
+See also: `-map-when', `-replace-last'"
+ (nreverse (-map-first pred rep (reverse list))))
+
+(defmacro --map-last (pred rep list)
+ "Anaphoric form of `-map-last'."
+ `(-map-last (lambda (it) ,pred) (lambda (it) (ignore it) ,rep) ,list))
+
+(defun -replace (old new list)
+ "Replace all OLD items in LIST with NEW.
+
+Elements are compared using `equal'.
+
+See also: `-replace-at'"
+ (declare (pure t) (side-effect-free t))
+ (--map-when (equal it old) new list))
+
+(defun -replace-first (old new list)
+ "Replace the first occurence of OLD with NEW in LIST.
+
+Elements are compared using `equal'.
+
+See also: `-map-first'"
+ (declare (pure t) (side-effect-free t))
+ (--map-first (equal old it) new list))
+
+(defun -replace-last (old new list)
+ "Replace the last occurence of OLD with NEW in LIST.
+
+Elements are compared using `equal'.
+
+See also: `-map-last'"
+ (declare (pure t) (side-effect-free t))
+ (--map-last (equal old it) new list))
+
+(defmacro --mapcat (form list)
+ "Anaphoric form of `-mapcat'."
+ (declare (debug (form form)))
+ `(apply 'append (--map ,form ,list)))
+
+(defun -mapcat (fn list)
+ "Return the concatenation of the result of mapping FN over LIST.
+Thus function FN should return a list."
+ (--mapcat (funcall fn it) list))
+
+(defun -flatten (l)
+ "Take a nested list L and return its contents as a single, flat list.
+
+Note that because `nil' represents a list of zero elements (an
+empty list), any mention of nil in L will disappear after
+flattening. If you need to preserve nils, consider `-flatten-n'
+or map them to some unique symbol and then map them back.
+
+Conses of two atoms are considered \"terminals\", that is, they
+aren't flattened further.
+
+See also: `-flatten-n'"
+ (declare (pure t) (side-effect-free t))
+ (if (and (listp l) (listp (cdr l)))
+ (-mapcat '-flatten l)
+ (list l)))
+
+(defmacro --iterate (form init n)
+ "Anaphoric version of `-iterate'."
+ (declare (debug (form form form)))
+ `(-iterate (lambda (it) ,form) ,init ,n))
+
+(defun -flatten-n (num list)
+ "Flatten NUM levels of a nested LIST.
+
+See also: `-flatten'"
+ (declare (pure t) (side-effect-free t))
+ (-last-item (--iterate (--mapcat (-list it) it) list (1+ num))))
+
+(defun -concat (&rest lists)
+ "Return a new list with the concatenation of the elements in the supplied LISTS."
+ (declare (pure t) (side-effect-free t))
+ (apply 'append lists))
+
+(defalias '-copy 'copy-sequence
+ "Create a shallow copy of LIST.
+
+\(fn LIST)")
+
+(defun -splice (pred fun list)
+ "Splice lists generated by FUN in place of elements matching PRED in LIST.
+
+FUN takes the element matching PRED as input.
+
+This function can be used as replacement for `,@' in case you
+need to splice several lists at marked positions (for example
+with keywords).
+
+See also: `-splice-list', `-insert-at'"
+ (let (r)
+ (--each list
+ (if (funcall pred it)
+ (let ((new (funcall fun it)))
+ (--each new (!cons it r)))
+ (!cons it r)))
+ (nreverse r)))
+
+(defmacro --splice (pred form list)
+ "Anaphoric form of `-splice'."
+ `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list))
+
+(defun -splice-list (pred new-list list)
+ "Splice NEW-LIST in place of elements matching PRED in LIST.
+
+See also: `-splice', `-insert-at'"
+ (-splice pred (lambda (_) new-list) list))
+
+(defmacro --splice-list (pred new-list list)
+ "Anaphoric form of `-splice-list'."
+ `(-splice-list (lambda (it) ,pred) ,new-list ,list))
+
+(defun -cons* (&rest args)
+ "Make a new list from the elements of ARGS.
+
+The last 2 members of ARGS are used as the final cons of the
+result so if the final member of ARGS is not a list the result is
+a dotted list."
+ (declare (pure t) (side-effect-free t))
+ (-reduce-r 'cons args))
+
+(defun -snoc (list elem &rest elements)
+ "Append ELEM to the end of the list.
+
+This is like `cons', but operates on the end of list.
+
+If ELEMENTS is non nil, append these to the list as well."
+ (-concat list (list elem) elements))
+
+(defmacro --first (form list)
+ "Anaphoric form of `-first'."
+ (declare (debug (form form)))
+ (let ((n (make-symbol "needle")))
+ `(let (,n)
+ (--each-while ,list (not ,n)
+ (when ,form (setq ,n it)))
+ ,n)))
+
+(defun -first (pred list)
+ "Return the first x in LIST where (PRED x) is non-nil, else nil.
+
+To get the first item in the list no questions asked, use `car'.
+
+Alias: `-find'"
+ (--first (funcall pred it) list))
+
+(defalias '-find '-first)
+(defalias '--find '--first)
+
+(defmacro --some (form list)
+ "Anaphoric form of `-some'."
+ (declare (debug (form form)))
+ (let ((n (make-symbol "needle")))
+ `(let (,n)
+ (--each-while ,list (not ,n)
+ (setq ,n ,form))
+ ,n)))
+
+(defun -some (pred list)
+ "Return (PRED x) for the first LIST item where (PRED x) is non-nil, else nil.
+
+Alias: `-any'"
+ (--some (funcall pred it) list))
+
+(defalias '-any '-some)
+(defalias '--any '--some)
+
+(defmacro --last (form list)
+ "Anaphoric form of `-last'."
+ (declare (debug (form form)))
+ (let ((n (make-symbol "needle")))
+ `(let (,n)
+ (--each ,list
+ (when ,form (setq ,n it)))
+ ,n)))
+
+(defun -last (pred list)
+ "Return the last x in LIST where (PRED x) is non-nil, else nil."
+ (--last (funcall pred it) list))
+
+(defalias '-first-item 'car
+ "Return the first item of LIST, or nil on an empty list.
+
+\(fn LIST)")
+
+(gv-define-simple-setter -first-item setcar)
+
+(defun -last-item (list)
+ "Return the last item of LIST, or nil on an empty list."
+ (declare (pure t) (side-effect-free t))
+ (car (last list)))
+
+(gv-define-setter -last-item (val x) `(setcar (last ,x) ,val))
+
+(defun -butlast (list)
+ "Return a list of all items in list except for the last."
+ ;; no alias as we don't want magic optional argument
+ (declare (pure t) (side-effect-free t))
+ (butlast list))
+
+(defmacro --count (pred list)
+ "Anaphoric form of `-count'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let ((,r 0))
+ (--each ,list (when ,pred (setq ,r (1+ ,r))))
+ ,r)))
+
+(defun -count (pred list)
+ "Counts the number of items in LIST where (PRED item) is non-nil."
+ (--count (funcall pred it) list))
+
+(defun ---truthy? (val)
+ (declare (pure t) (side-effect-free t))
+ (not (null val)))
+
+(defmacro --any? (form list)
+ "Anaphoric form of `-any?'."
+ (declare (debug (form form)))
+ `(---truthy? (--first ,form ,list)))
+
+(defun -any? (pred list)
+ "Return t if (PRED x) is non-nil for any x in LIST, else nil.
+
+Alias: `-any-p', `-some?', `-some-p'"
+ (--any? (funcall pred it) list))
+
+(defalias '-some? '-any?)
+(defalias '--some? '--any?)
+(defalias '-any-p '-any?)
+(defalias '--any-p '--any?)
+(defalias '-some-p '-any?)
+(defalias '--some-p '--any?)
+
+(defmacro --all? (form list)
+ "Anaphoric form of `-all?'."
+ (declare (debug (form form)))
+ (let ((a (make-symbol "all")))
+ `(let ((,a t))
+ (--each-while ,list ,a (setq ,a ,form))
+ (---truthy? ,a))))
+
+(defun -all? (pred list)
+ "Return t if (PRED x) is non-nil for all x in LIST, else nil.
+
+Alias: `-all-p', `-every?', `-every-p'"
+ (--all? (funcall pred it) list))
+
+(defalias '-every? '-all?)
+(defalias '--every? '--all?)
+(defalias '-all-p '-all?)
+(defalias '--all-p '--all?)
+(defalias '-every-p '-all?)
+(defalias '--every-p '--all?)
+
+(defmacro --none? (form list)
+ "Anaphoric form of `-none?'."
+ (declare (debug (form form)))
+ `(--all? (not ,form) ,list))
+
+(defun -none? (pred list)
+ "Return t if (PRED x) is nil for all x in LIST, else nil.
+
+Alias: `-none-p'"
+ (--none? (funcall pred it) list))
+
+(defalias '-none-p '-none?)
+(defalias '--none-p '--none?)
+
+(defmacro --only-some? (form list)
+ "Anaphoric form of `-only-some?'."
+ (declare (debug (form form)))
+ (let ((y (make-symbol "yes"))
+ (n (make-symbol "no")))
+ `(let (,y ,n)
+ (--each-while ,list (not (and ,y ,n))
+ (if ,form (setq ,y t) (setq ,n t)))
+ (---truthy? (and ,y ,n)))))
+
+(defun -only-some? (pred list)
+ "Return `t` if at least one item of LIST matches PRED and at least one item of LIST does not match PRED.
+Return `nil` both if all items match the predicate or if none of the items match the predicate.
+
+Alias: `-only-some-p'"
+ (--only-some? (funcall pred it) list))
+
+(defalias '-only-some-p '-only-some?)
+(defalias '--only-some-p '--only-some?)
+
+(defun -slice (list from &optional to step)
+ "Return copy of LIST, starting from index FROM to index TO.
+
+FROM or TO may be negative. These values are then interpreted
+modulo the length of the list.
+
+If STEP is a number, only each STEPth item in the resulting
+section is returned. Defaults to 1."
+ (declare (pure t) (side-effect-free t))
+ (let ((length (length list))
+ (new-list nil))
+ ;; to defaults to the end of the list
+ (setq to (or to length))
+ (setq step (or step 1))
+ ;; handle negative indices
+ (when (< from 0)
+ (setq from (mod from length)))
+ (when (< to 0)
+ (setq to (mod to length)))
+
+ ;; iterate through the list, keeping the elements we want
+ (--each-while list (< it-index to)
+ (when (and (>= it-index from)
+ (= (mod (- from it-index) step) 0))
+ (push it new-list)))
+ (nreverse new-list)))
+
+(defun -take (n list)
+ "Return a new list of the first N items in LIST, or all items if there are fewer than N.
+
+See also: `-take-last'"
+ (declare (pure t) (side-effect-free t))
+ (let (result)
+ (--dotimes n
+ (when list
+ (!cons (car list) result)
+ (!cdr list)))
+ (nreverse result)))
+
+(defun -take-last (n list)
+ "Return the last N items of LIST in order.
+
+See also: `-take'"
+ (declare (pure t) (side-effect-free t))
+ (copy-sequence (last list n)))
+
+(defalias '-drop 'nthcdr
+ "Return the tail of LIST without the first N items.
+
+See also: `-drop-last'
+
+\(fn N LIST)")
+
+(defun -drop-last (n list)
+ "Remove the last N items of LIST and return a copy.
+
+See also: `-drop'"
+ ;; No alias because we don't want magic optional argument
+ (declare (pure t) (side-effect-free t))
+ (butlast list n))
+
+(defmacro --take-while (form list)
+ "Anaphoric form of `-take-while'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result")))
+ `(let (,r)
+ (--each-while ,list ,form (!cons it ,r))
+ (nreverse ,r))))
+
+(defun -take-while (pred list)
+ "Return a new list of successive items from LIST while (PRED item) returns a non-nil value."
+ (--take-while (funcall pred it) list))
+
+(defmacro --drop-while (form list)
+ "Anaphoric form of `-drop-while'."
+ (declare (debug (form form)))
+ (let ((l (make-symbol "list")))
+ `(let ((,l ,list))
+ (while (and ,l (let ((it (car ,l))) ,form))
+ (!cdr ,l))
+ ,l)))
+
+(defun -drop-while (pred list)
+ "Return the tail of LIST starting from the first item for which (PRED item) returns nil."
+ (--drop-while (funcall pred it) list))
+
+(defun -split-at (n list)
+ "Return a list of ((-take N LIST) (-drop N LIST)), in no more than one pass through the list."
+ (declare (pure t) (side-effect-free t))
+ (let (result)
+ (--dotimes n
+ (when list
+ (!cons (car list) result)
+ (!cdr list)))
+ (list (nreverse result) list)))
+
+(defun -rotate (n list)
+ "Rotate LIST N places to the right. With N negative, rotate to the left.
+The time complexity is O(n)."
+ (declare (pure t) (side-effect-free t))
+ (if (> n 0)
+ (append (last list n) (butlast list n))
+ (append (-drop (- n) list) (-take (- n) list))))
+
+(defun -insert-at (n x list)
+ "Return a list with X inserted into LIST at position N.
+
+See also: `-splice', `-splice-list'"
+ (declare (pure t) (side-effect-free t))
+ (let ((split-list (-split-at n list)))
+ (nconc (car split-list) (cons x (cadr split-list)))))
+
+(defun -replace-at (n x list)
+ "Return a list with element at Nth position in LIST replaced with X.
+
+See also: `-replace'"
+ (declare (pure t) (side-effect-free t))
+ (let ((split-list (-split-at n list)))
+ (nconc (car split-list) (cons x (cdr (cadr split-list))))))
+
+(defun -update-at (n func list)
+ "Return a list with element at Nth position in LIST replaced with `(func (nth n list))`.
+
+See also: `-map-when'"
+ (let ((split-list (-split-at n list)))
+ (nconc (car split-list) (cons (funcall func (car (cadr split-list))) (cdr (cadr split-list))))))
+
+(defmacro --update-at (n form list)
+ "Anaphoric version of `-update-at'."
+ (declare (debug (form form form)))
+ `(-update-at ,n (lambda (it) ,form) ,list))
+
+(defun -remove-at (n list)
+ "Return a list with element at Nth position in LIST removed.
+
+See also: `-remove-at-indices', `-remove'"
+ (declare (pure t) (side-effect-free t))
+ (-remove-at-indices (list n) list))
+
+(defun -remove-at-indices (indices list)
+ "Return a list whose elements are elements from LIST without
+elements selected as `(nth i list)` for all i
+from INDICES.
+
+See also: `-remove-at', `-remove'"
+ (declare (pure t) (side-effect-free t))
+ (let* ((indices (-sort '< indices))
+ (diffs (cons (car indices) (-map '1- (-zip-with '- (cdr indices) indices))))
+ r)
+ (--each diffs
+ (let ((split (-split-at it list)))
+ (!cons (car split) r)
+ (setq list (cdr (cadr split)))))
+ (!cons list r)
+ (apply '-concat (nreverse r))))
+
+(defmacro --split-with (pred list)
+ "Anaphoric form of `-split-with'."
+ (declare (debug (form form)))
+ (let ((l (make-symbol "list"))
+ (r (make-symbol "result"))
+ (c (make-symbol "continue")))
+ `(let ((,l ,list)
+ (,r nil)
+ (,c t))
+ (while (and ,l ,c)
+ (let ((it (car ,l)))
+ (if (not ,pred)
+ (setq ,c nil)
+ (!cons it ,r)
+ (!cdr ,l))))
+ (list (nreverse ,r) ,l))))
+
+(defun -split-with (pred list)
+ "Return a list of ((-take-while PRED LIST) (-drop-while PRED LIST)), in no more than one pass through the list."
+ (--split-with (funcall pred it) list))
+
+(defmacro -split-on (item list)
+ "Split the LIST each time ITEM is found.
+
+Unlike `-partition-by', the ITEM is discarded from the results.
+Empty lists are also removed from the result.
+
+Comparison is done by `equal'.
+
+See also `-split-when'"
+ (declare (debug (form form)))
+ `(-split-when (lambda (it) (equal it ,item)) ,list))
+
+(defmacro --split-when (form list)
+ "Anaphoric version of `-split-when'."
+ (declare (debug (form form)))
+ `(-split-when (lambda (it) ,form) ,list))
+
+(defun -split-when (fn list)
+ "Split the LIST on each element where FN returns non-nil.
+
+Unlike `-partition-by', the \"matched\" element is discarded from
+the results. Empty lists are also removed from the result.
+
+This function can be thought of as a generalization of
+`split-string'."
+ (let (r s)
+ (while list
+ (if (not (funcall fn (car list)))
+ (push (car list) s)
+ (when s (push (nreverse s) r))
+ (setq s nil))
+ (!cdr list))
+ (when s (push (nreverse s) r))
+ (nreverse r)))
+
+(defmacro --separate (form list)
+ "Anaphoric form of `-separate'."
+ (declare (debug (form form)))
+ (let ((y (make-symbol "yes"))
+ (n (make-symbol "no")))
+ `(let (,y ,n)
+ (--each ,list (if ,form (!cons it ,y) (!cons it ,n)))
+ (list (nreverse ,y) (nreverse ,n)))))
+
+(defun -separate (pred list)
+ "Return a list of ((-filter PRED LIST) (-remove PRED LIST)), in one pass through the list."
+ (--separate (funcall pred it) list))
+
+(defun ---partition-all-in-steps-reversed (n step list)
+ "Private: Used by -partition-all-in-steps and -partition-in-steps."
+ (when (< step 1)
+ (error "Step must be a positive number, or you're looking at some juicy infinite loops."))
+ (let ((result nil))
+ (while list
+ (!cons (-take n list) result)
+ (setq list (-drop step list)))
+ result))
+
+(defun -partition-all-in-steps (n step list)
+ "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
+The last groups may contain less than N items."
+ (declare (pure t) (side-effect-free t))
+ (nreverse (---partition-all-in-steps-reversed n step list)))
+
+(defun -partition-in-steps (n step list)
+ "Return a new list with the items in LIST grouped into N-sized sublists at offsets STEP apart.
+If there are not enough items to make the last group N-sized,
+those items are discarded."
+ (declare (pure t) (side-effect-free t))
+ (let ((result (---partition-all-in-steps-reversed n step list)))
+ (while (and result (< (length (car result)) n))
+ (!cdr result))
+ (nreverse result)))
+
+(defun -partition-all (n list)
+ "Return a new list with the items in LIST grouped into N-sized sublists.
+The last group may contain less than N items."
+ (declare (pure t) (side-effect-free t))
+ (-partition-all-in-steps n n list))
+
+(defun -partition (n list)
+ "Return a new list with the items in LIST grouped into N-sized sublists.
+If there are not enough items to make the last group N-sized,
+those items are discarded."
+ (declare (pure t) (side-effect-free t))
+ (-partition-in-steps n n list))
+
+(defmacro --partition-by (form list)
+ "Anaphoric form of `-partition-by'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result"))
+ (s (make-symbol "sublist"))
+ (v (make-symbol "value"))
+ (n (make-symbol "new-value"))
+ (l (make-symbol "list")))
+ `(let ((,l ,list))
+ (when ,l
+ (let* ((,r nil)
+ (it (car ,l))
+ (,s (list it))
+ (,v ,form)
+ (,l (cdr ,l)))
+ (while ,l
+ (let* ((it (car ,l))
+ (,n ,form))
+ (unless (equal ,v ,n)
+ (!cons (nreverse ,s) ,r)
+ (setq ,s nil)
+ (setq ,v ,n))
+ (!cons it ,s)
+ (!cdr ,l)))
+ (!cons (nreverse ,s) ,r)
+ (nreverse ,r))))))
+
+(defun -partition-by (fn list)
+ "Apply FN to each item in LIST, splitting it each time FN returns a new value."
+ (--partition-by (funcall fn it) list))
+
+(defmacro --partition-by-header (form list)
+ "Anaphoric form of `-partition-by-header'."
+ (declare (debug (form form)))
+ (let ((r (make-symbol "result"))
+ (s (make-symbol "sublist"))
+ (h (make-symbol "header-value"))
+ (b (make-symbol "seen-body?"))
+ (n (make-symbol "new-value"))
+ (l (make-symbol "list")))
+ `(let ((,l ,list))
+ (when ,l
+ (let* ((,r nil)
+ (it (car ,l))
+ (,s (list it))
+ (,h ,form)
+ (,b nil)
+ (,l (cdr ,l)))
+ (while ,l
+ (let* ((it (car ,l))
+ (,n ,form))
+ (if (equal ,h ,n)
+ (when ,b
+ (!cons (nreverse ,s) ,r)
+ (setq ,s nil)
+ (setq ,b nil))
+ (setq ,b t))
+ (!cons it ,s)
+ (!cdr ,l)))
+ (!cons (nreverse ,s) ,r)
+ (nreverse ,r))))))
+
+(defun -partition-by-header (fn list)
+ "Apply FN to the first item in LIST. That is the header
+value. Apply FN to each item in LIST, splitting it each time FN
+returns the header value, but only after seeing at least one
+other value (the body)."
+ (--partition-by-header (funcall fn it) list))
+
+(defmacro --group-by (form list)
+ "Anaphoric form of `-group-by'."
+ (declare (debug t))
+ (let ((n (make-symbol "n"))
+ (k (make-symbol "k"))
+ (grp (make-symbol "grp")))
+ `(nreverse
+ (-map
+ (lambda (,n)
+ (cons (car ,n)
+ (nreverse (cdr ,n))))
+ (--reduce-from
+ (let* ((,k (,@form))
+ (,grp (assoc ,k acc)))
+ (if ,grp
+ (setcdr ,grp (cons it (cdr ,grp)))
+ (push
+ (list ,k it)
+ acc))
+ acc)
+ nil ,list)))))
+
+(defun -group-by (fn list)
+ "Separate LIST into an alist whose keys are FN applied to the
+elements of LIST. Keys are compared by `equal'."
+ (--group-by (funcall fn it) list))
+
+(defun -interpose (sep list)
+ "Return a new list of all elements in LIST separated by SEP."
+ (declare (pure t) (side-effect-free t))
+ (let (result)
+ (when list
+ (!cons (car list) result)
+ (!cdr list))
+ (while list
+ (setq result (cons (car list) (cons sep result)))
+ (!cdr list))
+ (nreverse result)))
+
+(defun -interleave (&rest lists)
+ "Return a new list of the first item in each list, then the second etc."
+ (declare (pure t) (side-effect-free t))
+ (let (result)
+ (while (-none? 'null lists)
+ (--each lists (!cons (car it) result))
+ (setq lists (-map 'cdr lists)))
+ (nreverse result)))
+
+(defmacro --zip-with (form list1 list2)
+ "Anaphoric form of `-zip-with'.
+
+The elements in list1 is bound as `it`, the elements in list2 as `other`."
+ (declare (debug (form form form)))
+ (let ((r (make-symbol "result"))
+ (l1 (make-symbol "list1"))
+ (l2 (make-symbol "list2")))
+ `(let ((,r nil)
+ (,l1 ,list1)
+ (,l2 ,list2))
+ (while (and ,l1 ,l2)
+ (let ((it (car ,l1))
+ (other (car ,l2)))
+ (!cons ,form ,r)
+ (!cdr ,l1)
+ (!cdr ,l2)))
+ (nreverse ,r))))
+
+(defun -zip-with (fn list1 list2)
+ "Zip the two lists LIST1 and LIST2 using a function FN. This
+function is applied pairwise taking as first argument element of
+LIST1 and as second argument element of LIST2 at corresponding
+position.
+
+The anaphoric form `--zip-with' binds the elements from LIST1 as `it`,
+and the elements from LIST2 as `other`."
+ (--zip-with (funcall fn it other) list1 list2))
+
+(defun -zip (&rest lists)
+ "Zip LISTS together. Group the head of each list, followed by the
+second elements of each list, and so on. The lengths of the returned
+groupings are equal to the length of the shortest input list.
+
+If two lists are provided as arguments, return the groupings as a list
+of cons cells. Otherwise, return the groupings as a list of lists.
+
+Please note! This distinction is being removed in an upcoming 3.0
+release of Dash. If you rely on this behavior, use -zip-pair instead."
+ (declare (pure t) (side-effect-free t))
+ (let (results)
+ (while (-none? 'null lists)
+ (setq results (cons (mapcar 'car lists) results))
+ (setq lists (mapcar 'cdr lists)))
+ (setq results (nreverse results))
+ (if (= (length lists) 2)
+ ;; to support backward compatability, return
+ ;; a cons cell if two lists were provided
+ (--map (cons (car it) (cadr it)) results)
+ results)))
+
+(defalias '-zip-pair '-zip)
+
+(defun -zip-fill (fill-value &rest lists)
+ "Zip LISTS, with FILL-VALUE padded onto the shorter lists. The
+lengths of the returned groupings are equal to the length of the
+longest input list."
+ (declare (pure t) (side-effect-free t))
+ (apply '-zip (apply '-pad (cons fill-value lists))))
+
+(defun -unzip (lists)
+ "Unzip LISTS.
+
+This works just like `-zip' but takes a list of lists instead of
+a variable number of arguments, such that
+
+ (-unzip (-zip L1 L2 L3 ...))
+
+is identity (given that the lists are the same length).
+
+See also: `-zip'"
+ (apply '-zip lists))
+
+(defun -cycle (list)
+ "Return an infinite copy of LIST that will cycle through the
+elements and repeat from the beginning."
+ (declare (pure t) (side-effect-free t))
+ (let ((newlist (-map 'identity list)))
+ (nconc newlist newlist)))
+
+(defun -pad (fill-value &rest lists)
+ "Appends FILL-VALUE to the end of each list in LISTS such that they
+will all have the same length."
+ (let* ((annotations (-annotate 'length lists))
+ (n (-max (-map 'car annotations))))
+ (--map (append (cdr it) (-repeat (- n (car it)) fill-value)) annotations)))
+
+(defun -annotate (fn list)
+ "Return a list of cons cells where each cell is FN applied to each
+element of LIST paired with the unmodified element of LIST."
+ (-zip (-map fn list) list))
+
+(defmacro --annotate (form list)
+ "Anaphoric version of `-annotate'."
+ (declare (debug (form form)))
+ `(-annotate (lambda (it) ,form) ,list))
+
+(defun dash--table-carry (lists restore-lists &optional re)
+ "Helper for `-table' and `-table-flat'.
+
+If a list overflows, carry to the right and reset the list."
+ (while (not (or (car lists)
+ (equal lists '(nil))))
+ (setcar lists (car restore-lists))
+ (pop (cadr lists))
+ (!cdr lists)
+ (!cdr restore-lists)
+ (when re
+ (push (nreverse (car re)) (cadr re))
+ (setcar re nil)
+ (!cdr re))))
+
+(defun -table (fn &rest lists)
+ "Compute outer product of LISTS using function FN.
+
+The function FN should have the same arity as the number of
+supplied lists.
+
+The outer product is computed by applying fn to all possible
+combinations created by taking one element from each list in
+order. The dimension of the result is (length lists).
+
+See also: `-table-flat'"
+ (let ((restore-lists (copy-sequence lists))
+ (last-list (last lists))
+ (re (make-list (length lists) nil)))
+ (while (car last-list)
+ (let ((item (apply fn (-map 'car lists))))
+ (push item (car re))
+ (setcar lists (cdar lists)) ;; silence byte compiler
+ (dash--table-carry lists restore-lists re)))
+ (nreverse (car (last re)))))
+
+(defun -table-flat (fn &rest lists)
+ "Compute flat outer product of LISTS using function FN.
+
+The function FN should have the same arity as the number of
+supplied lists.
+
+The outer product is computed by applying fn to all possible
+combinations created by taking one element from each list in
+order. The results are flattened, ignoring the tensor structure
+of the result. This is equivalent to calling:
+
+ (-flatten-n (1- (length lists)) (apply '-table fn lists))
+
+but the implementation here is much more efficient.
+
+See also: `-flatten-n', `-table'"
+ (let ((restore-lists (copy-sequence lists))
+ (last-list (last lists))
+ re)
+ (while (car last-list)
+ (let ((item (apply fn (-map 'car lists))))
+ (push item re)
+ (setcar lists (cdar lists)) ;; silence byte compiler
+ (dash--table-carry lists restore-lists)))
+ (nreverse re)))
+
+(defun -partial (fn &rest args)
+ "Take a function FN and fewer than the normal arguments to FN,
+and return a fn that takes a variable number of additional ARGS.
+When called, the returned function calls FN with ARGS first and
+then additional args."
+ (apply 'apply-partially fn args))
+
+(defun -elem-index (elem list)
+ "Return the index of the first element in the given LIST which
+is equal to the query element ELEM, or nil if there is no
+such element."
+ (declare (pure t) (side-effect-free t))
+ (car (-elem-indices elem list)))
+
+(defun -elem-indices (elem list)
+ "Return the indices of all elements in LIST equal to the query
+element ELEM, in ascending order."
+ (declare (pure t) (side-effect-free t))
+ (-find-indices (-partial 'equal elem) list))
+
+(defun -find-indices (pred list)
+ "Return the indices of all elements in LIST satisfying the
+predicate PRED, in ascending order."
+ (apply 'append (--map-indexed (when (funcall pred it) (list it-index)) list)))
+
+(defmacro --find-indices (form list)
+ "Anaphoric version of `-find-indices'."
+ (declare (debug (form form)))
+ `(-find-indices (lambda (it) ,form) ,list))
+
+(defun -find-index (pred list)
+ "Take a predicate PRED and a LIST and return the index of the
+first element in the list satisfying the predicate, or nil if
+there is no such element.
+
+See also `-first'."
+ (car (-find-indices pred list)))
+
+(defmacro --find-index (form list)
+ "Anaphoric version of `-find-index'."
+ (declare (debug (form form)))
+ `(-find-index (lambda (it) ,form) ,list))
+
+(defun -find-last-index (pred list)
+ "Take a predicate PRED and a LIST and return the index of the
+last element in the list satisfying the predicate, or nil if
+there is no such element.
+
+See also `-last'."
+ (-last-item (-find-indices pred list)))
+
+(defmacro --find-last-index (form list)
+ "Anaphoric version of `-find-last-index'."
+ `(-find-last-index (lambda (it) ,form) ,list))
+
+(defun -select-by-indices (indices list)
+ "Return a list whose elements are elements from LIST selected
+as `(nth i list)` for all i from INDICES."
+ (declare (pure t) (side-effect-free t))
+ (let (r)
+ (--each indices
+ (!cons (nth it list) r))
+ (nreverse r)))
+
+(defun -select-columns (columns table)
+ "Select COLUMNS from TABLE.
+
+TABLE is a list of lists where each element represents one row.
+It is assumed each row has the same length.
+
+Each row is transformed such that only the specified COLUMNS are
+selected.
+
+See also: `-select-column', `-select-by-indices'"
+ (declare (pure t) (side-effect-free t))
+ (--map (-select-by-indices columns it) table))
+
+(defun -select-column (column table)
+ "Select COLUMN from TABLE.
+
+TABLE is a list of lists where each element represents one row.
+It is assumed each row has the same length.
+
+The single selected column is returned as a list.
+
+See also: `-select-columns', `-select-by-indices'"
+ (declare (pure t) (side-effect-free t))
+ (--mapcat (-select-by-indices (list column) it) table))
+
+(defmacro -> (x &optional form &rest more)
+ "Thread the expr through the forms. Insert X as the second item
+in the first form, making a list of it if it is not a list
+already. If there are more forms, insert the first form as the
+second item in second form, etc."
+ (declare (debug (form &rest [&or symbolp (sexp &rest form)])))
+ (cond
+ ((null form) x)
+ ((null more) (if (listp form)
+ `(,(car form) ,x ,@(cdr form))
+ (list form x)))
+ (:else `(-> (-> ,x ,form) ,@more))))
+
+(defmacro ->> (x &optional form &rest more)
+ "Thread the expr through the forms. Insert X as the last item
+in the first form, making a list of it if it is not a list
+already. If there are more forms, insert the first form as the
+last item in second form, etc."
+ (declare (debug ->))
+ (cond
+ ((null form) x)
+ ((null more) (if (listp form)
+ `(,@form ,x)
+ (list form x)))
+ (:else `(->> (->> ,x ,form) ,@more))))
+
+(defmacro --> (x form &rest more)
+ "Thread the expr through the forms. Insert X at the position
+signified by the token `it' in the first form. If there are more
+forms, insert the first form at the position signified by `it' in
+in second form, etc."
+ (declare (debug ->))
+ (if (null more)
+ (if (listp form)
+ (--map-when (eq it 'it) x form)
+ (list form x))
+ `(--> (--> ,x ,form) ,@more)))
+
+(defmacro -some-> (x &optional form &rest more)
+ "When expr is non-nil, thread it through the first form (via `->'),
+and when that result is non-nil, through the next form, etc."
+ (declare (debug ->))
+ (if (null form) x
+ (let ((result (make-symbol "result")))
+ `(-some-> (-when-let (,result ,x)
+ (-> ,result ,form))
+ ,@more))))
+
+(defmacro -some->> (x &optional form &rest more)
+ "When expr is non-nil, thread it through the first form (via `->>'),
+and when that result is non-nil, through the next form, etc."
+ (declare (debug ->))
+ (if (null form) x
+ (let ((result (make-symbol "result")))
+ `(-some->> (-when-let (,result ,x)
+ (->> ,result ,form))
+ ,@more))))
+
+(defmacro -some--> (x &optional form &rest more)
+ "When expr in non-nil, thread it through the first form (via `-->'),
+and when that result is non-nil, through the next form, etc."
+ (declare (debug ->))
+ (if (null form) x
+ (let ((result (make-symbol "result")))
+ `(-some--> (-when-let (,result ,x)
+ (--> ,result ,form))
+ ,@more))))
+
+(defun -grade-up (comparator list)
+ "Grade elements of LIST using COMPARATOR relation, yielding a
+permutation vector such that applying this permutation to LIST
+sorts it in ascending order."
+ ;; ugly hack to "fix" lack of lexical scope
+ (let ((comp `(lambda (it other) (funcall ',comparator (car it) (car other)))))
+ (->> (--map-indexed (cons it it-index) list)
+ (-sort comp)
+ (-map 'cdr))))
+
+(defun -grade-down (comparator list)
+ "Grade elements of LIST using COMPARATOR relation, yielding a
+permutation vector such that applying this permutation to LIST
+sorts it in descending order."
+ ;; ugly hack to "fix" lack of lexical scope
+ (let ((comp `(lambda (it other) (funcall ',comparator (car other) (car it)))))
+ (->> (--map-indexed (cons it it-index) list)
+ (-sort comp)
+ (-map 'cdr))))
+
+(defvar dash--source-counter 0
+ "Monotonic counter for generated symbols.")
+
+(defun dash--match-make-source-symbol ()
+ "Generate a new dash-source symbol.
+
+All returned symbols are guaranteed to be unique."
+ (prog1 (make-symbol (format "--dash-source-%d--" dash--source-counter))
+ (setq dash--source-counter (1+ dash--source-counter))))
+
+(defun dash--match-ignore-place-p (symbol)
+ "Return non-nil if SYMBOL is a symbol and starts with _."
+ (and (symbolp symbol)
+ (eq (aref (symbol-name symbol) 0) ?_)))
+
+(defun dash--match-cons-skip-cdr (skip-cdr source)
+ "Helper function generating idiomatic shifting code."
+ (cond
+ ((= skip-cdr 0)
+ `(pop ,source))
+ (t
+ `(prog1 ,(dash--match-cons-get-car skip-cdr source)
+ (setq ,source ,(dash--match-cons-get-cdr (1+ skip-cdr) source))))))
+
+(defun dash--match-cons-get-car (skip-cdr source)
+ "Helper function generating idiomatic code to get nth car."
+ (cond
+ ((= skip-cdr 0)
+ `(car ,source))
+ ((= skip-cdr 1)
+ `(cadr ,source))
+ (t
+ `(nth ,skip-cdr ,source))))
+
+(defun dash--match-cons-get-cdr (skip-cdr source)
+ "Helper function generating idiomatic code to get nth cdr."
+ (cond
+ ((= skip-cdr 0)
+ source)
+ ((= skip-cdr 1)
+ `(cdr ,source))
+ (t
+ `(nthcdr ,skip-cdr ,source))))
+
+(defun dash--match-cons (match-form source)
+ "Setup a cons matching environment and call the real matcher."
+ (let ((s (dash--match-make-source-symbol))
+ (n 0)
+ (m match-form))
+ (while (and (consp m)
+ (dash--match-ignore-place-p (car m)))
+ (setq n (1+ n)) (!cdr m))
+ (cond
+ ;; when we only have one pattern in the list, we don't have to
+ ;; create a temporary binding (--dash-source--) for the source
+ ;; and just use the input directly
+ ((and (consp m)
+ (not (cdr m)))
+ (dash--match (car m) (dash--match-cons-get-car n source)))
+ ;; handle other special types
+ ((> n 0)
+ (dash--match m (dash--match-cons-get-cdr n source)))
+ ;; this is the only entry-point for dash--match-cons-1, that's
+ ;; why we can't simply use the above branch, it would produce
+ ;; infinite recursion
+ (t
+ (cons (list s source) (dash--match-cons-1 match-form s))))))
+
+(defun dash--match-cons-1 (match-form source &optional props)
+ "Match MATCH-FORM against SOURCE.
+
+MATCH-FORM is a proper or improper list. Each element of
+MATCH-FORM is either a symbol, which gets bound to the respective
+value in source or another match form which gets destructured
+recursively.
+
+If the cdr of last cons cell in the list is `nil', matching stops
+there.
+
+SOURCE is a proper or improper list."
+ (let ((skip-cdr (or (plist-get props :skip-cdr) 0)))
+ (cond
+ ((consp match-form)
+ (cond
+ ((cdr match-form)
+ (cond
+ ((and (symbolp (car match-form))
+ (memq (car match-form) '(&keys &plist &alist &hash)))
+ (dash--match-kv match-form (dash--match-cons-get-cdr skip-cdr source)))
+ ((dash--match-ignore-place-p (car match-form))
+ (dash--match-cons-1 (cdr match-form) source
+ (plist-put props :skip-cdr (1+ skip-cdr))))
+ (t
+ (-concat (dash--match (car match-form) (dash--match-cons-skip-cdr skip-cdr source))
+ (dash--match-cons-1 (cdr match-form) source)))))
+ (t ;; Last matching place, no need for shift
+ (dash--match (car match-form) (dash--match-cons-get-car skip-cdr source)))))
+ ((eq match-form nil)
+ nil)
+ (t ;; Handle improper lists. Last matching place, no need for shift
+ (dash--match match-form (dash--match-cons-get-cdr skip-cdr source))))))
+
+(defun dash--vector-tail (seq start)
+ "Return the tail of SEQ starting at START."
+ (cond
+ ((vectorp seq)
+ (let* ((re-length (- (length seq) start))
+ (re (make-vector re-length 0)))
+ (--dotimes re-length (aset re it (aref seq (+ it start))))
+ re))
+ ((stringp seq)
+ (substring seq start))))
+
+(defun dash--match-vector (match-form source)
+ "Setup a vector matching environment and call the real matcher."
+ (let ((s (dash--match-make-source-symbol)))
+ (cond
+ ;; don't bind `s' if we only have one sub-pattern
+ ((= (length match-form) 1)
+ (dash--match (aref match-form 0) `(aref ,source 0)))
+ ;; if the source is a symbol, we don't need to re-bind it
+ ((symbolp source)
+ (dash--match-vector-1 match-form source))
+ ;; don't bind `s' if we only have one sub-pattern which is not ignored
+ ((let* ((ignored-places (mapcar 'dash--match-ignore-place-p match-form))
+ (ignored-places-n (length (-remove 'null ignored-places))))
+ (when (= ignored-places-n (1- (length match-form)))
+ (let ((n (-find-index 'null ignored-places)))
+ (dash--match (aref match-form n) `(aref ,source ,n))))))
+ (t
+ (cons (list s source) (dash--match-vector-1 match-form s))))))
+
+(defun dash--match-vector-1 (match-form source)
+ "Match MATCH-FORM against SOURCE.
+
+MATCH-FORM is a vector. Each element of MATCH-FORM is either a
+symbol, which gets bound to the respective value in source or
+another match form which gets destructured recursively.
+
+If second-from-last place in MATCH-FORM is the symbol &rest, the
+next element of the MATCH-FORM is matched against the tail of
+SOURCE, starting at index of the &rest symbol. This is
+conceptually the same as the (head . tail) match for improper
+lists, where dot plays the role of &rest.
+
+SOURCE is a vector.
+
+If the MATCH-FORM vector is shorter than SOURCE vector, only
+the (length MATCH-FORM) places are bound, the rest of the SOURCE
+is discarded."
+ (let ((i 0)
+ (l (length match-form))
+ (re))
+ (while (< i l)
+ (let ((m (aref match-form i)))
+ (push (cond
+ ((and (symbolp m)
+ (eq m '&rest))
+ (prog1 (dash--match
+ (aref match-form (1+ i))
+ `(dash--vector-tail ,source ,i))
+ (setq i l)))
+ ((and (symbolp m)
+ ;; do not match symbols starting with _
+ (not (eq (aref (symbol-name m) 0) ?_)))
+ (list (list m `(aref ,source ,i))))
+ ((not (symbolp m))
+ (dash--match m `(aref ,source ,i))))
+ re)
+ (setq i (1+ i))))
+ (-flatten-n 1 (nreverse re))))
+
+(defun dash--match-kv (match-form source)
+ "Setup a kv matching environment and call the real matcher.
+
+kv can be any key-value store, such as plist, alist or hash-table."
+ (let ((s (dash--match-make-source-symbol)))
+ (cond
+ ;; don't bind `s' if we only have one sub-pattern (&type key val)
+ ((= (length match-form) 3)
+ (dash--match-kv-1 (cdr match-form) source (car match-form)))
+ ;; if the source is a symbol, we don't need to re-bind it
+ ((symbolp source)
+ (dash--match-kv-1 (cdr match-form) source (car match-form)))
+ (t
+ (cons (list s source) (dash--match-kv-1 (cdr match-form) s (car match-form)))))))
+
+(defun dash--match-kv-1 (match-form source type)
+ "Match MATCH-FORM against SOURCE of type TYPE.
+
+MATCH-FORM is a proper list of the form (key1 place1 ... keyN
+placeN). Each placeK is either a symbol, which gets bound to the
+value of keyK retrieved from the key-value store, or another
+match form which gets destructured recursively.
+
+SOURCE is a key-value store of type TYPE, which can be a plist,
+an alist or a hash table.
+
+TYPE is a token specifying the type of the key-value store.
+Valid values are &plist, &alist and &hash."
+ (-flatten-n 1 (-map
+ (lambda (kv)
+ (let* ((k (car kv))
+ (v (cadr kv))
+ (getter (cond
+ ((or (eq type '&plist) (eq type '&keys))
+ `(plist-get ,source ,k))
+ ((eq type '&alist)
+ `(cdr (assoc ,k ,source)))
+ ((eq type '&hash)
+ `(gethash ,k ,source)))))
+ (cond
+ ((symbolp v)
+ (list (list v getter)))
+ (t (dash--match v getter)))))
+ (-partition 2 match-form))))
+
+(defun dash--match-symbol (match-form source)
+ "Bind a symbol.
+
+This works just like `let', there is no destructuring."
+ (list (list match-form source)))
+
+(defun dash--match (match-form source)
+ "Match MATCH-FORM against SOURCE.
+
+This function tests the MATCH-FORM and dispatches to specific
+matchers based on the type of the expression.
+
+Key-value stores are disambiguated by placing a token &plist,
+&alist or &hash as a first item in the MATCH-FORM."
+ (cond
+ ((symbolp match-form)
+ (dash--match-symbol match-form source))
+ ((consp match-form)
+ (cond
+ ;; Handle the "x &as" bindings first.
+ ((and (consp (cdr match-form))
+ (symbolp (car match-form))
+ (eq '&as (cadr match-form)))
+ (let ((s (car match-form)))
+ (cons (list s source)
+ (dash--match (cddr match-form) s))))
+ ((memq (car match-form) '(&keys &plist &alist &hash))
+ (dash--match-kv match-form source))
+ (t (dash--match-cons match-form source))))
+ ((vectorp match-form)
+ ;; We support the &as binding in vectors too
+ (cond
+ ((and (> (length match-form) 2)
+ (symbolp (aref match-form 0))
+ (eq '&as (aref match-form 1)))
+ (let ((s (aref match-form 0)))
+ (cons (list s source)
+ (dash--match (dash--vector-tail match-form 2) s))))
+ (t (dash--match-vector match-form source))))))
+
+(defmacro -let* (varlist &rest body)
+ "Bind variables according to VARLIST then eval BODY.
+
+VARLIST is a list of lists of the form (PATTERN SOURCE). Each
+PATTERN is matched against the SOURCE structurally. SOURCE is
+only evaluated once for each PATTERN.
+
+Each SOURCE can refer to the symbols already bound by this
+VARLIST. This is useful if you want to destructure SOURCE
+recursively but also want to name the intermediate structures.
+
+See `-let' for the list of all possible patterns."
+ (declare (debug ((&rest (sexp form)) body))
+ (indent 1))
+ (let ((bindings (--mapcat (dash--match (car it) (cadr it)) varlist)))
+ `(let* ,bindings
+ ,@body)))
+
+(defmacro -let (varlist &rest body)
+ "Bind variables according to VARLIST then eval BODY.
+
+VARLIST is a list of lists of the form (PATTERN SOURCE). Each
+PATTERN is matched against the SOURCE \"structurally\". SOURCE
+is only evaluated once for each PATTERN. Each PATTERN is matched
+recursively, and can therefore contain sub-patterns which are
+matched against corresponding sub-expressions of SOURCE.
+
+All the SOURCEs are evalled before any symbols are
+bound (i.e. \"in parallel\").
+
+If VARLIST only contains one (PATTERN SOURCE) element, you can
+optionally specify it using a vector and discarding the
+outer-most parens. Thus
+
+ (-let ((PATTERN SOURCE)) ..)
+
+becomes
+
+ (-let [PATTERN SOURCE] ..).
+
+`-let' uses a convention of not binding places (symbols) starting
+with _ whenever it's possible. You can use this to skip over
+entries you don't care about. However, this is not *always*
+possible (as a result of implementation) and these symbols might
+get bound to undefined values.
+
+Following is the overview of supported patterns. Remember that
+patterns can be matched recursively, so every a, b, aK in the
+following can be a matching construct and not necessarily a
+symbol/variable.
+
+Symbol:
+
+ a - bind the SOURCE to A. This is just like regular `let'.
+
+Conses and lists:
+
+ (a) - bind `car' of cons/list to A
+
+ (a . b) - bind car of cons to A and `cdr' to B
+
+ (a b) - bind car of list to A and `cadr' to B
+
+ (a1 a2 a3 ...) - bind 0th car of list to A1, 1st to A2, 2nd to A3 ...
+
+ (a1 a2 a3 ... aN . rest) - as above, but bind the Nth cdr to REST.
+
+Vectors:
+
+ [a] - bind 0th element of a non-list sequence to A (works with
+ vectors, strings, bit arrays...)
+
+ [a1 a2 a3 ...] - bind 0th element of non-list sequence to A0, 1st to
+ A1, 2nd to A2, ...
+ If the PATTERN is shorter than SOURCE, the values at
+ places not in PATTERN are ignored.
+ If the PATTERN is longer than SOURCE, an `error' is
+ thrown.
+
+ [a1 a2 a3 ... &rest rest] - as above, but bind the rest of
+ the sequence to REST. This is
+ conceptually the same as improper list
+ matching (a1 a2 ... aN . rest)
+
+Key/value stores:
+
+ (&plist key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE plist to aK. If the
+ value is not found, aK is nil.
+
+ (&alist key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE alist to aK. If the
+ value is not found, aK is nil.
+
+ (&hash key0 a0 ... keyN aN) - bind value mapped by keyK in the
+ SOURCE hash table to aK. If the
+ value is not found, aK is nil.
+
+Further, special keyword &keys supports \"inline\" matching of
+plist-like key-value pairs, similarly to &keys keyword of
+`cl-defun'.
+
+ (a1 a2 ... aN &keys key1 b1 ... keyN bK)
+
+This binds N values from the list to a1 ... aN, then interprets
+the cdr as a plist (see key/value matching above).
+
+You can name the source using the syntax SYMBOL &as PATTERN.
+This syntax works with lists (proper or improper), vectors and
+all types of maps.
+
+ (list &as a b c) (list 1 2 3)
+
+binds A to 1, B to 2, C to 3 and LIST to (1 2 3).
+
+Similarly:
+
+ (bounds &as beg . end) (cons 1 2)
+
+binds BEG to 1, END to 2 and BOUNDS to (1 . 2).
+
+ (items &as first . rest) (list 1 2 3)
+
+binds FIRST to 1, REST to (2 3) and ITEMS to (1 2 3)
+
+ [vect &as _ b c] [1 2 3]
+
+binds B to 2, C to 3 and VECT to [1 2 3] (_ avoids binding as usual).
+
+ (plist &as &plist :b b) (list :a 1 :b 2 :c 3)
+
+binds B to 2 and PLIST to (:a 1 :b 2 :c 3). Same for &alist and &hash.
+
+This is especially useful when we want to capture the result of a
+computation and destructure at the same time. Consider the
+form (function-returning-complex-structure) returning a list of
+two vectors with two items each. We want to capture this entire
+result and pass it to another computation, but at the same time
+we want to get the second item from each vector. We can achieve
+it with pattern
+
+ (result &as [_ a] [_ b]) (function-returning-complex-structure)
+
+Note: Clojure programmers may know this feature as the \":as
+binding\". The difference is that we put the &as at the front
+because we need to support improper list binding."
+ (declare (debug ([&or (&rest (sexp form))
+ (vector [&rest [sexp form]])]
+ body))
+ (indent 1))
+ (if (vectorp varlist)
+ `(let* ,(dash--match (aref varlist 0) (aref varlist 1))
+ ,@body)
+ (let* ((inputs (--map-indexed (list (make-symbol (format "input%d" it-index)) (cadr it)) varlist))
+ (new-varlist (--map (list (caar it) (cadr it)) (-zip varlist inputs))))
+ `(let ,inputs
+ (-let* ,new-varlist ,@body)))))
+
+(defmacro -lambda (match-form &rest body)
+ "Return a lambda which destructures its input as MATCH-FORM and executes BODY.
+
+Note that you have to enclose the MATCH-FORM in a pair of parens,
+such that:
+
+ (-lambda (x) body)
+ (-lambda (x y ...) body)
+
+has the usual semantics of `lambda'. Furthermore, these get
+translated into normal lambda, so there is no performance
+penalty.
+
+See `-let' for the description of destructuring mechanism."
+ (declare (doc-string 2) (indent defun)
+ (debug (&define sexp
+ [&optional stringp]
+ [&optional ("interactive" interactive)]
+ def-body)))
+ (cond
+ ((not (consp match-form))
+ (signal 'wrong-type-argument "match-form must be a list"))
+ ;; no destructuring, so just return regular lambda to make things faster
+ ((-all? 'symbolp match-form)
+ `(lambda ,match-form ,@body))
+ (t
+ (let* ((inputs (--map-indexed (list it (make-symbol (format "input%d" it-index))) match-form)))
+ ;; TODO: because inputs to the lambda are evaluated only once,
+ ;; -let* need not to create the extra bindings to ensure that.
+ ;; We should find a way to optimize that. Not critical however.
+ `(lambda ,(--map (cadr it) inputs)
+ (-let* ,inputs ,@body))))))
+
+(defmacro -if-let* (vars-vals then &rest else)
+ "If all VALS evaluate to true, bind them to their corresponding
+VARS and do THEN, otherwise do ELSE. VARS-VALS should be a list
+of (VAR VAL) pairs.
+
+Note: binding is done according to `-let*'. VALS are evaluated
+sequentially, and evaluation stops after the first nil VAL is
+encountered."
+ (declare (debug ((&rest (sexp form)) form body))
+ (indent 2))
+ (->> vars-vals
+ (--mapcat (dash--match (car it) (cadr it)))
+ (--reduce-r-from
+ (let ((var (car it))
+ (val (cadr it)))
+ `(let ((,var ,val))
+ (if ,var ,acc ,@else)))
+ then)))
+
+(defmacro -if-let (var-val then &rest else)
+ "If VAL evaluates to non-nil, bind it to VAR and do THEN,
+otherwise do ELSE. VAR-VAL should be a (VAR VAL) pair.
+
+Note: binding is done according to `-let'."
+ (declare (debug ((sexp form) form body))
+ (indent 2))
+ `(-if-let* (,var-val) ,then ,@else))
+
+(defmacro --if-let (val then &rest else)
+ "If VAL evaluates to non-nil, bind it to `it' and do THEN,
+otherwise do ELSE."
+ (declare (debug (form form body))
+ (indent 2))
+ `(-if-let (it ,val) ,then ,@else))
+
+(defmacro -when-let* (vars-vals &rest body)
+ "If all VALS evaluate to true, bind them to their corresponding
+VARS and execute body. VARS-VALS should be a list of (VAR VAL)
+pairs.
+
+Note: binding is done according to `-let*'. VALS are evaluated
+sequentially, and evaluation stops after the first nil VAL is
+encountered."
+ (declare (debug ((&rest (sexp form)) body))
+ (indent 1))
+ `(-if-let* ,vars-vals (progn ,@body)))
+
+(defmacro -when-let (var-val &rest body)
+ "If VAL evaluates to non-nil, bind it to VAR and execute body.
+VAR-VAL should be a (VAR VAL) pair.
+
+Note: binding is done according to `-let'."
+ (declare (debug ((sexp form) body))
+ (indent 1))
+ `(-if-let ,var-val (progn ,@body)))
+
+(defmacro --when-let (val &rest body)
+ "If VAL evaluates to non-nil, bind it to `it' and execute
+body."
+ (declare (debug (form body))
+ (indent 1))
+ `(--if-let ,val (progn ,@body)))
+
+(defvar -compare-fn nil
+ "Tests for equality use this function or `equal' if this is nil.
+It should only be set using dynamic scope with a let, like:
+
+ (let ((-compare-fn #'=)) (-union numbers1 numbers2 numbers3)")
+
+(defun -distinct (list)
+ "Return a new list with all duplicates removed.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil.
+
+Alias: `-uniq'"
+ (let (result)
+ (--each list (unless (-contains? result it) (!cons it result)))
+ (nreverse result)))
+
+(defalias '-uniq '-distinct)
+
+(defun -union (list list2)
+ "Return a new list containing the elements of LIST and elements of LIST2 that are not in LIST.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil."
+ ;; We fall back to iteration implementation if the comparison
+ ;; function isn't one of `eq', `eql' or `equal'.
+ (let* ((result (reverse list))
+ ;; TODO: get rid of this dynamic variable, pass it as an
+ ;; argument instead.
+ (-compare-fn (if (bound-and-true-p -compare-fn)
+ -compare-fn
+ 'equal)))
+ (if (memq -compare-fn '(eq eql equal))
+ (let ((ht (make-hash-table :test -compare-fn)))
+ (--each list (puthash it t ht))
+ (--each list2 (unless (gethash it ht) (!cons it result))))
+ (--each list2 (unless (-contains? result it) (!cons it result))))
+ (nreverse result)))
+
+(defun -intersection (list list2)
+ "Return a new list containing only the elements that are members of both LIST and LIST2.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil."
+ (--filter (-contains? list2 it) list))
+
+(defun -difference (list list2)
+ "Return a new list with only the members of LIST that are not in LIST2.
+The test for equality is done with `equal',
+or with `-compare-fn' if that's non-nil."
+ (--filter (not (-contains? list2 it)) list))
+
+(defun -powerset (list)
+ "Return the power set of LIST."
+ (if (null list) '(())
+ (let ((last (-powerset (cdr list))))
+ (append (mapcar (lambda (x) (cons (car list) x)) last)
+ last))))
+
+(defun -permutations (list)
+ "Return the permutations of LIST."
+ (if (null list) '(())
+ (apply #'append
+ (mapcar (lambda (x)
+ (mapcar (lambda (perm) (cons x perm))
+ (-permutations (remove x list))))
+ list))))
+
+(defun -contains? (list element)
+ "Return non-nil if LIST contains ELEMENT.
+
+The test for equality is done with `equal', or with `-compare-fn'
+if that's non-nil.
+
+Alias: `-contains-p'"
+ (not
+ (null
+ (cond
+ ((null -compare-fn) (member element list))
+ ((eq -compare-fn 'eq) (memq element list))
+ ((eq -compare-fn 'eql) (memql element list))
+ (t
+ (let ((lst list))
+ (while (and lst
+ (not (funcall -compare-fn element (car lst))))
+ (setq lst (cdr lst)))
+ lst))))))
+
+(defalias '-contains-p '-contains?)
+
+(defun -same-items? (list list2)
+ "Return true if LIST and LIST2 has the same items.
+
+The order of the elements in the lists does not matter.
+
+Alias: `-same-items-p'"
+ (let ((length-a (length list))
+ (length-b (length list2)))
+ (and
+ (= length-a length-b)
+ (= length-a (length (-intersection list list2))))))
+
+(defalias '-same-items-p '-same-items?)
+
+(defun -is-prefix? (prefix list)
+ "Return non-nil if PREFIX is prefix of LIST.
+
+Alias: `-is-prefix-p'"
+ (declare (pure t) (side-effect-free t))
+ (--each-while list (equal (car prefix) it)
+ (!cdr prefix))
+ (not prefix))
+
+(defun -is-suffix? (suffix list)
+ "Return non-nil if SUFFIX is suffix of LIST.
+
+Alias: `-is-suffix-p'"
+ (declare (pure t) (side-effect-free t))
+ (-is-prefix? (reverse suffix) (reverse list)))
+
+(defun -is-infix? (infix list)
+ "Return non-nil if INFIX is infix of LIST.
+
+This operation runs in O(n^2) time
+
+Alias: `-is-infix-p'"
+ (declare (pure t) (side-effect-free t))
+ (let (done)
+ (while (and (not done) list)
+ (setq done (-is-prefix? infix list))
+ (!cdr list))
+ done))
+
+(defalias '-is-prefix-p '-is-prefix?)
+(defalias '-is-suffix-p '-is-suffix?)
+(defalias '-is-infix-p '-is-infix?)
+
+(defun -sort (comparator list)
+ "Sort LIST, stably, comparing elements using COMPARATOR.
+Return the sorted list. LIST is NOT modified by side effects.
+COMPARATOR is called with two elements of LIST, and should return non-nil
+if the first element should sort before the second."
+ (sort (copy-sequence list) comparator))
+
+(defmacro --sort (form list)
+ "Anaphoric form of `-sort'."
+ (declare (debug (form form)))
+ `(-sort (lambda (it other) ,form) ,list))
+
+(defun -list (&rest args)
+ "Return a list with ARGS.
+
+If first item of ARGS is already a list, simply return ARGS. If
+not, return a list with ARGS as elements."
+ (declare (pure t) (side-effect-free t))
+ (let ((arg (car args)))
+ (if (listp arg) arg args)))
+
+(defun -repeat (n x)
+ "Return a list with X repeated N times.
+Return nil if N is less than 1."
+ (declare (pure t) (side-effect-free t))
+ (let (ret)
+ (--dotimes n (!cons x ret))
+ ret))
+
+(defun -sum (list)
+ "Return the sum of LIST."
+ (declare (pure t) (side-effect-free t))
+ (apply '+ list))
+
+(defun -product (list)
+ "Return the product of LIST."
+ (declare (pure t) (side-effect-free t))
+ (apply '* list))
+
+(defun -max (list)
+ "Return the largest value from LIST of numbers or markers."
+ (declare (pure t) (side-effect-free t))
+ (apply 'max list))
+
+(defun -min (list)
+ "Return the smallest value from LIST of numbers or markers."
+ (declare (pure t) (side-effect-free t))
+ (apply 'min list))
+
+(defun -max-by (comparator list)
+ "Take a comparison function COMPARATOR and a LIST and return
+the greatest element of the list by the comparison function.
+
+See also combinator `-on' which can transform the values before
+comparing them."
+ (--reduce (if (funcall comparator it acc) it acc) list))
+
+(defun -min-by (comparator list)
+ "Take a comparison function COMPARATOR and a LIST and return
+the least element of the list by the comparison function.
+
+See also combinator `-on' which can transform the values before
+comparing them."
+ (--reduce (if (funcall comparator it acc) acc it) list))
+
+(defmacro --max-by (form list)
+ "Anaphoric version of `-max-by'.
+
+The items for the comparator form are exposed as \"it\" and \"other\"."
+ (declare (debug (form form)))
+ `(-max-by (lambda (it other) ,form) ,list))
+
+(defmacro --min-by (form list)
+ "Anaphoric version of `-min-by'.
+
+The items for the comparator form are exposed as \"it\" and \"other\"."
+ (declare (debug (form form)))
+ `(-min-by (lambda (it other) ,form) ,list))
+
+(defun -iterate (fun init n)
+ "Return a list of iterated applications of FUN to INIT.
+
+This means a list of form:
+
+ (init (fun init) (fun (fun init)) ...)
+
+N is the length of the returned list."
+ (if (= n 0) nil
+ (let ((r (list init)))
+ (--dotimes (1- n)
+ (push (funcall fun (car r)) r))
+ (nreverse r))))
+
+(defun -fix (fn list)
+ "Compute the (least) fixpoint of FN with initial input LIST.
+
+FN is called at least once, results are compared with `equal'."
+ (let ((re (funcall fn list)))
+ (while (not (equal list re))
+ (setq list re)
+ (setq re (funcall fn re)))
+ re))
+
+(defmacro --fix (form list)
+ "Anaphoric form of `-fix'."
+ `(-fix (lambda (it) ,form) ,list))
+
+(defun -unfold (fun seed)
+ "Build a list from SEED using FUN.
+
+This is \"dual\" operation to `-reduce-r': while -reduce-r
+consumes a list to produce a single value, `-unfold' takes a
+seed value and builds a (potentially infinite!) list.
+
+FUN should return `nil' to stop the generating process, or a
+cons (A . B), where A will be prepended to the result and B is
+the new seed."
+ (let ((last (funcall fun seed)) r)
+ (while last
+ (push (car last) r)
+ (setq last (funcall fun (cdr last))))
+ (nreverse r)))
+
+(defmacro --unfold (form seed)
+ "Anaphoric version of `-unfold'."
+ (declare (debug (form form)))
+ `(-unfold (lambda (it) ,form) ,seed))
+
+(defun -cons-pair? (con)
+ "Return non-nil if CON is true cons pair.
+That is (A . B) where B is not a list."
+ (declare (pure t) (side-effect-free t))
+ (and (listp con)
+ (not (listp (cdr con)))))
+
+(defun -cons-to-list (con)
+ "Convert a cons pair to a list with `car' and `cdr' of the pair respectively."
+ (declare (pure t) (side-effect-free t))
+ (list (car con) (cdr con)))
+
+(defun -value-to-list (val)
+ "Convert a value to a list.
+
+If the value is a cons pair, make a list with two elements, `car'
+and `cdr' of the pair respectively.
+
+If the value is anything else, wrap it in a list."
+ (declare (pure t) (side-effect-free t))
+ (cond
+ ((-cons-pair? val) (-cons-to-list val))
+ (t (list val))))
+
+(defun -tree-mapreduce-from (fn folder init-value tree)
+ "Apply FN to each element of TREE, and make a list of the results.
+If elements of TREE are lists themselves, apply FN recursively to
+elements of these nested lists.
+
+Then reduce the resulting lists using FOLDER and initial value
+INIT-VALUE. See `-reduce-r-from'.
+
+This is the same as calling `-tree-reduce-from' after `-tree-map'
+but is twice as fast as it only traverse the structure once."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) (funcall fn tree))
+ ((listp tree)
+ (-reduce-r-from folder init-value (mapcar (lambda (x) (-tree-mapreduce-from fn folder init-value x)) tree)))
+ (t (funcall fn tree))))
+
+(defmacro --tree-mapreduce-from (form folder init-value tree)
+ "Anaphoric form of `-tree-mapreduce-from'."
+ (declare (debug (form form form form)))
+ `(-tree-mapreduce-from (lambda (it) ,form) (lambda (it acc) ,folder) ,init-value ,tree))
+
+(defun -tree-mapreduce (fn folder tree)
+ "Apply FN to each element of TREE, and make a list of the results.
+If elements of TREE are lists themselves, apply FN recursively to
+elements of these nested lists.
+
+Then reduce the resulting lists using FOLDER and initial value
+INIT-VALUE. See `-reduce-r-from'.
+
+This is the same as calling `-tree-reduce' after `-tree-map'
+but is twice as fast as it only traverse the structure once."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) (funcall fn tree))
+ ((listp tree)
+ (-reduce-r folder (mapcar (lambda (x) (-tree-mapreduce fn folder x)) tree)))
+ (t (funcall fn tree))))
+
+(defmacro --tree-mapreduce (form folder tree)
+ "Anaphoric form of `-tree-mapreduce'."
+ (declare (debug (form form form)))
+ `(-tree-mapreduce (lambda (it) ,form) (lambda (it acc) ,folder) ,tree))
+
+(defun -tree-map (fn tree)
+ "Apply FN to each element of TREE while preserving the tree structure."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) (funcall fn tree))
+ ((listp tree)
+ (mapcar (lambda (x) (-tree-map fn x)) tree))
+ (t (funcall fn tree))))
+
+(defmacro --tree-map (form tree)
+ "Anaphoric form of `-tree-map'."
+ (declare (debug (form form)))
+ `(-tree-map (lambda (it) ,form) ,tree))
+
+(defun -tree-reduce-from (fn init-value tree)
+ "Use FN to reduce elements of list TREE.
+If elements of TREE are lists themselves, apply the reduction recursively.
+
+FN is first applied to INIT-VALUE and first element of the list,
+then on this result and second element from the list etc.
+
+The initial value is ignored on cons pairs as they always contain
+two elements."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) tree)
+ ((listp tree)
+ (-reduce-r-from fn init-value (mapcar (lambda (x) (-tree-reduce-from fn init-value x)) tree)))
+ (t tree)))
+
+(defmacro --tree-reduce-from (form init-value tree)
+ "Anaphoric form of `-tree-reduce-from'."
+ (declare (debug (form form form)))
+ `(-tree-reduce-from (lambda (it acc) ,form) ,init-value ,tree))
+
+(defun -tree-reduce (fn tree)
+ "Use FN to reduce elements of list TREE.
+If elements of TREE are lists themselves, apply the reduction recursively.
+
+FN is first applied to first element of the list and second
+element, then on this result and third element from the list etc.
+
+See `-reduce-r' for how exactly are lists of zero or one element handled."
+ (cond
+ ((not tree) nil)
+ ((-cons-pair? tree) tree)
+ ((listp tree)
+ (-reduce-r fn (mapcar (lambda (x) (-tree-reduce fn x)) tree)))
+ (t tree)))
+
+(defmacro --tree-reduce (form tree)
+ "Anaphoric form of `-tree-reduce'."
+ (declare (debug (form form)))
+ `(-tree-reduce (lambda (it acc) ,form) ,tree))
+
+(defun -tree-map-nodes (pred fun tree)
+ "Call FUN on each node of TREE that satisfies PRED.
+
+If PRED returns nil, continue descending down this node. If PRED
+returns non-nil, apply FUN to this node and do not descend
+further."
+ (if (funcall pred tree)
+ (funcall fun tree)
+ (if (and (listp tree)
+ (not (-cons-pair? tree)))
+ (-map (lambda (x) (-tree-map-nodes pred fun x)) tree)
+ tree)))
+
+(defmacro --tree-map-nodes (pred form tree)
+ "Anaphoric form of `-tree-map-nodes'."
+ `(-tree-map-nodes (lambda (it) ,pred) (lambda (it) ,form) ,tree))
+
+(defun -tree-seq (branch children tree)
+ "Return a sequence of the nodes in TREE, in depth-first search order.
+
+BRANCH is a predicate of one argument that returns non-nil if the
+passed argument is a branch, that is, a node that can have children.
+
+CHILDREN is a function of one argument that returns the children
+of the passed branch node.
+
+Non-branch nodes are simply copied."
+ (cons tree
+ (when (funcall branch tree)
+ (-mapcat (lambda (x) (-tree-seq branch children x))
+ (funcall children tree)))))
+
+(defmacro --tree-seq (branch children tree)
+ "Anaphoric form of `-tree-seq'."
+ `(-tree-seq (lambda (it) ,branch) (lambda (it) ,children) ,tree))
+
+(defun -clone (list)
+ "Create a deep copy of LIST.
+The new list has the same elements and structure but all cons are
+replaced with new ones. This is useful when you need to clone a
+structure such as plist or alist."
+ (declare (pure t) (side-effect-free t))
+ (-tree-map 'identity list))
+
+(defun dash-enable-font-lock ()
+ "Add syntax highlighting to dash functions, macros and magic values."
+ (eval-after-load "lisp-mode"
+ '(progn
+ (let ((new-keywords '(
+ "-each"
+ "--each"
+ "-each-indexed"
+ "--each-indexed"
+ "-each-while"
+ "--each-while"
+ "-dotimes"
+ "--dotimes"
+ "-map"
+ "--map"
+ "-reduce-from"
+ "--reduce-from"
+ "-reduce"
+ "--reduce"
+ "-reduce-r-from"
+ "--reduce-r-from"
+ "-reduce-r"
+ "--reduce-r"
+ "-filter"
+ "--filter"
+ "-select"
+ "--select"
+ "-remove"
+ "--remove"
+ "-reject"
+ "--reject"
+ "-remove-first"
+ "--remove-first"
+ "-reject-first"
+ "--reject-first"
+ "-remove-last"
+ "--remove-last"
+ "-reject-last"
+ "--reject-last"
+ "-remove-item"
+ "-non-nil"
+ "-keep"
+ "--keep"
+ "-map-indexed"
+ "--map-indexed"
+ "-splice"
+ "--splice"
+ "-splice-list"
+ "--splice-list"
+ "-map-when"
+ "--map-when"
+ "-replace-where"
+ "--replace-where"
+ "-map-first"
+ "--map-first"
+ "-map-last"
+ "--map-last"
+ "-replace"
+ "-replace-first"
+ "-replace-last"
+ "-flatten"
+ "-flatten-n"
+ "-concat"
+ "-mapcat"
+ "--mapcat"
+ "-copy"
+ "-cons*"
+ "-snoc"
+ "-first"
+ "--first"
+ "-find"
+ "--find"
+ "-some"
+ "--some"
+ "-any"
+ "--any"
+ "-last"
+ "--last"
+ "-first-item"
+ "-last-item"
+ "-butlast"
+ "-count"
+ "--count"
+ "-any?"
+ "--any?"
+ "-some?"
+ "--some?"
+ "-any-p"
+ "--any-p"
+ "-some-p"
+ "--some-p"
+ "-all?"
+ "--all?"
+ "-every?"
+ "--every?"
+ "-all-p"
+ "--all-p"
+ "-every-p"
+ "--every-p"
+ "-none?"
+ "--none?"
+ "-none-p"
+ "--none-p"
+ "-only-some?"
+ "--only-some?"
+ "-only-some-p"
+ "--only-some-p"
+ "-slice"
+ "-take"
+ "-drop"
+ "-take-while"
+ "--take-while"
+ "-drop-while"
+ "--drop-while"
+ "-split-at"
+ "-rotate"
+ "-insert-at"
+ "-replace-at"
+ "-update-at"
+ "--update-at"
+ "-remove-at"
+ "-remove-at-indices"
+ "-split-with"
+ "--split-with"
+ "-split-on"
+ "-split-when"
+ "--split-when"
+ "-separate"
+ "--separate"
+ "-partition-all-in-steps"
+ "-partition-in-steps"
+ "-partition-all"
+ "-partition"
+ "-partition-by"
+ "--partition-by"
+ "-partition-by-header"
+ "--partition-by-header"
+ "-group-by"
+ "--group-by"
+ "-interpose"
+ "-interleave"
+ "-zip-with"
+ "--zip-with"
+ "-zip"
+ "-zip-fill"
+ "-cycle"
+ "-pad"
+ "-annotate"
+ "--annotate"
+ "-table"
+ "-table-flat"
+ "-partial"
+ "-elem-index"
+ "-elem-indices"
+ "-find-indices"
+ "--find-indices"
+ "-find-index"
+ "--find-index"
+ "-find-last-index"
+ "--find-last-index"
+ "-select-by-indices"
+ "-select-columns"
+ "-select-column"
+ "-grade-up"
+ "-grade-down"
+ "->"
+ "->>"
+ "-->"
+ "-when-let"
+ "-when-let*"
+ "--when-let"
+ "-if-let"
+ "-if-let*"
+ "--if-let"
+ "-let*"
+ "-let"
+ "-lambda"
+ "-distinct"
+ "-uniq"
+ "-union"
+ "-intersection"
+ "-difference"
+ "-contains?"
+ "-contains-p"
+ "-same-items?"
+ "-same-items-p"
+ "-is-prefix-p"
+ "-is-prefix?"
+ "-is-suffix-p"
+ "-is-suffix?"
+ "-is-infix-p"
+ "-is-infix?"
+ "-sort"
+ "--sort"
+ "-list"
+ "-repeat"
+ "-sum"
+ "-product"
+ "-max"
+ "-min"
+ "-max-by"
+ "--max-by"
+ "-min-by"
+ "--min-by"
+ "-iterate"
+ "--iterate"
+ "-fix"
+ "--fix"
+ "-unfold"
+ "--unfold"
+ "-cons-pair?"
+ "-cons-to-list"
+ "-value-to-list"
+ "-tree-mapreduce-from"
+ "--tree-mapreduce-from"
+ "-tree-mapreduce"
+ "--tree-mapreduce"
+ "-tree-map"
+ "--tree-map"
+ "-tree-reduce-from"
+ "--tree-reduce-from"
+ "-tree-reduce"
+ "--tree-reduce"
+ "-tree-seq"
+ "--tree-seq"
+ "-tree-map-nodes"
+ "--tree-map-nodes"
+ "-clone"
+ "-rpartial"
+ "-juxt"
+ "-applify"
+ "-on"
+ "-flip"
+ "-const"
+ "-cut"
+ "-orfn"
+ "-andfn"
+ "-iteratefn"
+ "-fixfn"
+ "-prodfn"
+ ))
+ (special-variables '(
+ "it"
+ "it-index"
+ "acc"
+ "other"
+ )))
+ (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "\\_<" (regexp-opt special-variables 'paren) "\\_>")
+ 1 font-lock-variable-name-face)) 'append)
+ (font-lock-add-keywords 'emacs-lisp-mode `((,(concat "(\\s-*" (regexp-opt new-keywords 'paren) "\\_>")
+ 1 font-lock-keyword-face)) 'append))
+ (--each (buffer-list)
+ (with-current-buffer it
+ (when (and (eq major-mode 'emacs-lisp-mode)
+ (boundp 'font-lock-mode)
+ font-lock-mode)
+ (font-lock-refresh-defaults)))))))
+
+(provide 'dash)
+;;; dash.el ends here
--- /dev/null
+;;; git-commit-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+\f
+;;;### (autoloads nil "git-commit" "git-commit.el" (22576 8241 0
+;;;;;; 0))
+;;; Generated autoloads from git-commit.el
+
+(defvar global-git-commit-mode t "\
+Non-nil if Global Git-Commit mode is enabled.
+See the `global-git-commit-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `global-git-commit-mode'.")
+
+(custom-autoload 'global-git-commit-mode "git-commit" nil)
+
+(autoload 'global-git-commit-mode "git-commit" "\
+Edit Git commit messages.
+This global mode arranges for `git-commit-setup' to be called
+when a Git commit message file is opened. That usually happens
+when Git uses the Emacsclient as $GIT_EDITOR to have the user
+provide such a commit message.
+
+\(fn &optional ARG)" t nil)
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; git-commit-autoloads.el ends here
--- /dev/null
+;;; -*- no-byte-compile: t -*-
+(define-package "git-commit" "20161108.1335" "Edit Git commit messages" '((emacs "24.4") (dash "20160820.501") (with-editor "20160929.734")) :url "https://github.com/magit/magit" :keywords '("git" "tools" "vc"))
--- /dev/null
+;;; git-commit.el --- Edit Git commit messages -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Authors: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Sebastian Wiesner <lunaryornNOSPAMgmail.com>
+;; Florian Ragwitz <raflNOSPAMdebian.org>
+;; Marius Vollmer <marius.vollmerNOSPAMgmail.com>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Package-Requires: ((emacs "24.4") (dash "20160820.501") (with-editor "20160929.734"))
+;; Package-Version: 20161108.1335
+;; Keywords: git tools vc
+;; Homepage: https://github.com/magit/magit
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package assists the user in writing good Git commit messages.
+
+;; While Git allows for the message to be provided on the command
+;; line, it is preferable to tell Git to create the commit without
+;; actually passing it a message. Git then invokes the `$GIT_EDITOR'
+;; (or if that is undefined `$EDITOR') asking the user to provide the
+;; message by editing the file ".git/COMMIT_EDITMSG" (or another file
+;; in that directory, e.g. ".git/MERGE_MSG" for merge commits).
+
+;; When `global-git-commit-mode' is enabled, which it is by default,
+;; then opening such a file causes the features described below, to
+;; be enabled in that buffer. Normally this would be done using a
+;; major-mode but to allow the use of any major-mode, as the user sees
+;; fit, it is done here by running a setup function, which among other
+;; things turns on the preferred major-mode, by default `text-mode'.
+
+;; Git waits for the `$EDITOR' to finish and then either creates the
+;; commit using the contents of the file as commit message, or, if the
+;; editor process exited with a non-zero exit status, aborts without
+;; creating a commit. Unfortunately Emacsclient (which is what Emacs
+;; users should be using as `$EDITOR' or at least as `$GIT_EDITOR')
+;; does not differentiate between "successfully" editing a file and
+;; aborting; not out of the box that is.
+
+;; By making use of the `with-editor' package this package provides
+;; both ways of finish an editing session. In either case the file
+;; is saved, but Emacseditor's exit code differs.
+;;
+;; C-c C-c Finish the editing session successfully by returning
+;; with exit code 0. Git then creates the commit using
+;; the message it finds in the file.
+;;
+;; C-c C-k Aborts the edit editing session by returning with exit
+;; code 1. Git then aborts the commit.
+
+;; Aborting the commit does not cause the message to be lost, but
+;; relying solely on the file not being tampered with is risky. This
+;; package additionally stores all aborted messages for the duration
+;; of the current session (i.e. until you close Emacs). To get back
+;; an aborted message use M-p and M-n while editing a message.
+;;
+;; M-p Replace the buffer contents with the previous message
+;; from the message ring. Of course only after storing
+;; the current content there too.
+;;
+;; M-n Replace the buffer contents with the next message from
+;; the message ring, after storing the current content.
+
+;; Some support for pseudo headers as used in some projects is
+;; provided by these commands:
+;;
+;; C-c C-s Insert a Signed-off-by header.
+;; C-C C-a Insert a Acked-by header.
+;; C-c C-t Insert a Tested-by header.
+;; C-c C-r Insert a Reviewed-by header.
+;; C-c C-o Insert a Cc header.
+;; C-c C-p Insert a Reported-by header.
+;; C-c M-s Insert a Suggested-by header.
+
+;; When Git requests a commit message from the user, it does so by
+;; having her edit a file which initially contains some comments,
+;; instructing her what to do, and providing useful information, such
+;; as which files were modified. These comments, even when left
+;; intact by the user, do not become part of the commit message. This
+;; package ensures these comments are propertizes as such and further
+;; prettifies them by using different faces for various parts, such as
+;; files.
+
+;; Finally this package highlights style errors, like lines that are
+;; too long, or when the second line is not empty. It may even nag
+;; you when you attempt to finish the commit without having fixed
+;; these issues. The style checks and many other settings can easily
+;; be configured:
+;;
+;; M-x customize-group RET git-commit RET
+
+;;; Code:
+;;;; Dependencies
+
+(require 'dash)
+(require 'log-edit)
+(require 'ring)
+(require 'server)
+(require 'with-editor)
+
+(eval-when-compile (require 'recentf))
+
+;;;; Declarations
+
+(defvar flyspell-generic-check-word-predicate)
+(defvar font-lock-beg)
+(defvar font-lock-end)
+
+(declare-function magit-expand-git-file-name 'magit-git)
+
+;;; Options
+;;;; Variables
+
+(defgroup git-commit nil
+ "Edit Git commit messages."
+ :prefix "git-commit-"
+ :group 'tools)
+
+;;;###autoload
+(define-minor-mode global-git-commit-mode
+ "Edit Git commit messages.
+This global mode arranges for `git-commit-setup' to be called
+when a Git commit message file is opened. That usually happens
+when Git uses the Emacsclient as $GIT_EDITOR to have the user
+provide such a commit message."
+ :group 'git-commit
+ :type 'boolean
+ :global t
+ :init-value t
+ :initialize (lambda (symbol exp)
+ (custom-initialize-default symbol exp)
+ (when global-git-commit-mode
+ (add-hook 'find-file-hook 'git-commit-setup-check-buffer)))
+ (if global-git-commit-mode
+ (add-hook 'find-file-hook 'git-commit-setup-check-buffer)
+ (remove-hook 'find-file-hook 'git-commit-setup-check-buffer)))
+
+(defcustom git-commit-major-mode 'text-mode
+ "Major mode used to edit Git commit messages.
+The major mode configured here is turned on by the minor mode
+`git-commit-mode'."
+ :group 'git-commit
+ :type '(choice (function-item text-mode)
+ (const :tag "No major mode")))
+
+(unless (find-lisp-object-file-name 'git-commit-setup-hook 'defvar)
+ (add-hook 'git-commit-setup-hook 'with-editor-usage-message)
+ (add-hook 'git-commit-setup-hook 'git-commit-propertize-diff)
+ (add-hook 'git-commit-setup-hook 'git-commit-turn-on-auto-fill)
+ (add-hook 'git-commit-setup-hook 'git-commit-setup-changelog-support)
+ (add-hook 'git-commit-setup-hook 'git-commit-save-message))
+(defcustom git-commit-setup-hook
+ '(git-commit-save-message
+ git-commit-setup-changelog-support
+ git-commit-turn-on-auto-fill
+ git-commit-propertize-diff
+ with-editor-usage-message)
+ "Hook run at the end of `git-commit-setup'."
+ :group 'git-commit
+ :type 'hook
+ :options '(git-commit-save-message
+ git-commit-setup-changelog-support
+ git-commit-turn-on-auto-fill
+ git-commit-turn-on-flyspell
+ git-commit-propertize-diff
+ with-editor-usage-message))
+
+(defcustom git-commit-finish-query-functions
+ '(git-commit-check-style-conventions)
+ "List of functions called to query before performing commit.
+
+The commit message buffer is current while the functions are
+called. If any of them returns nil, then the commit is not
+performed and the buffer is not killed. The user should then
+fix the issue and try again.
+
+The functions are called with one argument. If it is non-nil
+then that indicates that the user used a prefix argument to
+force finishing the session despite issues. Functions should
+usually honor this wish and return non-nil."
+ :options '(git-commit-check-style-conventions)
+ :type 'hook
+ :group 'git-commit)
+
+(defcustom git-commit-style-convention-checks '(non-empty-second-line)
+ "List of checks performed by `git-commit-check-style-conventions'.
+Valid members are `non-empty-second-line' and `overlong-first-line'.
+That function is a member of `git-commit-finish-query-functions'."
+ :options '(non-empty-second-line overlong-summary-line)
+ :type '(list :convert-widget custom-hook-convert-widget)
+ :group 'git-commit)
+
+(defcustom git-commit-summary-max-length 68
+ "Column beyond which characters in the summary lines are highlighted.
+
+The highlighting indicates that the summary is getting too long
+by some standards. It does in no way imply that going over the
+limit a few characters or in some cases even many characters is
+anything that deserves shaming. It's just a friendly reminder
+that if you can make the summary shorter, then you might want
+to consider doing so."
+ :group 'git-commit
+ :safe 'numberp
+ :type 'number)
+
+(defcustom git-commit-fill-column nil
+ "Override `fill-column' in commit message buffers.
+
+If this is non-nil, then it should be an integer. If that is the
+case and the buffer-local value of `fill-column' is not already
+set by the time `git-commit-turn-on-auto-fill' is called as a
+member of `git-commit-setup-hook', then that function sets the
+buffer-local value of `fill-column' to the value of this option.
+
+This option exists mostly for historic reasons. If you are not
+already using it, then you probably shouldn't start doing so."
+ :group 'git-commit
+ :safe 'numberp
+ :type '(choice (const :tag "use regular fill-column")
+ number))
+
+(defcustom git-commit-known-pseudo-headers
+ '("Signed-off-by" "Acked-by" "Cc"
+ "Suggested-by" "Reported-by" "Tested-by" "Reviewed-by")
+ "A list of Git pseudo headers to be highlighted."
+ :group 'git-commit
+ :safe (lambda (val) (and (listp val) (-all-p 'stringp val)))
+ :type '(repeat string))
+
+;;;; Faces
+
+(defgroup git-commit-faces nil
+ "Faces for highlighting Git commit messages."
+ :prefix "git-commit-"
+ :group 'git-commit
+ :group 'faces)
+
+(defface git-commit-summary
+ '((t :inherit font-lock-type-face))
+ "Face used for the summary in commit messages."
+ :group 'git-commit-faces)
+
+(defface git-commit-overlong-summary
+ '((t :inherit font-lock-warning-face))
+ "Face used for the tail of overlong commit message summaries."
+ :group 'git-commit-faces)
+
+(defface git-commit-nonempty-second-line
+ '((t :inherit font-lock-warning-face))
+ "Face used for non-whitespace on the second line of commit messages."
+ :group 'git-commit-faces)
+
+(defface git-commit-note
+ '((t :inherit font-lock-string-face))
+ "Face used for notes in commit messages."
+ :group 'git-commit-faces)
+
+(defface git-commit-pseudo-header
+ '((t :inherit font-lock-string-face))
+ "Font used for pseudo headers in commit messages."
+ :group 'git-commit-faces)
+
+(defface git-commit-known-pseudo-header
+ '((t :inherit font-lock-keyword-face))
+ "Face used for the keywords of known pseudo headers in commit messages."
+ :group 'git-commit-faces)
+
+(defface git-commit-comment-branch
+ '((t :inherit font-lock-variable-name-face))
+ "Face used for branch names in commit message comments."
+ :group 'git-commit-faces)
+
+(defface git-commit-comment-detached
+ '((t :inherit git-commit-comment-branch))
+ "Face used for detached `HEAD' in commit message comments."
+ :group 'git-commit-faces)
+
+(defface git-commit-comment-heading
+ '((t :inherit git-commit-known-pseudo-header))
+ "Face used for headings in commit message comments."
+ :group 'git-commit-faces)
+
+(defface git-commit-comment-file
+ '((t :inherit git-commit-pseudo-header))
+ "Face used for file names in commit message comments."
+ :group 'git-commit-faces)
+
+(defface git-commit-comment-action
+ '((t :inherit git-commit-comment-branch))
+ "Face used for actions in commit message comments."
+ :group 'git-commit-faces)
+
+;;; Keymap
+
+(defvar git-commit-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-c C-s") 'git-commit-signoff)
+ (define-key map (kbd "C-c C-a") 'git-commit-ack)
+ (define-key map (kbd "C-c C-t") 'git-commit-test)
+ (define-key map (kbd "C-c C-r") 'git-commit-review)
+ (define-key map (kbd "C-c C-o") 'git-commit-cc)
+ (define-key map (kbd "C-c C-p") 'git-commit-reported)
+ (define-key map (kbd "C-c C-i") 'git-commit-suggested)
+ (define-key map (kbd "C-c M-s") 'git-commit-save-message)
+ (define-key map (kbd "M-p") 'git-commit-prev-message)
+ (define-key map (kbd "M-n") 'git-commit-next-message)
+ ;; Old bindings to avoid confusion
+ (define-key map (kbd "C-c C-x s") 'git-commit-signoff)
+ (define-key map (kbd "C-c C-x a") 'git-commit-ack)
+ (define-key map (kbd "C-c C-x t") 'git-commit-test)
+ (define-key map (kbd "C-c C-x r") 'git-commit-review)
+ (define-key map (kbd "C-c C-x o") 'git-commit-cc)
+ (define-key map (kbd "C-c C-x p") 'git-commit-reported)
+ map)
+ "Key map used by `git-commit-mode'.")
+
+;;; Menu
+
+(require 'easymenu)
+(easy-menu-define git-commit-mode-menu git-commit-mode-map
+ "Git Commit Mode Menu"
+ '("Commit"
+ ["Previous" git-commit-prev-message t]
+ ["Next" git-commit-next-message t]
+ "-"
+ ["Ack" git-commit-ack :active t
+ :help "Insert an 'Acked-by' header"]
+ ["Sign-Off" git-commit-signoff :active t
+ :help "Insert a 'Signed-off-by' header"]
+ ["Tested-by" git-commit-test :active t
+ :help "Insert a 'Tested-by' header"]
+ ["Reviewed-by" git-commit-review :active t
+ :help "Insert a 'Reviewed-by' header"]
+ ["CC" git-commit-cc t
+ :help "Insert a 'Cc' header"]
+ ["Reported" git-commit-reported :active t
+ :help "Insert a 'Reported-by' header"]
+ ["Suggested" git-commit-suggested t
+ :help "Insert a 'Suggested-by' header"]
+ "-"
+ ["Save" git-commit-save-message t]
+ ["Cancel" with-editor-cancel t]
+ ["Commit" with-editor-finish t]))
+
+;;; Hooks
+
+(defconst git-commit-filename-regexp "/\\(\
+\\(\\(COMMIT\\|NOTES\\|PULLREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\
+\\|BRANCH_DESCRIPTION\\)\\'")
+
+(eval-after-load 'recentf
+ '(add-to-list 'recentf-exclude git-commit-filename-regexp))
+
+(add-to-list 'with-editor-file-name-history-exclude git-commit-filename-regexp)
+
+(defun git-commit-setup-font-lock-in-buffer ()
+ (and buffer-file-name
+ (string-match-p git-commit-filename-regexp buffer-file-name)
+ (git-commit-setup-font-lock)))
+
+(add-hook 'after-change-major-mode-hook 'git-commit-setup-font-lock-in-buffer)
+
+(defun git-commit-setup-check-buffer ()
+ (and buffer-file-name
+ (string-match-p git-commit-filename-regexp buffer-file-name)
+ (git-commit-setup)))
+
+(defun git-commit-setup ()
+ ;; cygwin git will pass a cygwin path (/cygdrive/c/foo/.git/...),
+ ;; try to handle this in window-nt Emacs.
+ (--when-let
+ (and (eq system-type 'windows-nt)
+ (not (file-accessible-directory-p default-directory))
+ (if (require 'magit-git nil t)
+ ;; Emacs prepends a "c:".
+ (magit-expand-git-file-name (substring buffer-file-name 2))
+ ;; Fallback if we can't load `magit-git'.
+ (and (string-match "\\`[a-z]:/\\(cygdrive/\\)?\\([a-z]\\)/\\(.*\\)"
+ buffer-file-name)
+ (concat (match-string 2 buffer-file-name) ":/"
+ (match-string 3 buffer-file-name)))))
+ (when (file-accessible-directory-p (file-name-directory it))
+ (find-alternate-file it)))
+ (when git-commit-major-mode
+ (let ((auto-mode-alist (list (cons (concat "\\`"
+ (regexp-quote buffer-file-name)
+ "\\'")
+ git-commit-major-mode))))
+ (normal-mode)))
+ (setq with-editor-show-usage nil)
+ (with-editor-mode 1)
+ (add-hook 'with-editor-finish-query-functions
+ 'git-commit-finish-query-functions nil t)
+ (add-hook 'with-editor-pre-finish-hook
+ 'git-commit-save-message nil t)
+ (add-hook 'with-editor-pre-cancel-hook
+ 'git-commit-save-message nil t)
+ (setq with-editor-cancel-message
+ 'git-commit-cancel-message)
+ (make-local-variable 'log-edit-comment-ring-index)
+ (git-commit-mode 1)
+ (git-commit-setup-font-lock)
+ (when (boundp 'save-place)
+ (setq save-place nil))
+ (save-excursion
+ (goto-char (point-min))
+ (when (= (line-beginning-position)
+ (line-end-position))
+ (open-line 1)))
+ (run-hooks 'git-commit-setup-hook)
+ (set-buffer-modified-p nil))
+
+(defun git-commit-setup-font-lock ()
+ (let ((table (make-syntax-table (syntax-table))))
+ (when comment-start
+ (modify-syntax-entry (string-to-char comment-start) "." table))
+ (modify-syntax-entry ?# "." table)
+ (modify-syntax-entry ?\" "." table)
+ (modify-syntax-entry ?\' "." table)
+ (modify-syntax-entry ?` "." table)
+ (set-syntax-table table))
+ (setq-local comment-start
+ (or (ignore-errors
+ (car (process-lines "git" "config" "core.commentchar")))
+ "#"))
+ (setq-local comment-start-skip (format "^%s+[\s\t]*" comment-start))
+ (setq-local comment-end-skip "\n")
+ (setq-local comment-use-syntax nil)
+ (setq-local font-lock-multiline t)
+ (add-hook 'font-lock-extend-region-functions
+ #'git-commit-extend-region-summary-line
+ t t)
+ (font-lock-add-keywords nil (git-commit-mode-font-lock-keywords) t))
+
+(define-minor-mode git-commit-mode
+ "Auxiliary minor mode used when editing Git commit messages.
+This mode is only responsible for setting up some key bindings.
+Don't use it directly, instead enable `global-git-commit-mode'."
+ :lighter "")
+
+(put 'git-commit-mode 'permanent-local t)
+
+(defun git-commit-setup-changelog-support ()
+ "Treat ChangeLog entries as paragraphs."
+ (setq-local paragraph-start (concat paragraph-start "\\|\\*\\|(")))
+
+(defun git-commit-turn-on-auto-fill ()
+ "Unconditionally turn on Auto Fill mode.
+If `git-commit-fill-column' is non-nil, and `fill-column'
+doesn't already have a buffer-local value, then set that
+to `git-commit-fill-column'."
+ (when (and (numberp git-commit-fill-column)
+ (not (local-variable-p 'fill-column)))
+ (setq fill-column git-commit-fill-column))
+ (turn-on-auto-fill))
+
+(defun git-commit-turn-on-flyspell ()
+ "Unconditionally turn on Flyspell mode.
+Also prevent comments from being checked and
+finally check current non-comment text."
+ (require 'flyspell)
+ (turn-on-flyspell)
+ (setq flyspell-generic-check-word-predicate
+ 'git-commit-flyspell-verify)
+ (flyspell-buffer))
+
+(defun git-commit-flyspell-verify ()
+ (not (= (char-after (line-beginning-position)) ?#)))
+
+(defun git-commit-finish-query-functions (force)
+ (run-hook-with-args-until-failure
+ 'git-commit-finish-query-functions force))
+
+(defun git-commit-check-style-conventions (force)
+ "Check for violations of certain basic style conventions.
+
+For each violation ask the user if she wants to proceed anyway.
+Option `git-commit-check-style-conventions' controls which
+conventions are checked."
+ (or force
+ (save-excursion
+ (goto-char (point-min))
+ (re-search-forward (git-commit-summary-regexp) nil t)
+ (if (equal (match-string 1) "")
+ t ; Just try; we don't know whether --allow-empty-message was used.
+ (and (or (not (memq 'overlong-summary-line
+ git-commit-style-convention-checks))
+ (equal (match-string 2) "")
+ (y-or-n-p "Summary line is too long. Commit anyway? "))
+ (or (not (memq 'non-empty-second-line
+ git-commit-style-convention-checks))
+ (not (match-string 3))
+ (y-or-n-p "Second line is not empty. Commit anyway? ")))))))
+
+(defun git-commit-cancel-message ()
+ (message
+ (concat "Commit canceled"
+ (and (memq 'git-commit-save-message with-editor-pre-cancel-hook)
+ ". Message saved to `log-edit-comment-ring'"))))
+
+;;; History
+
+(defun git-commit-prev-message (arg)
+ "Cycle backward through message history, after saving current message.
+With a numeric prefix ARG, go back ARG comments."
+ (interactive "*p")
+ (when (and (git-commit-save-message) (> arg 0))
+ (setq log-edit-comment-ring-index
+ (log-edit-new-comment-index
+ arg (ring-length log-edit-comment-ring))))
+ (save-restriction
+ (goto-char (point-min))
+ (narrow-to-region (point)
+ (if (re-search-forward (concat "^" comment-start))
+ (max 1 (- (point) 2))
+ (point-max)))
+ (log-edit-previous-comment arg)))
+
+(defun git-commit-next-message (arg)
+ "Cycle forward through message history, after saving current message.
+With a numeric prefix ARG, go forward ARG comments."
+ (interactive "*p")
+ (git-commit-prev-message (- arg)))
+
+(defun git-commit-save-message ()
+ "Save current message to `log-edit-comment-ring'."
+ (interactive)
+ (--when-let (git-commit-buffer-message)
+ (unless (ring-member log-edit-comment-ring it)
+ (ring-insert log-edit-comment-ring it))))
+
+(defun git-commit-buffer-message ()
+ (let ((flush (concat "^" comment-start))
+ (str (buffer-substring-no-properties (point-min) (point-max))))
+ (with-temp-buffer
+ (insert str)
+ (goto-char (point-min))
+ (when (re-search-forward (concat flush " -+ >8 -+$") nil t)
+ (delete-region (point-at-bol) (point-max)))
+ (goto-char (point-min))
+ (flush-lines flush)
+ (goto-char (point-max))
+ (unless (eq (char-before) ?\n)
+ (insert ?\n))
+ (setq str (buffer-string)))
+ (unless (string-match "\\`[ \t\n\r]*\\'" str)
+ (when (string-match "\\`\n\\{2,\\}" str)
+ (setq str (replace-match "\n" t t str)))
+ (when (string-match "\n\\{2,\\}\\'" str)
+ (setq str (replace-match "\n" t t str)))
+ str)))
+
+;;; Headers
+
+(defun git-commit-ack (name mail)
+ "Insert a header acknowledging that you have looked at the commit."
+ (interactive (git-commit-self-ident))
+ (git-commit-insert-header "Acked-by" name mail))
+
+(defun git-commit-review (name mail)
+ "Insert a header acknowledging that you have reviewed the commit."
+ (interactive (git-commit-self-ident))
+ (git-commit-insert-header "Reviewed-by" name mail))
+
+(defun git-commit-signoff (name mail)
+ "Insert a header to sign off the commit."
+ (interactive (git-commit-self-ident))
+ (git-commit-insert-header "Signed-off-by" name mail))
+
+(defun git-commit-test (name mail)
+ "Insert a header acknowledging that you have tested the commit."
+ (interactive (git-commit-self-ident))
+ (git-commit-insert-header "Tested-by" name mail))
+
+(defun git-commit-cc (name mail)
+ "Insert a header mentioning someone who might be interested."
+ (interactive (git-commit-read-ident))
+ (git-commit-insert-header "Cc" name mail))
+
+(defun git-commit-reported (name mail)
+ "Insert a header mentioning the person who reported the issue."
+ (interactive (git-commit-read-ident))
+ (git-commit-insert-header "Reported-by" name mail))
+
+(defun git-commit-suggested (name mail)
+ "Insert a header mentioning the person who suggested the change."
+ (interactive (git-commit-read-ident))
+ (git-commit-insert-header "Suggested-by" name mail))
+
+(defun git-commit-self-ident ()
+ (list (or (getenv "GIT_AUTHOR_NAME")
+ (getenv "GIT_COMMITTER_NAME")
+ (ignore-errors (car (process-lines "git" "config" "user.name")))
+ user-full-name
+ (read-string "Name: "))
+ (or (getenv "GIT_AUTHOR_EMAIL")
+ (getenv "GIT_COMMITTER_EMAIL")
+ (getenv "EMAIL")
+ (ignore-errors (car (process-lines "git" "config" "user.email")))
+ (read-string "Email: "))))
+
+(defun git-commit-read-ident ()
+ (list (read-string "Name: ")
+ (read-string "Email: ")))
+
+(defun git-commit-insert-header (header name email)
+ (setq header (format "%s: %s <%s>" header name email))
+ (save-excursion
+ (goto-char (point-max))
+ (cond ((re-search-backward "^[-a-zA-Z]+: [^<]+? <[^>]+>" nil t)
+ (end-of-line)
+ (insert ?\n header)
+ (unless (= (char-after) ?\n)
+ (insert ?\n)))
+ (t
+ (while (re-search-backward (concat "^" comment-start) nil t))
+ (unless (looking-back "\n\n" nil)
+ (insert ?\n))
+ (insert header ?\n)))
+ (unless (or (eobp) (= (char-after) ?\n))
+ (insert ?\n))))
+
+;;; Font-Lock
+
+(defconst git-commit-comment-headings
+ '("Changes to be committed:"
+ "Untracked files:"
+ "Changed but not updated:"
+ "Changes not staged for commit:"
+ "Unmerged paths:"))
+
+(defun git-commit-summary-regexp ()
+ (concat
+ ;; Leading empty lines and comments
+ (format "\\`\\(?:^\\(?:\\s-*\\|%s.*\\)\n\\)*" comment-start)
+ ;; Summary line
+ (format "\\(.\\{0,%d\\}\\)\\(.*\\)" git-commit-summary-max-length)
+ ;; Non-empty non-comment second line
+ (format "\\(?:\n%s\\|\n\\(.+\\)\\)?" comment-start)))
+
+(defun git-commit-extend-region-summary-line ()
+ "Identify the multiline summary-regexp construct.
+Added to `font-lock-extend-region-functions'."
+ (save-excursion
+ (save-match-data
+ (goto-char (point-min))
+ (when (looking-at (git-commit-summary-regexp))
+ (let ((summary-beg (match-beginning 0))
+ (summary-end (match-end 0)))
+ (when (or (< summary-beg font-lock-beg summary-end)
+ (< summary-beg font-lock-end summary-end))
+ (setq font-lock-beg (min font-lock-beg summary-beg)
+ font-lock-end (max font-lock-end summary-end))))))))
+
+(defun git-commit-mode-font-lock-keywords ()
+ `(;; Comments
+ (,(format "^%s.*" comment-start)
+ (0 'font-lock-comment-face))
+ (,(format "^%s On branch \\(.*\\)" comment-start)
+ (1 'git-commit-comment-branch t))
+ (,(format "^%s Not currently on any branch." comment-start)
+ (1 'git-commit-comment-detached t))
+ (,(format "^%s %s" comment-start
+ (regexp-opt git-commit-comment-headings t))
+ (1 'git-commit-comment-heading t))
+ (,(format "^%s\t\\(?:\\([^:\n]+\\):\\s-+\\)?\\(.*\\)" comment-start)
+ (1 'git-commit-comment-action t t)
+ (2 'git-commit-comment-file t))
+ ;; Pseudo headers
+ (,(format "^\\(%s:\\)\\( .*\\)"
+ (regexp-opt git-commit-known-pseudo-headers))
+ (1 'git-commit-known-pseudo-header)
+ (2 'git-commit-pseudo-header))
+ ("^[-a-zA-Z]+: [^<]+? <[^>]+>"
+ (0 'git-commit-pseudo-header))
+ ;; Summary
+ (,(git-commit-summary-regexp)
+ (1 'git-commit-summary t))
+ ;; - Note (overrides summary)
+ ("\\[.+?\\]"
+ (0 'git-commit-note t))
+ ;; - Non-empty second line (overrides summary and note)
+ (,(git-commit-summary-regexp)
+ (2 'git-commit-overlong-summary t t)
+ (3 'git-commit-nonempty-second-line t t))))
+
+(defun git-commit-propertize-diff ()
+ (save-excursion
+ (goto-char (point-min))
+ (when (re-search-forward "^diff --git" nil t)
+ (beginning-of-line)
+ (let ((buffer (current-buffer)))
+ (insert
+ (with-temp-buffer
+ (insert
+ (with-current-buffer buffer
+ (prog1 (buffer-substring-no-properties (point) (point-max))
+ (delete-region (point) (point-max)))))
+ (diff-mode)
+ (let (font-lock-verbose font-lock-support-mode)
+ (if (fboundp 'font-lock-ensure)
+ (font-lock-ensure)
+ (with-no-warnings
+ (font-lock-fontify-buffer))))
+ (let (next (pos (point-min)))
+ (while (setq next (next-single-property-change pos 'face))
+ (put-text-property pos next 'font-lock-face
+ (get-text-property pos 'face))
+ (setq pos next))
+ (put-text-property pos (point-max) 'font-lock-face
+ (get-text-property pos 'face)))
+ (buffer-string)))))))
+
+;;; git-commit.el ends soon
+(provide 'git-commit)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; git-commit.el ends here
+++ /dev/null
-Authors
-=======
-
-The following people have contributed to Magit, including the
-libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el`
-which are distributed as separate Elpa packages.
-
-For statistics see http://magit.vc/stats/authors.html.
-
-Names below are sorted alphabetically.
-
-Author
-------
-
-- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-
-Maintainer
-----------
-
-- Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-Developers
-----------
-
-- Kyle Meyer <kyleNOSPAMkyleam.com>
-- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-
-Retired Maintainers and Developers
-----------------------------------
-
-- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-- Pieter Praet <pieterNOSPAMpraet.org>
-- Phil Jackson <philNOSPAMshellarchive.co.uk>
-- Rémi Vanicat <vanicatNOSPAMdebian.org>
-- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-
-Contributors
-------------
-
-- Aaron Culich <aculichNOSPAMgmail.com>
-- Abdo Roig-Maranges <abdo.roigNOSPAMgmail.com>
-- acple <silentsphere110NOSPAMgmail.com>
-- Adam Spiers <emacsNOSPAMadamspiers.org>
-- Adeodato Simó <datoNOSPAMnet.com.org.es>
-- Ævar Arnfjörð Bjarmason <avarabNOSPAMgmail.com>
-- Alan Falloon <alan.falloonNOSPAMgmail.com>
-- Alex Dunn <adunnNOSPAMucsb.edu>
-- Alexey Voinov <alexey.v.voinovNOSPAMgmail.com>
-- Alex Kost <alezostNOSPAMgmail.com>
-- Alex Ott <alexottNOSPAMgmail.com>
-- Andreas Fuchs <asfNOSPAMboinkor.net>
-- Andreas Liljeqvist <andreas.liljeqvistNOSPAMrobacks.se>
-- Andreas Rottmann <a.rottmannNOSPAMgmx.at>
-- Andrei Chițu <andrei.chitu1NOSPAMgmail.com>
-- Andrew Kirkpatrick <andrew.kirkpatrickNOSPAMadelaide.edu.au>
-- Andrew Schwartzmeyer <andrewNOSPAMschwartzmeyer.com>
-- Andrey Smirnov <andrew.smirnovNOSPAMgmail.com>
-- Andriy Kmit' <devNOSPAMmadand.net>
-- Andy Sawyer <gitNOSPAMpureabstract.org>
-- Barak A. Pearlmutter <barak+gitNOSPAMpearlmutter.net>
-- Bastian Beischer <beischerNOSPAMphysik.rwth-aachen.de>
-- Ben Walton <bwaltonNOSPAMartsci.utoronto.ca>
-- Bradley Wright <bradNOSPAMintranation.com>
-- Brandon W Maister <quodlibetorNOSPAMgmail.com>
-- Brian Warner <warnerNOSPAMlothar.com>
-- Bryan Shell <bryan.shellNOSPAMorbitz.com>
-- Carl Lieberman <liebermancarlNOSPAMgmail.com>
-- Chris Bernard <cebernardNOSPAMgmail.com>
-- Chris Done <chrisdoneNOSPAMgmail.com>
-- Chris Moore <dooglusNOSPAMgmail.com>
-- Chris Ring <chrisNOSPAMringthis.com>
-- Christian Dietrich <christian.dietrichNOSPAMinformatik.uni-erlangen.de>
-- Christian Kluge <ckfrakturfreakNOSPAMweb.de>
-- Christopher Monsanto <chrisNOSPAMmonsan.to>
-- Cornelius Mika <cornelius.mikaNOSPAMgmail.com>
-- Craig Andera <canderaNOSPAMwangdera.com>
-- Dale Hagglund <dale.hagglundNOSPAMgmail.com>
-- Damien Cassou <damienNOSPAMcassou.me>
-- Daniel Brockman <danielNOSPAMgointeractive.se>
-- Daniel Farina <drfarinaNOSPAMacm.org>
-- Daniel Hackney <danNOSPAMhaxney.org>
-- Dan LaManna <dan.lamannaNOSPAMgmail.com>
-- David Abrahams <daveNOSPAMboostpro.com>
-- David Hull <david.hullNOSPAMopenx.com>
-- David L. Rager <ragerdlNOSPAMgmail.com>
-- David Wallin <david.wallinNOSPAMgmail.com>
-- Dennis Paskorz <dennisNOSPAMwalltowall.com>
-- Divye Kapoor <divyeNOSPAMgoogle.com>
-- Dominique Quatravaux <domqNOSPAMgoogle.com>
-- Eli Barzilay <eliNOSPAMbarzilay.org>
-- Eric Davis <edNOSPAMnpri.org>
-- Eric Schulte <schulte.ericNOSPAMgmail.com>
-- Evgkeni Sampelnikof <esabofNOSPAMgmail.com>
-- Felix Geller <fgellerNOSPAMgmail.com>
-- Feng Li <fengliNOSPAMblackmagicdesign.com>
-- Florian Ragwitz <raflNOSPAMdebian.org>
-- Geoff Shannon <geoffpshannonNOSPAMgmail.com>
-- George Kadianakis <desnackedNOSPAMgmail.com>
-- Graham Clark <grclarkNOSPAMgmail.com>
-- Greg A. Woods <woodsNOSPAMplanix.com>
-- Greg Lucas <gregNOSPAMglucas.net>
-- Greg Sexton <gregsextonNOSPAMgmail.com>
-- Guillaume Martres <smarterNOSPAMubuntu.com>
-- Hannu Koivisto <azureNOSPAMiki.fi>
-- Hans-Peter Deifel <hpdeifelNOSPAMgmx.de>
-- Ian Eure <ian.eureNOSPAMgmail.com>
-- Ingo Lohmar <i.lohmarNOSPAMgmail.com>
-- Jan Tatarik <jan.tatarikNOSPAMxing.com>
-- Jasper St. Pierre <jstpierreNOSPAMmecheye.net>
-- Jeff Bellegarde <jbellegardeNOSPAMwhitepages.com>
-- Jeff Dairiki <dairikiNOSPAMdairiki.org>
-- Jesse Alama <jesse.alamaNOSPAMgmail.com>
-- Johann Klähn <kljohannNOSPAMgmail.com>
-- John Mastro <john.b.mastroNOSPAMgmail.com>
-- John Wiegley <johnwNOSPAMnewartisans.com>
-- Jonas Bernoulli <jonasNOSPAMbernoul.li>
-- Jonathan Roes <jroesNOSPAMjroes.net>
-- Jordan Greenberg <jordanNOSPAMsoftwareslave.com>
-- Josiah Schwab <jschwabNOSPAMgmail.com>
-- Julien Danjou <julienNOSPAMdanjou.info>
-- Justin Caratzas <justin.caratzasNOSPAMgmail.com>
-- Kan-Ru Chen <kanruNOSPAMkanru.info>
-- Kan-Ru Chen <kosterNOSPAMdebian.org>
-- Kimberly Wolk <kimwolkNOSPAMhotmail.com>
-- Kyle Meyer <kyleNOSPAMkyleam.com>
-- Laurent Laffont <laurent.laffontNOSPAMgmail.com>
-- Leandro Facchinetti <meNOSPAMleafac.com>
-- Lele Gaifax <leleNOSPAMmetapensiero.it>
-- Leo Liu <sdl.webNOSPAMgmail.com>
-- Leonardo Etcheverry <leoNOSPAMkalio.net>
-- Lingchao Xin <douglarekNOSPAMusers.noreply.github.com>
-- Lluís Vilanova <vilanovaNOSPAMac.upc.edu>
-- Loic Dachary <loicNOSPAMdachary.org>
-- Luís Borges de Oliveira <lboNOSPAMsiscog.pt>
-- Luke Amdor <luke.amdorNOSPAMgmail.com>
-- Manuel Vázquez Acosta <mva.ledNOSPAMgmail.com>
-- Marcel Wolf <mwolfNOSPAMml1.net>
-- Marc Herbert <marc.herbertNOSPAMgmail.com>
-- Marcin Bachry <hegel666NOSPAMgmail.com>
-- Marco Craveiro <marco.craveiroNOSPAMgmail.com>
-- Marian Schubert <marian.schubertNOSPAMgooddata.com>
-- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-- Mark Hepburn <Mark.HepburnNOSPAMcsiro.au>
-- Mark Karpov <markkarpovNOSPAMopmbx.org>
-- Mark Oteiza <mvoteizaNOSPAMudel.edu>
-- Matus Goljer <dota.keysNOSPAMgmail.com>
-- Michael Fogleman <michaelwfoglemanNOSPAMgmail.com>
-- Michael Griffiths <mikeyNOSPAMcich.li>
-- Michael Heerdegen <michael_heerdegenNOSPAMweb.de>
-- Michal Sojka <sojkam1NOSPAMfel.cvut.cz>
-- Miles Bader <milesNOSPAMgnu.org>
-- Miloš Mošić <mosic.milosNOSPAMgmail.com>
-- Mitchel Humpherys <mitch.specialNOSPAMgmail.com>
-- Moritz Bunkus <moritzNOSPAMbunkus.org>
-- Natalie Weizenbaum <nex342NOSPAMgmail.com>
-- Nguyễn Tuấn Anh <ubolontonNOSPAMgmail.com>
-- Nic Ferier <nicNOSPAMferrier.me.uk>
-- Nick Alcock <nick.alcockNOSPAMoracle.com>
-- Nick Alexander <nalexanderNOSPAMmozilla.com>
-- Nick Dimiduk <ndimidukNOSPAMgmail.com>
-- Nicklas Lindgren <niliNOSPAMgulmohar.se>
-- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-- Nicolas Petton <nicolasNOSPAMpetton.fr>
-- Nicolas Richard <theonewiththeevillookNOSPAMyahoo.fr>
-- Nikolay Martynov <mar.kolyaNOSPAMgmail.com>
-- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-- Ole Arndt <oliver.arndtNOSPAMcegedim.com>
-- Oleh Krehel <ohwoeowhoNOSPAMgmail.com>
-- Óscar Fuentes <ofvNOSPAMwanadoo.es>
-- Paul Stadig <paulNOSPAMstadig.name>
-- Pavel Holejsovsky <pavel.holejsovskyNOSPAMupek.com>
-- Pekka Pessi <nospamNOSPAMpessi.fi>
-- Peter Eisentraut <peterNOSPAMeisentraut.org>
-- Peter Jaros <peter.a.jarosNOSPAMgmail.com>
-- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-- Peter Vasil <mailNOSPAMpetervasil.net>
-- Philippe Vaucher <philippe.vaucherNOSPAMgmail.com>
-- Philipp Haselwarter <philippNOSPAMhaselwarter.org>
-- Philip Weaver <philip.weaverNOSPAMgmail.com>
-- Phil Jackson <philNOSPAMshellarchive.co.uk>
-- Phil Sainty <philNOSPAMcatalyst.net.nz>
-- Pieter Praet <pieterNOSPAMpraet.org>
-- Prathamesh Sonpatki <csonpatkiNOSPAMgmail.com>
-- rabio <rabiodevNOSPAMo2.pl>
-- Rafael Laboissiere <rafaelNOSPAMlaboissiere.net>
-- Raimon Grau <raimonNOSPAM3scale.net>
-- Ramkumar Ramachandra <artagnonNOSPAMgmail.com>
-- Remco van 't Veer <rwvtveerNOSPAMxs4all.nl>
-- Rémi Vanicat <vanicatNOSPAMdebian.org>
-- René Stadler <mailNOSPAMrenestadler.de>
-- Richard Kim <emacs18NOSPAMgmail.com>
-- Robert Boone <robo4288NOSPAMgmail.com>
-- Robin Green <greenrdNOSPAMgreenrd.org>
-- Roger Crew <crewNOSPAMcs.stanford.edu>
-- Romain Francoise <romainNOSPAMorebokech.com>
-- Ron Parker <rparkerNOSPAMa123systems.com>
-- Roy Crihfield <rscrihfNOSPAMgmail.com>
-- Rüdiger Sonderfeld <ruedigerNOSPAMc-plusplus.net>
-- Ryan C. Thompson <rctNOSPAMthompsonclan.org>
-- Samuel Bronson <naestenNOSPAMgmail.com>
-- Sanjoy Das <sanjoyNOSPAMplayingwithpointers.com>
-- Sean Bryant <sbryantNOSPAMhackinggibsons.com>
-- Sebastian Wiesner <lunaryornNOSPAMgmail.com>
-- Sébastien Gross <sebNOSPAMchezwam.org>
-- Seong-Kook Shin <cinskyNOSPAMgmail.com>
-- Sergey Pashinin <sergeyNOSPAMpashinin.com>
-- Sergey Vinokurov <serg.fooNOSPAMgmail.com>
-- Servilio Afre Puentes <afrepuesNOSPAMmcmaster.ca>
-- Štěpán Němec <stepnemNOSPAMgmail.com>
-- Steven Chow <steveNOSPAMmyfreestuffapp.com>
-- Steven E. Harris <sehNOSPAMpanix.com>
-- Steven Thomas <sthomas314NOSPAMgmail.com>
-- Steven Vancoillie <steven.vancoillieNOSPAMrunbox.com>
-- Steve Purcell <steveNOSPAMsanityinc.com>
-- Suhail Shergill <suhailshergillNOSPAMgmail.com>
-- Sylvain Rousseau <thisirsNOSPAMgmail.com>
-- Syohei Yoshida <syohexNOSPAMgmail.com>
-- Takafumi Arakaki <aka.tkfNOSPAMgmail.com>
-- Teemu Likonen <tlikonenNOSPAMiki.fi>
-- Teruki Shigitani <teruki.shigitaniNOSPAMgmail.com>
-- Thierry Volpiatto <thierry.volpiattoNOSPAMgmail.com>
-- Thomas A Caswell <tcaswellNOSPAMgmail.com>
-- Thomas Frössman <thomasfNOSPAMjossystem.se>
-- Thomas Jost <thomas.jostNOSPAMgmail.com>
-- Thomas Riccardi <riccardi.thomasNOSPAMgmail.com>
-- Tibor Simko <tibor.simkoNOSPAMcern.ch>
-- Timo Juhani Lindfors <timo.lindforsNOSPAMiki.fi>
-- Tim Perkins <tprk77NOSPAMgmail.com>
-- Tim Wraight <timNOSPAMwraight.net>
-- Ting-Yu Lin <aethanycNOSPAMgmail.com>
-- Tom Feist <shabbleNOSPAMmetavore.org>
-- Vineet Naik <vineetNOSPAMhelpshift.com>
-- Wei Huang <weihNOSPAMopera.com>
-- Wilfred Hughes <meNOSPAMwilfred.me.uk>
-- Win Treese <treeseNOSPAMacm.org>
-- Xavier Noria <fxnNOSPAMhashref.com>
-- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-- York Zhao <gtdplatformNOSPAMgmail.com>
-- Yuichi Higashi <aaa707bNOSPAMgmail.com>
-- Zach Latta <zachNOSPAMzachlatta.com>
+++ /dev/null
-
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-
+++ /dev/null
-This is the file .../info/dir, which contains the
-topmost node of the Info hierarchy, called (dir)Top.
-The first time you invoke Info you start off looking at this node.
-\1f
-File: dir, Node: Top This is the top of the INFO tree
-
- This (the Directory node) gives a menu of major topics.
- Typing "q" exits, "?" lists all Info commands, "d" returns here,
- "h" gives a primer for first-timers,
- "mEmacs<Return>" visits the Emacs manual, etc.
-
- In Emacs, you can click mouse button 2 on a menu item or cross reference
- to select it.
-
-* Menu:
-
-Emacs
-* Magit: (magit). Using Git from Emacs with Magit.
+++ /dev/null
-;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Phil Jackson <philNOSPAMshellarchive.co.uk>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; This file is not part of GNU Emacs.
-
-;; This file is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-
-;; This file is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this file. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This package assists the user in editing the list of commits to be
-;; rewritten during an interactive rebase.
-
-;; When the user initiates an interactive rebase, e.g. using "r e" in
-;; a Magit buffer or on the command line using "git rebase -i REV",
-;; Git invokes the `$GIT_SEQUENCE_EDITOR' (or if that is undefined
-;; `$GIT_EDITOR' or even `$EDITOR') letting the user rearrange, drop,
-;; reword, edit, and squash commits.
-
-;; This package provides the major-mode `git-rebase-mode' which makes
-;; doing so much more fun, by making the buffer more colorful and
-;; providing the following commands:
-;;
-;; C-c C-c Tell Git to make it happen.
-;; C-c C-k Tell Git that you changed your mind, i.e. abort.
-;;
-;; p Move point to previous line.
-;; n Move point to next line.
-;;
-;; M-p Move the commit at point up.
-;; M-n Move the commit at point down.
-;;
-;; k Drop the commit at point.
-;; c Don't drop the commit at point.
-;; r Change the message of the commit at point.
-;; e Edit the commit at point.
-;; s Squash the commit at point, into the one above.
-;; f Like "s" but don't also edit the commit message.
-;; x Add a script to be run with the commit at point
-;; being checked out.
-;;
-;; RET Show the commit at point in another buffer.
-;; C-/ Undo last change.
-
-;; You should probably also read the `git-rebase' manpage.
-
-;;; Code:
-
-(require 'dash)
-(require 'easymenu)
-(require 'server)
-(require 'with-editor)
-(require 'magit)
-
-(eval-when-compile (require 'recentf))
-
-;;; Options
-;;;; Variables
-
-(defgroup git-rebase nil
- "Edit Git rebase sequences."
- :group 'tools)
-
-(defcustom git-rebase-auto-advance t
- "Whether to move to next line after changing a line."
- :group 'git-rebase
- :type 'boolean)
-
-(defcustom git-rebase-show-instructions t
- "Whether to show usage instructions inside the rebase buffer."
- :group 'git-rebase
- :type 'boolean)
-
-(defcustom git-rebase-confirm-cancel t
- "Whether confirmation is required to cancel."
- :group 'git-rebase
- :type 'boolean)
-
-;;;; Faces
-
-(defgroup git-rebase-faces nil
- "Faces used by Git-Rebase mode."
- :group 'faces
- :group 'git-rebase)
-
-(defface git-rebase-hash
- '((((class color) (background light)) :foreground "grey60")
- (((class color) (background dark)) :foreground "grey40"))
- "Face for commit hashes."
- :group 'git-rebase-faces)
-
-(defface git-rebase-description nil
- "Face for commit descriptions."
- :group 'git-rebase-faces)
-
-(defface git-rebase-killed-action
- '((t (:inherit font-lock-comment-face :strike-through t)))
- "Face for commented action and exec lines."
- :group 'git-rebase-faces)
-
-;;; Keymaps
-
-(defvar git-rebase-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map special-mode-map)
- (define-key map (kbd "q") 'undefined)
- (define-key map [remap undo] 'git-rebase-undo)
- (define-key map (kbd "RET") 'git-rebase-show-commit)
- (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up)
- (define-key map (kbd "x") 'git-rebase-exec)
- (define-key map (kbd "c") 'git-rebase-pick)
- (define-key map (kbd "r") 'git-rebase-reword)
- (define-key map (kbd "w") 'git-rebase-reword)
- (define-key map (kbd "e") 'git-rebase-edit)
- (define-key map (kbd "s") 'git-rebase-squash)
- (define-key map (kbd "f") 'git-rebase-fixup)
- (define-key map (kbd "y") 'git-rebase-insert)
- (define-key map (kbd "k") 'git-rebase-kill-line)
- (define-key map (kbd "C-k") 'git-rebase-kill-line)
- (define-key map (kbd "p") 'git-rebase-backward-line)
- (define-key map (kbd "n") 'forward-line)
- (define-key map (kbd "M-p") 'git-rebase-move-line-up)
- (define-key map (kbd "M-n") 'git-rebase-move-line-down)
- (define-key map (kbd "M-<up>") 'git-rebase-move-line-up)
- (define-key map (kbd "M-<down>") 'git-rebase-move-line-down)
- (define-key map (kbd "C-x C-t") 'git-rebase-move-line-up)
- map)
- "Keymap for Git-Rebase mode.")
-
-(put 'git-rebase-reword :advertised-binding "r")
-(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p"))
-
-(easy-menu-define git-rebase-mode-menu git-rebase-mode-map
- "Git-Rebase mode menu"
- '("Rebase"
- ["Pick" git-rebase-pick t]
- ["Reword" git-rebase-reword t]
- ["Edit" git-rebase-edit t]
- ["Squash" git-rebase-squash t]
- ["Fixup" git-rebase-fixup t]
- ["Kill" git-rebase-kill-line t]
- ["Execute" git-rebase-exec t]
- ["Move Down" git-rebase-move-line-down t]
- ["Move Up" git-rebase-move-line-up t]
- "---"
- ["Cancel" with-editor-cancel t]
- ["Finish" with-editor-finish t]))
-
-(defvar git-rebase-command-descriptions
- '((with-editor-finish . "tell Git to make it happen")
- (with-editor-cancel . "tell Git that you changed your mind, i.e. abort")
- (previous-line . "move point to previous line")
- (next-line . "move point to next line")
- (git-rebase-move-line-up . "move the commit at point up")
- (git-rebase-move-line-down . "move the commit at point down")
- (git-rebase-show-commit . "show the commit at point in another buffer")
- (undo . "undo last change")
- (git-rebase-kill-line . "drop the commit at point")))
-
-;;; Commands
-
-(defun git-rebase-pick ()
- "Use commit on current line."
- (interactive)
- (git-rebase-set-action "pick"))
-
-(defun git-rebase-reword ()
- "Edit message of commit on current line."
- (interactive)
- (git-rebase-set-action "reword"))
-
-(defun git-rebase-edit ()
- "Stop at the commit on the current line."
- (interactive)
- (git-rebase-set-action "edit"))
-
-(defun git-rebase-squash ()
- "Meld commit on current line into previous commit, edit message."
- (interactive)
- (git-rebase-set-action "squash"))
-
-(defun git-rebase-fixup ()
- "Meld commit on current line into previous commit, discard its message."
- (interactive)
- (git-rebase-set-action "fixup"))
-
-(defconst git-rebase-line
- "^\\(#?\\(?:[fprse]\\|pick\\|reword\\|edit\\|squash\\|fixup\\|exec\\)\\) \
-\\(?:\\([^ \n]+\\) \\(.*\\)\\)?")
-
-(defun git-rebase-set-action (action)
- (goto-char (line-beginning-position))
- (if (and (looking-at git-rebase-line)
- (not (string-match-p "\\(e\\|exec\\)$" (match-string 1))))
- (let ((inhibit-read-only t))
- (replace-match action t t nil 1)
- (when git-rebase-auto-advance
- (forward-line)))
- (ding)))
-
-(defun git-rebase-line-p (&optional pos)
- (save-excursion
- (when pos (goto-char pos))
- (goto-char (line-beginning-position))
- (looking-at-p git-rebase-line)))
-
-(defun git-rebase-region-bounds ()
- (when (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))))))
-
-(defun git-rebase-move-line-down (n)
- "Move the current commit (or command) N lines down.
-If N is negative, move the commit up instead. With an active
-region, move all the lines that the region touches, not just the
-current line."
- (interactive "p")
- (-let* (((beg end) (or (git-rebase-region-bounds)
- (list (line-beginning-position)
- (1+ (line-end-position)))))
- (pt-offset (- (point) beg))
- (mark-offset (and mark-active (- (mark) beg))))
- (save-restriction
- (narrow-to-region
- (point-min)
- (1+ (save-excursion
- (goto-char (point-min))
- (while (re-search-forward git-rebase-line nil t))
- (point))))
- (if (or (and (< n 0) (= beg (point-min)))
- (and (> n 0) (= end (point-max)))
- (> end (point-max)))
- (ding)
- (goto-char (if (< n 0) beg end))
- (forward-line n)
- (atomic-change-group
- (let ((inhibit-read-only t))
- (insert (delete-and-extract-region beg end)))
- (let ((new-beg (- (point) (- end beg))))
- (when (use-region-p)
- (setq deactivate-mark nil)
- (set-mark (+ new-beg mark-offset)))
- (goto-char (+ new-beg pt-offset))))))))
-
-(defun git-rebase-move-line-up (n)
- "Move the current commit (or command) N lines up.
-If N is negative, move the commit down instead. With an active
-region, move all the lines that the region touches, not just the
-current line."
- (interactive "p")
- (git-rebase-move-line-down (- n)))
-
-(defun git-rebase-highlight-region (start end window rol)
- (let ((inhibit-read-only t)
- (deactivate-mark nil)
- (bounds (git-rebase-region-bounds)))
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (when bounds
- (magit-section-make-overlay (car bounds) (cadr bounds)
- 'magit-section-heading-selection))
- (if (and bounds (not magit-keep-region-overlay))
- (funcall (default-value 'redisplay-unhighlight-region-function) rol)
- (funcall (default-value 'redisplay-highlight-region-function)
- start end window rol))))
-
-(defun git-rebase-unhighlight-region (rol)
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (funcall (default-value 'redisplay-unhighlight-region-function) rol))
-
-(defun git-rebase-kill-line ()
- "Kill the current action line."
- (interactive)
- (goto-char (line-beginning-position))
- (when (and (looking-at git-rebase-line)
- (not (eq (char-after) ?#)))
- (let ((inhibit-read-only t))
- (insert ?#))
- (when git-rebase-auto-advance
- (forward-line))))
-
-(defun git-rebase-insert (rev)
- "Read an arbitrary commit and insert it below current line."
- (interactive (list (magit-read-branch-or-commit "Insert revision")))
- (forward-line)
- (--if-let (magit-rev-format "%h %s" rev)
- (let ((inhibit-read-only t))
- (insert "pick " it ?\n))
- (user-error "Unknown revision")))
-
-(defun git-rebase-exec (arg)
- "Insert a shell command to be run after the proceeding commit.
-
-If there already is such a command on the current line, then edit
-that instead. With a prefix argument insert a new command even
-when there already is one on the current line. With empty input
-remove the command on the current line, if any."
- (interactive "P")
- (let ((inhibit-read-only t) initial command)
- (unless arg
- (goto-char (line-beginning-position))
- (when (looking-at "^#?\\(e\\|exec\\) \\(.*\\)")
- (setq initial (match-string-no-properties 2))))
- (setq command (read-shell-command "Execute: " initial))
- (pcase (list command initial)
- (`("" nil) (ding))
- (`("" ,_)
- (delete-region (match-beginning 0) (1+ (match-end 0))))
- (`(,_ nil)
- (forward-line)
- (insert (concat "exec " command "\n"))
- (unless git-rebase-auto-advance
- (forward-line -1)))
- (_
- (replace-match (concat "exec " command) t t)
- (if git-rebase-auto-advance
- (forward-line)
- (goto-char (line-beginning-position)))))))
-
-(defun git-rebase-undo (&optional arg)
- "Undo some previous changes.
-Like `undo' but works in read-only buffers."
- (interactive "P")
- (let ((inhibit-read-only t))
- (undo arg)))
-
-(defun git-rebase-show-commit ()
- "Show the commit on the current line if any."
- (interactive)
- (save-excursion
- (goto-char (line-beginning-position))
- (--if-let (and (looking-at git-rebase-line)
- (match-string 2))
- (apply #'magit-show-commit it (magit-diff-arguments))
- (ding))))
-
-(defun git-rebase-backward-line (&optional n)
- "Move N lines backward (forward if N is negative).
-Like `forward-line' but go into the opposite direction."
- (interactive "p")
- (forward-line (- n)))
-
-;;; Mode
-
-;;;###autoload
-(define-derived-mode git-rebase-mode special-mode "Git Rebase"
- "Major mode for editing of a Git rebase file.
-
-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."
- :group 'git-rebase
- (setq font-lock-defaults '(git-rebase-mode-font-lock-keywords t t))
- (unless git-rebase-show-instructions
- (let ((inhibit-read-only t))
- (flush-lines "^\\($\\|#\\)")))
- (with-editor-mode 1)
- (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)
- (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))
-
-(defun git-rebase-cancel-confirm (force)
- (or (not (buffer-modified-p)) force (y-or-n-p "Abort this rebase? ")))
-
-(defun git-rebase-autostash-save ()
- (--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash"))
- (push (cons 'stash it) with-editor-cancel-alist)))
-
-(defun git-rebase-autostash-apply ()
- (--when-let (cdr (assq 'stash with-editor-cancel-alist))
- (magit-stash-apply it)))
-
-(defconst git-rebase-mode-font-lock-keywords
- `(("^\\([efprs]\\|pick\\|reword\\|edit\\|squash\\|fixup\\) \\([^ \n]+\\) \\(.*\\)"
- (1 'font-lock-keyword-face)
- (2 'git-rebase-hash)
- (3 'git-rebase-description))
- ("^\\(exec\\) \\(.*\\)"
- (1 'font-lock-keyword-face)
- (2 'git-rebase-description))
- ("^#.*" 0 'font-lock-comment-face)
- ("^#[^ \n].*" 0 'git-rebase-killed-action t))
- "Font lock keywords for Git-Rebase mode.")
-
-(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."
- (let ((inhibit-read-only t))
- (save-excursion
- (goto-char (point-min))
- (when (and git-rebase-show-instructions
- (re-search-forward "^# Commands:\n" nil t))
- (--each git-rebase-command-descriptions
- (insert (format "# %-8s %s\n"
- (substitute-command-keys (format "\\[%s]" (car it)))
- (cdr it))))
- (while (re-search-forward "^#\\( ?\\)\\([^,],\\) \\([^ ]+\\) = " nil t)
- (let ((cmd (intern (concat "git-rebase-" (match-string 3)))))
- (if (not (fboundp cmd))
- (delete-region (line-beginning-position) (1+ (line-end-position)))
- (replace-match " " t t nil 1)
- (replace-match
- (format "%-8s"
- (mapconcat #'key-description
- (--filter (not (eq (elt it 0) 'menu-bar))
- (reverse (where-is-internal cmd)))
- ", "))
- t t nil 2))))))))
-
-(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t)
-
-(defun git-rebase-mode-disable-before-save-hook ()
- (set (make-local-variable 'before-save-hook) nil))
-
-(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook)
-
-;;;###autoload
-(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
-;;;###autoload
-(add-to-list 'auto-mode-alist
- (cons git-rebase-filename-regexp 'git-rebase-mode))
-
-(add-to-list 'with-editor-server-window-alist
- (cons git-rebase-filename-regexp 'switch-to-buffer))
-
-(eval-after-load 'recentf
- '(add-to-list 'recentf-exclude git-rebase-filename-regexp))
-
-(provide 'git-rebase)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; git-rebase.el ends here
+++ /dev/null
-;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements commands for applying Git diffs or parts
-;; of such a diff. The supported "apply variants" are apply, stage,
-;; unstage, discard, and reverse - more than Git itself knows about,
-;; at least at the porcelain level.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-diff)
-(require 'magit-wip)
-
-;; For `magit-apply'
-(declare-function magit-anti-stage 'magit-rockstar)
-(declare-function magit-am-popup 'magit-sequence)
-;; For `magit-discard-files'
-(declare-function magit-checkout-stage 'magit)
-(declare-function magit-checkout-read-stage 'magit)
-(defvar auto-revert-verbose)
-
-(require 'dired)
-
-;;; Options
-
-(defcustom magit-delete-by-moving-to-trash t
- "Whether Magit uses the system's trash can."
- :package-version '(magit . "2.1.0")
- :group 'magit
- :type 'boolean)
-
-(defcustom magit-unstage-committed t
- "Whether unstaging a committed change reverts it instead.
-
-A committed change cannot be unstaged, because staging and
-unstaging are actions that are concern with the differences
-between the index and the working tree, not with committed
-changes.
-
-If this option is non-nil (the default), then typing \"u\"
-(`magit-unstage') on a committed change, causes it to be
-reversed in the index but not the working tree. For more
-information see command `magit-reverse-in-index'."
- :package-version '(magit . "2.4.1")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Commands
-;;;; Apply
-
-(defun magit-apply (&rest args)
- "Apply the change at point.
-With a prefix argument and if necessary, attempt a 3-way merge."
- (interactive (and current-prefix-arg (list "--3way")))
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(,(or `unstaged `staged) ,_)
- (user-error "Change is already in the working tree"))
- (`(untracked ,(or `file `files))
- (magit-am-popup))
- (`(,_ region) (magit-apply-region it args))
- (`(,_ hunk) (magit-apply-hunk it args))
- (`(,_ hunks) (magit-apply-hunks it args))
- (`(,_ file) (magit-apply-diff it args))
- (`(,_ files) (magit-apply-diffs it args)))))
-
-(defun magit-apply-diffs (sections &rest args)
- (setq sections (magit-apply--get-diffs sections))
- (magit-apply-patch sections args
- (mapconcat
- (lambda (s)
- (concat (magit-diff-file-header s)
- (buffer-substring (magit-section-content s)
- (magit-section-end s))))
- sections "")))
-
-(defun magit-apply-diff (section &rest args)
- (setq section (car (magit-apply--get-diffs (list section))))
- (magit-apply-patch section args
- (concat (magit-diff-file-header section)
- (buffer-substring (magit-section-content section)
- (magit-section-end section)))))
-
-(defun magit-apply-hunks (sections &rest args)
- (let ((section (magit-section-parent (car sections))))
- (when (string-match "^diff --cc" (magit-section-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch section args
- (concat (magit-section-diff-header section)
- (mapconcat
- (lambda (s)
- (buffer-substring (magit-section-start s)
- (magit-section-end s)))
- sections "")))))
-
-(defun magit-apply-hunk (section &rest args)
- (when (string-match "^diff --cc" (magit-section-parent-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch (magit-section-parent section) args
- (concat (magit-diff-file-header section)
- (buffer-substring (magit-section-start section)
- (magit-section-end section)))))
-
-(defun magit-apply-region (section &rest args)
- (unless (magit-diff-context-p)
- (user-error "Not enough context to apply region. Increase the context"))
- (when (string-match "^diff --cc" (magit-section-parent-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch (magit-section-parent section) args
- (concat (magit-diff-file-header section)
- (magit-diff-hunk-region-patch section args))))
-
-(defun magit-apply-patch (section:s args patch)
- (let* ((files (if (atom section:s)
- (list (magit-section-value section:s))
- (mapcar 'magit-section-value section:s)))
- (command (symbol-name this-command))
- (command (if (and command (string-match "^magit-\\([^-]+\\)" command))
- (match-string 1 command)
- "apply")))
- (when (and magit-wip-before-change-mode (not inhibit-magit-refresh))
- (magit-wip-commit-before-change files (concat " before " command)))
- (with-temp-buffer
- (insert patch)
- (magit-run-git-with-input
- "apply" args "-p0"
- (unless (magit-diff-context-p) "--unidiff-zero")
- "--ignore-space-change" "-"))
- (unless inhibit-magit-refresh
- (when magit-wip-after-apply-mode
- (magit-wip-commit-after-apply files (concat " after " command)))
- (magit-refresh))))
-
-(defun magit-apply--get-selection ()
- (or (magit-region-sections 'hunk 'file)
- (let ((section (magit-current-section)))
- (pcase (magit-section-type section)
- ((or `hunk `file) section)
- ((or `staged `unstaged `untracked
- `stashed-index `stashed-worktree `stashed-untracked)
- (magit-section-children section))
- (_ (user-error "Cannot apply this, it's not a change"))))))
-
-(defun magit-apply--get-diffs (sections)
- (magit-section-case
- ([file diffstat]
- (--map (or (magit-get-section
- (append `((file . ,(magit-section-value it)))
- (magit-section-ident magit-root-section)))
- (error "Cannot get required diff headers"))
- sections))
- (t sections)))
-
-;;;; Stage
-
-(defun magit-stage ()
- "Add the change at point to the staging area."
- (interactive)
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(untracked ,_) (magit-stage-untracked))
- (`(unstaged region) (magit-apply-region it "--cached"))
- (`(unstaged hunk) (magit-apply-hunk it "--cached"))
- (`(unstaged hunks) (magit-apply-hunks it "--cached"))
- (`(unstaged file) (magit-stage-1 "-u" (list (magit-section-value it))))
- (`(unstaged files) (magit-stage-1 "-u" (magit-region-values)))
- (`(unstaged list) (magit-stage-1 "-u"))
- (`(staged ,_) (user-error "Already staged"))
- (`(committed ,_) (user-error "Cannot stage committed changes"))
- (`(undefined ,_) (user-error "Cannot stage this change")))))
-
-;;;###autoload
-(defun magit-stage-file (file)
- "Stage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be staged. Otherwise stage the file at point without
-requiring confirmation."
- (interactive
- (let* ((atpoint (magit-section-when (file)))
- (current (magit-file-relative-name))
- (choices (nconc (magit-modified-files)
- (magit-untracked-files)))
- (default (car (member (or atpoint current) choices))))
- (list (if (or current-prefix-arg (not default))
- (magit-completing-read "Stage file" choices
- nil t nil nil default)
- default))))
- (magit-with-toplevel
- (magit-stage-1 nil (list file))))
-
-;;;###autoload
-(defun magit-stage-modified (&optional all)
- "Stage all changes to files modified in the worktree.
-Stage all new content of tracked files and remove tracked files
-that no longer exist in the working tree from the index also.
-With a prefix argument also stage previously untracked (but not
-ignored) files.
-\('git add --update|--all .')."
- (interactive (progn (unless (or (not (magit-anything-staged-p))
- (magit-confirm 'stage-all-changes))
- (user-error "Abort"))
- (list current-prefix-arg)))
- (magit-with-toplevel
- (magit-stage-1 (if all "--all" "-u"))))
-
-(defun magit-stage-1 (arg &optional files)
- (magit-wip-commit-before-change files " before stage")
- (magit-run-git "add" arg (if files (cons "--" files) "."))
- (when magit-auto-revert-mode
- (mapc #'magit-turn-on-auto-revert-mode-if-desired files))
- (magit-wip-commit-after-apply files " after stage"))
-
-(defun magit-stage-untracked ()
- (let* ((section (magit-current-section))
- (files (pcase (magit-diff-scope)
- (`file (list (magit-section-value section)))
- (`files (magit-region-values))
- (`list (magit-untracked-files))))
- plain repos)
- (dolist (file files)
- (if (magit-git-repo-p file t)
- (push file repos)
- (push file plain)))
- (magit-wip-commit-before-change files " before stage")
- (when plain
- (magit-run-git "add" "--" plain)
- (when magit-auto-revert-mode
- (mapc #'magit-turn-on-auto-revert-mode-if-desired plain)))
- (dolist (repo repos)
- (save-excursion
- (goto-char (magit-section-start
- (magit-get-section
- `((file . ,repo) (untracked) (status)))))
- (call-interactively 'magit-submodule-add)))
- (magit-wip-commit-after-apply files " after stage")))
-
-;;;; Unstage
-
-(defun magit-unstage ()
- "Remove the change at point from the staging area."
- (interactive)
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(untracked ,_) (user-error "Cannot unstage untracked changes"))
- (`(unstaged ,_) (user-error "Already unstaged"))
- (`(staged region) (magit-apply-region it "--reverse" "--cached"))
- (`(staged hunk) (magit-apply-hunk it "--reverse" "--cached"))
- (`(staged hunks) (magit-apply-hunks it "--reverse" "--cached"))
- (`(staged file) (magit-unstage-1 (list (magit-section-value it))))
- (`(staged files) (magit-unstage-1 (magit-region-values)))
- (`(staged list) (magit-unstage-all))
- (`(committed ,_) (if magit-unstage-committed
- (magit-reverse-in-index)
- (user-error "Cannot unstage committed changes")))
- (`(undefined ,_) (user-error "Cannot unstage this change")))))
-
-;;;###autoload
-(defun magit-unstage-file (file)
- "Unstage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be unstaged. Otherwise unstage the file at point
-without requiring confirmation."
- (interactive
- (let* ((atpoint (magit-section-when (file)))
- (current (magit-file-relative-name))
- (choices (magit-staged-files))
- (default (car (member (or atpoint current) choices))))
- (list (if (or current-prefix-arg (not default))
- (magit-completing-read "Unstage file" choices
- nil t nil nil default)
- default))))
- (magit-with-toplevel
- (magit-unstage-1 (list file))))
-
-(defun magit-unstage-1 (files)
- (magit-wip-commit-before-change files " before unstage")
- (if (magit-no-commit-p)
- (magit-run-git "rm" "--cached" "--" files)
- (magit-run-git "reset" "HEAD" "--" files))
- (magit-wip-commit-after-apply files " after unstage"))
-
-;;;###autoload
-(defun magit-unstage-all ()
- "Remove all changes from the staging area."
- (interactive)
- (when (or (and (not (magit-anything-unstaged-p))
- (not (magit-untracked-files)))
- (magit-confirm 'unstage-all-changes))
- (magit-wip-commit-before-change nil " before unstage")
- (magit-run-git "reset" "HEAD" "--")
- (magit-wip-commit-after-apply nil " after unstage")))
-
-;;;; Discard
-
-(defun magit-discard ()
- "Remove the change at point."
- (interactive)
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(committed ,_) (user-error "Cannot discard committed changes"))
- (`(undefined ,_) (user-error "Cannot discard this change"))
- (`(,_ region) (magit-discard-region it))
- (`(,_ hunk) (magit-discard-hunk it))
- (`(,_ hunks) (magit-discard-hunks it))
- (`(,_ file) (magit-discard-file it))
- (`(,_ files) (magit-discard-files it))
- (`(,_ list) (magit-discard-files it)))))
-
-(defun magit-discard-region (section)
- (when (magit-confirm 'discard "Discard region")
- (magit-discard-apply section 'magit-apply-region)))
-
-(defun magit-discard-hunk (section)
- (when (magit-confirm 'discard "Discard hunk")
- (magit-discard-apply section 'magit-apply-hunk)))
-
-(defun magit-discard-apply (section apply)
- (if (eq (magit-diff-type section) 'unstaged)
- (funcall apply section "--reverse")
- (if (magit-anything-unstaged-p
- nil (if (eq (magit-section-type section) 'file)
- (magit-section-value section)
- (magit-section-parent-value section)))
- (progn (let ((inhibit-magit-refresh t))
- (funcall apply section "--reverse" "--cached")
- (funcall apply section "--reverse"))
- (magit-refresh))
- (funcall apply section "--reverse" "--index"))))
-
-(defun magit-discard-hunks (sections)
- (when (magit-confirm 'discard
- (format "Discard %s 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)
- (let ((section (car sections)))
- (if (eq (magit-diff-type section) 'unstaged)
- (funcall apply sections "--reverse")
- (if (magit-anything-unstaged-p
- nil (if (eq (magit-section-type section) 'file)
- (magit-section-value section)
- (magit-section-parent-value section)))
- (progn (let ((inhibit-magit-refresh t))
- (funcall apply sections "--reverse" "--cached")
- (funcall apply sections "--reverse"))
- (magit-refresh))
- (funcall apply sections "--reverse" "--index")))))
-
-(defun magit-discard-file (section)
- (magit-discard-files (list section)))
-
-(defun magit-discard-files (sections)
- (let ((auto-revert-verbose nil)
- (type (magit-diff-type (car sections)))
- (status (magit-file-status))
- files delete resurrect rename discard discard-new resolve)
- (dolist (section sections)
- (let ((file (magit-section-value section)))
- (push file files)
- (pcase (cons (pcase type
- (`staged ?X)
- (`unstaged ?Y)
- (`untracked ?Z))
- (cddr (assoc file status)))
- (`(?Z) (--each (magit-untracked-files nil file)
- (push it delete)))
- ((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete))
- ((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete))
- ((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve))
- (`(,_ ?A ?A) (push file resolve))
- (`(?X ?M ,(or ? ?M ?D)) (push section discard))
- (`(?Y ,_ ?M ) (push section discard))
- (`(?X ?A ?M ) (push file discard-new))
- (`(?X ?C ?M ) (push file discard-new))
- (`(?X ?A ,(or ? ?D)) (push file delete))
- (`(?X ?C ,(or ? ?D)) (push file delete))
- (`(?X ?D ,(or ? ?M )) (push file resurrect))
- (`(?Y ,_ ?D ) (push file resurrect))
- (`(?X ?R ,(or ? ?M ?D)) (push file rename)))))
- (unwind-protect
- (let ((inhibit-magit-refresh t))
- (magit-wip-commit-before-change files " before discard")
- (when resolve
- (dolist (file (nreverse resolve))
- (magit-checkout-stage file (magit-checkout-read-stage file))))
- (magit-discard-files--resurrect (nreverse resurrect))
- (magit-discard-files--delete (nreverse delete) status)
- (magit-discard-files--rename (nreverse rename) status)
- (magit-discard-files--discard (nreverse discard)
- (nreverse discard-new))
- (magit-wip-commit-after-apply files " after discard"))
- (magit-refresh))))
-
-(defun magit-discard-files--resurrect (files)
- (when (magit-confirm-files 'resurrect files)
- (if (eq (magit-diff-type) 'staged)
- (magit-call-git "reset" "--" files)
- (magit-call-git "checkout" "--" files))))
-
-(defun magit-discard-files--delete (files status)
- (when (if magit-delete-by-moving-to-trash
- (magit-confirm-files 'trash files)
- (magit-confirm-files 'delete files))
- (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
- (dolist (file files)
- (if (memq (magit-diff-type) '(unstaged untracked))
- (dired-delete-file file dired-recursive-deletes
- magit-delete-by-moving-to-trash)
- (pcase (nth 3 (assoc file status))
- (? (delete-file file t)
- (magit-call-git "rm" "--cached" "--" file))
- (?M (let ((temp (magit-git-string "checkout-index" "--temp" file)))
- (string-match
- (format "\\(.+?\\)\t%s" (regexp-quote file)) temp)
- (rename-file (match-string 1 temp)
- (setq temp (concat file ".~{index}~")))
- (delete-file temp t))
- (magit-call-git "rm" "--cached" "--force" "--" file))
- (?D (magit-call-git "checkout" "--" file)
- (delete-file file t)
- (magit-call-git "rm" "--cached" "--force" "--" file))))))))
-
-(defun magit-discard-files--rename (files status)
- (when (magit-confirm 'rename "Undo rename %s" "Undo %i renames"
- (mapcar (lambda (file)
- (setq file (assoc file status))
- (format "%s -> %s" (cadr file) (car file)))
- files))
- (dolist (file files)
- (let ((orig (cadr (assoc file status))))
- (if (file-exists-p file)
- (magit-call-git "mv" file orig)
- (magit-call-git "rm" "--cached" "--" file)
- (magit-call-git "reset" "--" orig))))))
-
-(defun magit-discard-files--discard (sections new-files)
- (let ((files (mapcar #'magit-section-value sections)))
- (when (magit-confirm-files
- 'discard (append files new-files)
- (format "Discard %s changes in" (magit-diff-type)))
- (if (eq (magit-diff-type (car sections)) 'unstaged)
- (magit-call-git "checkout" "--" files)
- (when new-files
- (magit-call-git "add" "--" new-files)
- (magit-call-git "reset" "--" new-files))
- (let ((binaries (magit-staged-binary-files)))
- (when binaries
- (setq sections
- (--filter (not (member (magit-section-value it) binaries))
- sections)))
- (if (= (length sections) 1)
- (magit-discard-apply (car sections) 'magit-apply-diff)
- (magit-discard-apply-n sections 'magit-apply-diffs))
- (when binaries
- (let ((modified (magit-modified-files t)))
- (setq binaries (--separate (member it modified) binaries)))
- (when (cadr binaries)
- (magit-call-git "reset" "--" (cadr binaries)))
- (when (car binaries)
- (user-error
- (concat
- "Cannot discard staged changes to binary files, "
- "which also have unstaged changes. Unstage instead.")))))))))
-
-;;;; Reverse
-
-(defun magit-reverse (&rest args)
- "Reverse the change at point in the working tree."
- (interactive (and current-prefix-arg (list "--3way")))
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(untracked ,_) (user-error "Cannot reverse untracked changes"))
- (`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
- (`(,_ region) (magit-reverse-region it args))
- (`(,_ hunk) (magit-reverse-hunk it args))
- (`(,_ hunks) (magit-reverse-hunks it args))
- (`(,_ file) (magit-reverse-file it args))
- (`(,_ files) (magit-reverse-files it args))
- (`(,_ list) (magit-reverse-files it args)))))
-
-(defun magit-reverse-region (section args)
- (when (magit-confirm 'reverse "Reverse region")
- (apply 'magit-apply-region section "--reverse" args)))
-
-(defun magit-reverse-hunk (section args)
- (when (magit-confirm 'reverse "Reverse hunk")
- (apply 'magit-apply-hunk section "--reverse" args)))
-
-(defun magit-reverse-hunks (sections args)
- (when (magit-confirm 'reverse
- (format "Reverse %s hunks from %s"
- (length sections)
- (magit-section-parent-value (car sections))))
- (magit-apply-hunks sections "--reverse" args)))
-
-(defun magit-reverse-file (section args)
- (magit-reverse-files (list section) args))
-
-(defun magit-reverse-files (sections args)
- (-let [(binaries sections)
- (let ((bs (magit-staged-binary-files)))
- (--separate (member (magit-section-value it) bs) sections))]
- (when (magit-confirm-files 'reverse (mapcar #'magit-section-value sections))
- (if (= (length sections) 1)
- (magit-apply-diff (car sections) "--reverse" args)
- (magit-apply-diffs sections "--reverse" args)))
- (when binaries
- (user-error "Cannot reverse binary files"))))
-
-(defun magit-reverse-in-index (&rest args)
- "Reverse the change at point in the index but not the working tree.
-
-Use this command to extract a change from `HEAD', while leaving
-it in the working tree, so that it can later be committed using
-a separate commit. A typical workflow would be:
-
-0. Optionally make sure that there are no uncommitted changes.
-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.
-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\"
- and then type \"c c\" to create a new commit."
- (interactive)
- (magit-reverse (cons "--cached" args)))
-
-;;; magit-apply.el ends soon
-(provide 'magit-apply)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-apply.el ends here
+++ /dev/null
-;;; magit-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
-\f
-;;;### (autoloads nil "git-rebase" "git-rebase.el" (22216 31956 0
-;;;;;; 0))
-;;; Generated autoloads from git-rebase.el
-
-(autoload 'git-rebase-mode "git-rebase" "\
-Major mode for editing of a Git rebase file.
-
-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.
-
-\(fn)" t nil)
-
-(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
-
-(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp 'git-rebase-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "magit" "magit.el" (22216 31956 0 0))
-;;; Generated autoloads from magit.el
-
-(autoload 'magit-status "magit" "\
-Show the status of the current Git repository in a buffer.
-With a prefix argument prompt for a repository to be shown.
-With two prefix arguments prompt for an arbitrary directory.
-If that directory isn't the root of an existing repository
-then offer to initialize it as a new repository.
-
-\(fn &optional DIRECTORY)" t nil)
-
-(autoload 'magit-status-internal "magit" "\
-
-
-\(fn DIRECTORY)" nil nil)
- (autoload 'magit-show-refs-popup "magit" nil t)
-
-(autoload 'magit-show-refs-head "magit" "\
-List and compare references in a dedicated buffer.
-Refs are compared with `HEAD'.
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-show-refs-current "magit" "\
-List and compare references in a dedicated buffer.
-Refs are compared with the current branch or `HEAD' if
-it is detached.
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-show-refs "magit" "\
-List and compare references in a dedicated buffer.
-Refs are compared with a branch read form the user.
-
-\(fn &optional REF ARGS)" t nil)
-
-(autoload 'magit-find-file "magit" "\
-View FILE from REV.
-Switch to a buffer visiting blob REV:FILE,
-creating one if none already exists.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-find-file-other-window "magit" "\
-View FILE from REV, in another window.
-Like `magit-find-file', but create a new window or reuse an
-existing one.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-dired-jump "magit" "\
-Visit file at point using Dired.
-With a prefix argument, visit in other window. If there
-is no file at point then instead visit `default-directory'.
-
-\(fn &optional OTHER-WINDOW)" t nil)
-
-(autoload 'magit-checkout-file "magit" "\
-Checkout FILE from REV.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-init "magit" "\
-Initialize a Git repository, then show its status.
-
-If the directory is below an existing repository, then the user
-has to confirm that a new one should be created inside. If the
-directory is the root of the existing repository, then the user
-has to confirm that it should be reinitialized.
-
-Non-interactively DIRECTORY is (re-)initialized unconditionally.
-
-\(fn DIRECTORY)" t nil)
- (autoload 'magit-branch-popup "magit" nil t)
-
-(autoload 'magit-checkout "magit" "\
-Checkout REVISION, updating the index and the working tree.
-If REVISION is a local branch then that becomes the current
-branch. If it is something else then `HEAD' becomes detached.
-Checkout fails if the working tree or the staging area contain
-changes.
-
-\(git checkout REVISION).
-
-\(fn REVISION)" t nil)
-
-(autoload 'magit-branch "magit" "\
-Create BRANCH at branch or revision START-POINT.
-
-\(git branch [ARGS] BRANCH START-POINT).
-
-\(fn BRANCH START-POINT &optional ARGS)" t nil)
-
-(autoload 'magit-branch-and-checkout "magit" "\
-Create and checkout BRANCH at branch or revision START-POINT.
-
-\(git checkout [ARGS] -b BRANCH START-POINT).
-
-\(fn BRANCH START-POINT &optional ARGS)" t nil)
-
-(autoload 'magit-branch-spinoff "magit" "\
-Create new branch from the unpushed commits.
-
-Create and checkout a new branch starting at and tracking the
-current branch. That branch in turn is reset to the last commit
-it shares with its upstream. If the current branch has no
-upstream or no unpushed commits, then the new branch is created
-anyway and the previously current branch is not touched.
-
-This is useful to create a feature branch after work has already
-began on the old branch (likely but not necessarily \"master\").
-
-If the current branch is a member of the value of option
-`magit-branch-prefer-remote-upstream' (which see), then the
-current branch will be used as the starting point as usual, but
-the upstream of the starting-point may be used as the upstream
-of the new branch, instead of the starting-point itself.
-
-\(fn BRANCH &rest ARGS)" t nil)
-
-(autoload 'magit-branch-reset "magit" "\
-Reset a branch to the tip of another branch or any other commit.
-
-When the branch being reset is the current branch, then do a
-hard reset. If there are any uncommitted changes, then the user
-has to confirming the reset because those changes would be lost.
-
-This is useful when you have started work on a feature branch but
-realize it's all crap and want to start over.
-
-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.
-
-\(fn BRANCH TO &optional ARGS SET-UPSTREAM)" t nil)
-
-(autoload 'magit-branch-delete "magit" "\
-Delete one or multiple branches.
-If the region marks multiple branches, then offer to delete
-those, otherwise prompt for a single branch to be deleted,
-defaulting to the branch at point.
-
-\(fn BRANCHES &optional FORCE)" t nil)
-
-(autoload 'magit-branch-rename "magit" "\
-Rename branch OLD to NEW.
-With prefix, forces the rename even if NEW already exists.
-
-\(git branch -m|-M OLD NEW).
-
-\(fn OLD NEW &optional FORCE)" t nil)
-
-(autoload 'magit-edit-branch*description "magit" "\
-Edit the description of the current branch.
-With a prefix argument edit the description of another branch.
-
-The description for the branch named NAME is stored in the Git
-variable `branch.<name>.description'.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-set-branch*merge/remote "magit" "\
-Set or unset the upstream of the current branch.
-With a prefix argument do so for another branch.
-
-When the branch in question already has an upstream then simply
-unsets it. Invoke this command again to set another upstream.
-
-Together the Git variables `branch.<name>.remote' and
-`branch.<name>.merge' define the upstream branch of the local
-branch named NAME. The value of `branch.<name>.remote' is the
-name of the upstream remote. The value of `branch.<name>.merge'
-is the full reference of the upstream branch, on the remote.
-
-Non-interactively, when UPSTREAM is non-nil, then always set it
-as the new upstream, regardless of whether another upstream was
-already set. When nil, then always unset.
-
-\(fn BRANCH UPSTREAM)" t nil)
-
-(autoload 'magit-cycle-branch*rebase "magit" "\
-Cycle the value of `branch.<name>.rebase' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variables `branch.<name>.rebase' controls whether pulling
-into the branch named NAME is done by rebasing that branch onto
-the fetched branch or by merging that branch.
-
-When `true' then pulling is done by rebasing.
-When `false' then pulling is done by merging.
-
-When that variable is undefined then the value of `pull.rebase'
-is used instead. It defaults to `false'.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-cycle-branch*pushRemote "magit" "\
-Cycle the value of `branch.<name>.pushRemote' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variable `branch.<name>.pushRemote' specifies the remote
-that the branch named NAME is usually pushed to. The value has
-to be the name of an existing remote.
-
-If that variable is undefined, then the value of the Git variable
-`remote.pushDefault' is used instead, provided that it is defined,
-which by default it is not.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-cycle-pull\.rebase "magit" "\
-Cycle the repository-local value of `pull.rebase'.
-
-The Git variable `pull.rebase' specifies whether pulling is done
-by rebasing or by merging. It can be overwritten using the Git
-variable `branch.<name>.rebase'.
-
-When `true' then pulling is done by rebasing.
-When `false' (the default) then pulling is done by merging.
-
-\(fn)" t nil)
-
-(autoload 'magit-cycle-remote\.pushDefault "magit" "\
-Cycle the repository-local value of `remote.pushDefault'.
-
-The Git variable `remote.pushDefault' specifies the remote that
-local branches are usually pushed to. It can be overwritten
-using the Git variable `branch.<name>.pushRemote'.
-
-\(fn)" t nil)
-
-(autoload 'magit-cycle-branch*autoSetupMerge "magit" "\
-Cycle the repository-local value of `branch.autoSetupMerge'.
-
-The Git variable `branch.autoSetupMerge' under what circumstances
-creating a branch (named NAME) should result in the variables
-`branch.<name>.merge' and `branch.<name>.remote' being set
-according to the starting point used to create the branch. If
-the starting point isn't a branch, then these variables are never
-set.
-
-When `always' then the variables are set regardless of whether
-the starting point is a local or a remote branch.
-
-When `true' (the default) then the variable are set when the
-starting point is a remote branch, but not when it is a local
-branch.
-
-When `false' then the variables are never set.
-
-\(fn)" t nil)
-
-(autoload 'magit-cycle-branch*autoSetupRebase "magit" "\
-Cycle the repository-local value of `branch.autoSetupRebase'.
-
-The Git variable `branch.autoSetupRebase' specifies whether
-creating a branch (named NAME) should result in the variable
-`branch.<name>.rebase' being set to `true'.
-
-When `always' then the variable is set regardless of whether the
-starting point is a local or a remote branch.
-
-When `local' then the variable are set when the starting point
-is a local branch, but not when it is a remote branch.
-
-When `remote' then the variable are set when the starting point
-is a remote branch, but not when it is a local branch.
-
-When `never' (the default) then the variable is never set.
-
-\(fn)" t nil)
- (autoload 'magit-merge-popup "magit" nil t)
-
-(autoload 'magit-merge "magit" "\
-Merge commit REV into the current branch; using default message.
-
-Unless there are conflicts or a prefix argument is used create a
-merge commit using a generic commit message and without letting
-the user inspect the result. With a prefix argument pretend the
-merge failed to give the user the opportunity to inspect the
-merge.
-
-\(git merge --no-edit|--no-commit [ARGS] REV)
-
-\(fn REV &optional ARGS NOCOMMIT)" t nil)
-
-(autoload 'magit-merge-editmsg "magit" "\
-Merge commit REV into the current branch; and edit message.
-Perform the merge and prepare a commit message but let the user
-edit it.
-
-\(git merge --edit [ARGS] rev)
-
-\(fn REV &optional ARGS)" t nil)
-
-(autoload 'magit-merge-nocommit "magit" "\
-Merge commit REV into the current branch; pretending it failed.
-Pretend the merge failed to give the user the opportunity to
-inspect the merge and change the commit message.
-
-\(git merge --no-commit [ARGS] rev)
-
-\(fn REV &optional ARGS)" t nil)
-
-(autoload 'magit-merge-preview "magit" "\
-Preview result of merging REV into the current branch.
-
-\(fn REV)" t nil)
-
-(autoload 'magit-merge-abort "magit" "\
-Abort the current merge operation.
-
-\(git merge --abort)
-
-\(fn)" t nil)
-
-(autoload 'magit-reset-index "magit" "\
-Reset the index to COMMIT.
-Keep the head and working tree as-is, so if COMMIT refers to the
-head this effectively unstages all changes.
-
-\(git reset COMMIT)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset "magit" "\
-Reset the head and index to COMMIT, but not the working tree.
-With a prefix argument also reset the working tree.
-
-\(git reset --mixed|--hard COMMIT)
-
-\(fn COMMIT &optional HARD)" t nil)
-
-(autoload 'magit-reset-head "magit" "\
-Reset the head and index to COMMIT, but not the working tree.
-
-\(git reset --mixed COMMIT)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-soft "magit" "\
-Reset the head to COMMIT, but not the index and working tree.
-
-\(git reset --soft REVISION)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-hard "magit" "\
-Reset the head, index, and working tree to COMMIT.
-
-\(git reset --hard REVISION)
-
-\(fn COMMIT)" t nil)
- (autoload 'magit-tag-popup "magit" nil t)
-
-(autoload 'magit-tag "magit" "\
-Create a new tag with the given NAME at REV.
-With a prefix argument annotate the tag.
-
-\(git tag [--annotate] NAME REV)
-
-\(fn NAME REV &optional ARGS)" t nil)
-
-(autoload 'magit-tag-delete "magit" "\
-Delete one or more tags.
-If the region marks multiple tags (and nothing else), then offer
-to delete those, otherwise prompt for a single tag to be deleted,
-defaulting to the tag at point.
-
-\(git tag -d TAGS)
-
-\(fn TAGS)" t nil)
- (autoload 'magit-notes-popup "magit" nil t)
-
-(defvar global-magit-file-mode nil "\
-Non-nil if Global-Magit-File mode is enabled.
-See the command `global-magit-file-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `global-magit-file-mode'.")
-
-(custom-autoload 'global-magit-file-mode "magit" nil)
-
-(autoload 'global-magit-file-mode "magit" "\
-Toggle Magit-File mode in all buffers.
-With prefix ARG, enable Global-Magit-File mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Magit-File mode is enabled in all buffers where
-`magit-file-mode-turn-on' would do it.
-See `magit-file-mode' for more information on Magit-File mode.
-
-\(fn &optional ARG)" t nil)
- (autoload 'magit-dispatch-popup "magit" nil t)
- (autoload 'magit-run-popup "magit" nil t)
-
-(autoload 'magit-git-command "magit" "\
-Execute a Git subcommand asynchronously, displaying the output.
-With a prefix argument run Git in the root of the current
-repository, otherwise in `default-directory'.
-
-\(fn ARGS DIRECTORY)" t nil)
-
-(autoload 'magit-git-command-topdir "magit" "\
-Execute a Git subcommand asynchronously, displaying the output.
-Run Git in the top-level directory of the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-shell-command "magit" "\
-Execute a shell command asynchronously, displaying the output.
-With a prefix argument run the command in the root of the current
-repository, otherwise in `default-directory'.
-
-\(fn ARGS DIRECTORY)" t nil)
-
-(autoload 'magit-shell-command-topdir "magit" "\
-Execute a shell command asynchronously, displaying the output.
-Run the command in the top-level directory of the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-version "magit" "\
-Return the version of Magit currently in use.
-When called interactive also show the used versions of Magit,
-Git, and Emacs in the echo area.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-apply" "magit-apply.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-apply.el
-
-(autoload 'magit-stage-file "magit-apply" "\
-Stage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be staged. Otherwise stage the file at point without
-requiring confirmation.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-stage-modified "magit-apply" "\
-Stage all changes to files modified in the worktree.
-Stage all new content of tracked files and remove tracked files
-that no longer exist in the working tree from the index also.
-With a prefix argument also stage previously untracked (but not
-ignored) files.
-\('git add --update|--all .').
-
-\(fn &optional ALL)" t nil)
-
-(autoload 'magit-unstage-file "magit-apply" "\
-Unstage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be unstaged. Otherwise unstage the file at point
-without requiring confirmation.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-unstage-all "magit-apply" "\
-Remove all changes from the staging area.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-autorevert" "magit-autorevert.el" (22216
-;;;;;; 31956 0 0))
-;;; Generated autoloads from magit-autorevert.el
-
-(defvar magit-revert-buffers t)
-
-(defvar magit-auto-revert-mode (and (not global-auto-revert-mode) magit-revert-buffers) "\
-Non-nil if Magit-Auto-Revert mode is enabled.
-See the command `magit-auto-revert-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `magit-auto-revert-mode'.")
-
-(custom-autoload 'magit-auto-revert-mode "magit-autorevert" nil)
-
-(autoload 'magit-auto-revert-mode "magit-autorevert" "\
-Toggle Auto-Revert mode in all buffers.
-With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Auto-Revert mode is enabled in all buffers where
-`magit-turn-on-auto-revert-mode-if-desired' would do it.
-See `auto-revert-mode' for more information on Auto-Revert mode.
-
-\(fn &optional ARG)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-bisect" "magit-bisect.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-bisect.el
- (autoload 'magit-bisect-popup "magit-bisect" nil t)
-
-(autoload 'magit-bisect-start "magit-bisect" "\
-Start a bisect session.
-
-Bisecting a bug means to find the commit that introduced it.
-This command starts such a bisect session by asking for a know
-good and a bad commit. To move the session forward use the
-other actions from the bisect popup (\\<magit-status-mode-map>\\[magit-bisect-popup]).
-
-\(fn BAD GOOD)" t nil)
-
-(autoload 'magit-bisect-reset "magit-bisect" "\
-After bisecting, cleanup bisection state and return to original `HEAD'.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-good "magit-bisect" "\
-While bisecting, mark the current commit as good.
-Use this after you have asserted that the commit does not contain
-the bug in question.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-bad "magit-bisect" "\
-While bisecting, mark the current commit as bad.
-Use this after you have asserted that the commit does contain the
-bug in question.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-skip "magit-bisect" "\
-While bisecting, skip the current commit.
-Use this if for some reason the current commit is not a good one
-to test. This command lets Git choose a different one.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-run "magit-bisect" "\
-Bisect automatically by running commands after each step.
-
-Unlike `git bisect run' this can be used before bisecting has
-begun. In that case it behaves like `git bisect start; git
-bisect run'.
-
-\(fn CMDLINE &optional BAD GOOD)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-blame" "magit-blame.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-blame.el
- (autoload 'magit-blame-popup "magit-blame" nil t)
-
-(autoload 'magit-blame "magit-blame" "\
-Display edit history of FILE up to REVISION.
-
-Interactively blame the file being visited in the current buffer.
-If the buffer visits a revision of that file, then blame up to
-that revision, otherwise blame the file's full history, including
-uncommitted changes.
-
-If Magit-Blame mode is already turned on then blame recursively, by
-visiting REVISION:FILE (using `magit-find-file'), where revision
-is the revision before the revision that added the lines at
-point.
-
-ARGS is a list of additional arguments to pass to `git blame';
-only arguments available from `magit-blame-popup' should be used.
-
-\(fn REVISION FILE &optional ARGS)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-commit" "magit-commit.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-commit.el
-
-(autoload 'magit-commit "magit-commit" "\
-Create a new commit on HEAD.
-With a prefix argument amend to the commit at HEAD instead.
-
-\(git commit [--amend] ARGS)
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-commit-amend "magit-commit" "\
-Amend the last commit.
-
-\(git commit --amend ARGS)
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-commit-extend "magit-commit" "\
-Amend the last commit, without editing the 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.
-\(git commit
---amend --no-edit)
-
-\(fn &optional ARGS OVERRIDE-DATE)" t nil)
-
-(autoload 'magit-commit-reword "magit-commit" "\
-Reword the last commit, ignoring staged changes.
-
-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.
-
-\(git commit --amend --only)
-
-\(fn &optional ARGS OVERRIDE-DATE)" t nil)
-
-(autoload 'magit-commit-fixup "magit-commit" "\
-Create a fixup commit.
-
-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'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-squash "magit-commit" "\
-Create a squash commit, without editing the squash 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'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-augment "magit-commit" "\
-Create a squash commit, editing the squash 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'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-instant-fixup "magit-commit" "\
-Create a fixup commit targeting COMMIT and instantly rebase.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-instant-squash "magit-commit" "\
-Create a squash commit targeting COMMIT and instantly rebase.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-diff" "magit-diff.el" (22216 31956 0
-;;;;;; 0))
-;;; Generated autoloads from magit-diff.el
-
-(autoload 'magit-diff-dwim "magit-diff" "\
-Show changes for the thing at point.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff "magit-diff" "\
-Show differences between two commits.
-
-REV-OR-RANGE should be a range or a single revision. If it is a
-revision, then show changes in the working tree relative to that
-revision. If it is a range, but one side is omitted, then show
-changes relative to `HEAD'.
-
-If the region is active, use the revisions on the first and last
-line of the region as the two sides of the range. With a prefix
-argument, instead of diffing the revisions, choose a revision to
-view changes along, starting at the common ancestor of both
-revisions (i.e., use a \"...\" range).
-
-\(fn REV-OR-RANGE &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-working-tree "magit-diff" "\
-Show changes between the current working tree and the `HEAD' commit.
-With a prefix argument show changes between the working tree and
-a commit read from the minibuffer.
-
-\(fn &optional REV ARGS FILES)" t nil)
-
-(autoload 'magit-diff-staged "magit-diff" "\
-Show changes between the index and the `HEAD' commit.
-With a prefix argument show changes between the index and
-a commit read from the minibuffer.
-
-\(fn &optional REV ARGS FILES)" t nil)
-
-(autoload 'magit-diff-unstaged "magit-diff" "\
-Show changes between the working tree and the index.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-while-committing "magit-diff" "\
-While committing, show the changes that are about to be committed.
-While amending, invoking the command again toggles between
-showing just the new changes or all the changes that will
-be committed.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-paths "magit-diff" "\
-Show changes between any two files on disk.
-
-\(fn A B)" t nil)
-
-(autoload 'magit-show-commit "magit-diff" "\
-Show the revision at point.
-If there is no revision at point or with a prefix argument prompt
-for a revision.
-
-\(fn REV &optional ARGS FILES MODULE)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-ediff" "magit-ediff.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-ediff.el
- (autoload 'magit-ediff-popup "magit-ediff" nil t)
-
-(autoload 'magit-ediff-resolve "magit-ediff" "\
-Resolve outstanding conflicts in FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-In the rare event that you want to manually resolve all
-conflicts, including those already resolved by Git, use
-`ediff-merge-revisions-with-ancestor'.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-stage "magit-ediff" "\
-Stage and unstage changes to FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-compare "magit-ediff" "\
-Compare REVA:FILEA with REVB:FILEB using Ediff.
-
-FILEA and FILEB have to be relative to the top directory of the
-repository. If REVA or REVB is nil then this stands for the
-working tree state.
-
-If the region is active, use the revisions on the first and last
-line of the region. With a prefix argument, instead of diffing
-the revisions, choose a revision to view changes along, starting
-at the common ancestor of both revisions (i.e., use a \"...\"
-range).
-
-\(fn REVA REVB FILEA FILEB)" t nil)
-
-(autoload 'magit-ediff-dwim "magit-ediff" "\
-Compare, stage, or resolve using Ediff.
-This command tries to guess what file, and what commit or range
-the user wants to compare, stage, or resolve using Ediff. It
-might only be able to guess either the file, or range or commit,
-in which case the user is asked about the other. It might not
-always guess right, in which case the appropriate `magit-ediff-*'
-command has to be used explicitly. If it cannot read the user's
-mind at all, then it asks the user for a command to run.
-
-\(fn)" t nil)
-
-(autoload 'magit-ediff-show-staged "magit-ediff" "\
-Show staged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-unstaged "magit-ediff" "\
-Show unstaged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-working-tree "magit-ediff" "\
-Show changes between HEAD and working tree using Ediff.
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-commit "magit-ediff" "\
-Show changes introduced by COMMIT using Ediff.
-
-\(fn COMMIT)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-extras" "magit-extras.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-extras.el
-
-(autoload 'magit-run-git-gui "magit-extras" "\
-Run `git gui' for the current git repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-run-git-gui-blame "magit-extras" "\
-Run `git gui blame' on the given FILENAME and COMMIT.
-Interactively run it for the current file and the HEAD, with a
-prefix or when the current file cannot be determined let the user
-choose. When the current buffer is visiting FILENAME instruct
-blame to center around the line point is on.
-
-\(fn COMMIT FILENAME &optional LINENUM)" t nil)
-
-(autoload 'magit-run-gitk "magit-extras" "\
-Run `gitk' in the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-run-gitk-branches "magit-extras" "\
-Run `gitk --branches' in the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-run-gitk-all "magit-extras" "\
-Run `gitk --all' in the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-clean "magit-extras" "\
-Remove untracked files from the working tree.
-With a prefix argument also remove ignored files,
-with two prefix arguments remove ignored files only.
-
-\(git clean -f -d [-x|-X])
-
-\(fn &optional ARG)" t nil)
-
-(autoload 'magit-gitignore "magit-extras" "\
-Instruct Git to ignore FILE-OR-PATTERN.
-With a prefix argument only ignore locally.
-
-\(fn FILE-OR-PATTERN &optional LOCAL)" t nil)
-
-(autoload 'magit-gitignore-locally "magit-extras" "\
-Instruct Git to locally ignore FILE-OR-PATTERN.
-
-\(fn FILE-OR-PATTERN)" t nil)
-
-(autoload 'magit-add-change-log-entry "magit-extras" "\
-Find change log file and add date entry and item for current change.
-This differs from `add-change-log-entry' (which see) in that
-it acts on the current hunk in a Magit buffer instead of on
-a position in a file-visiting buffer.
-
-\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil)
-
-(autoload 'magit-add-change-log-entry-other-window "magit-extras" "\
-Find change log file in other window and add entry and item.
-This differs from `add-change-log-entry-other-window' (which see)
-in that it acts on the current hunk in a Magit buffer instead of
-on a position in a file-visiting buffer.
-
-\(fn &optional WHOAMI FILE-NAME)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-log" "magit-log.el" (22216 31956 0 0))
-;;; Generated autoloads from magit-log.el
-
-(autoload 'magit-log-current "magit-log" "\
-Show log for the current branch.
-When `HEAD' is detached or with a prefix argument show log for
-one or more revs read from the minibuffer.
-
-\(fn REVS &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log "magit-log" "\
-Show log for one or more revs read from the minibuffer.
-The user can input any revision or revisions separated by a
-space, or even ranges, but only branches and tags, and a
-representation of the commit at point, are available as
-completion candidates.
-
-\(fn REVS &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-head "magit-log" "\
-Show log for `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-branches "magit-log" "\
-Show log for all local branches and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-all-branches "magit-log" "\
-Show log for all local and remote branches and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-all "magit-log" "\
-Show log for all references and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-buffer-file "magit-log" "\
-Show log for the blob or file visited in the current buffer.
-With a prefix argument or when `--follow' is part of
-`magit-log-arguments', then follow renames.
-
-\(fn &optional FOLLOW BEG END)" t nil)
-
-(autoload 'magit-reflog-current "magit-log" "\
-Display the reflog of the current branch.
-
-\(fn)" t nil)
-
-(autoload 'magit-reflog "magit-log" "\
-Display the reflog of a branch.
-
-\(fn REF)" t nil)
-
-(autoload 'magit-reflog-head "magit-log" "\
-Display the `HEAD' reflog.
-
-\(fn)" t nil)
-
-(autoload 'magit-cherry "magit-log" "\
-Show commits in a branch that are not merged in the upstream branch.
-
-\(fn HEAD UPSTREAM)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-remote" "magit-remote.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-remote.el
-
-(autoload 'magit-clone "magit-remote" "\
-Clone the REPOSITORY to DIRECTORY.
-Then show the status buffer for the new repository.
-
-\(fn REPOSITORY DIRECTORY)" t nil)
- (autoload 'magit-remote-popup "magit-remote" nil t)
-
-(autoload 'magit-remote-add "magit-remote" "\
-Add a remote named REMOTE and fetch it.
-
-\(fn REMOTE URL)" t nil)
-
-(autoload 'magit-remote-rename "magit-remote" "\
-Rename the remote named OLD to NEW.
-
-\(fn OLD NEW)" t nil)
-
-(autoload 'magit-remote-set-url "magit-remote" "\
-Change the url of the remote named REMOTE to URL.
-
-\(fn REMOTE URL)" t nil)
-
-(autoload 'magit-remote-remove "magit-remote" "\
-Delete the remote named REMOTE.
-
-\(fn REMOTE)" t nil)
-
-(autoload 'magit-remote-set-head "magit-remote" "\
-Set the local representation of REMOTE's default branch.
-Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
-accordingly. With a prefix argument query for the branch to be
-used, which allows you to select an incorrect value if you fancy
-doing that.
-
-\(fn REMOTE &optional BRANCH)" t nil)
-
-(autoload 'magit-remote-unset-head "magit-remote" "\
-Unset the local representation of REMOTE's default branch.
-Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\".
-
-\(fn REMOTE)" t nil)
- (autoload 'magit-fetch-popup "magit-remote" nil t)
-
-(autoload 'magit-fetch-from-pushremote "magit-remote" "\
-Fetch from the push-remote of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-fetch-from-upstream "magit-remote" "\
-Fetch from the upstream repository of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-fetch "magit-remote" "\
-Fetch from another repository.
-
-\(fn REMOTE ARGS)" t nil)
-
-(autoload 'magit-fetch-all "magit-remote" "\
-Fetch from all remotes.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-fetch-all-prune "magit-remote" "\
-Fetch from all remotes, and prune.
-Prune remote tracking branches for branches that have been
-removed on the respective remote.
-
-\(fn)" t nil)
-
-(autoload 'magit-fetch-all-no-prune "magit-remote" "\
-Fetch from all remotes.
-
-\(fn)" t nil)
- (autoload 'magit-pull-popup "magit-remote" nil t)
- (autoload 'magit-pull-and-fetch-popup "magit-remote" nil t)
-
-(autoload 'magit-pull-from-pushremote "magit-remote" "\
-Pull from the push-remote of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-pull-from-upstream "magit-remote" "\
-Pull from the upstream of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-pull "magit-remote" "\
-Pull from a branch read in the minibuffer.
-
-\(fn SOURCE ARGS)" t nil)
- (autoload 'magit-push-popup "magit-remote" nil t)
-
-(autoload 'magit-push-current-to-pushremote "magit-remote" "\
-Push the current branch to `branch.<name>.pushRemote'.
-If that variable is unset, then push to `remote.pushDefault'.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the push-remote is not configured, then read the push-remote from
-the user, set it, and then push to it. With a prefix argument
-the push-remote can be changed before pushed to it.
-
-\(fn ARGS &optional PUSH-REMOTE)" t nil)
-
-(autoload 'magit-push-current-to-upstream "magit-remote" "\
-Push the current branch to its upstream branch.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the upstream is not configured, then read the upstream from the
-user, set it, and then push to it. With a prefix argument the
-upstream can be changed before pushed to it.
-
-\(fn ARGS &optional UPSTREAM)" t nil)
-
-(autoload 'magit-push-current "magit-remote" "\
-Push the current branch to a branch read in the minibuffer.
-
-\(fn TARGET ARGS)" t nil)
-
-(autoload 'magit-push "magit-remote" "\
-Push an arbitrary branch or commit somewhere.
-Both the source and the target are read in the minibuffer.
-
-\(fn SOURCE TARGET ARGS)" t nil)
-
-(autoload 'magit-push-matching "magit-remote" "\
-Push all matching branches to another repository.
-If multiple remotes exist, then read one from the user.
-If just one exists, use that without requiring confirmation.
-
-\(fn REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-tags "magit-remote" "\
-Push all tags to another repository.
-If only one remote exists, then push to that. Otherwise prompt
-for a remote, offering the remote configured for the current
-branch as default.
-
-\(fn REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-tag "magit-remote" "\
-Push a tag to another repository.
-
-\(fn TAG REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-implicitly "magit-remote" "\
-Push somewhere without using an explicit refspec.
-
-This command simply runs \"git push -v [ARGS]\". ARGS are the
-arguments specified in the popup buffer. No explicit refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?P
- 'magit-push-implicitly--desc
- 'magit-push-implicitly ?p t))
-
-The function `magit-push-implicitly--desc' attempts to predict
-what this command will do, the value it returns is displayed in
-the popup buffer.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-push-to-remote "magit-remote" "\
-Push to REMOTE without using an explicit refspec.
-The REMOTE is read in the minibuffer.
-
-This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
-are the arguments specified in the popup buffer. No refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?r
- 'magit-push-to-remote--desc
- 'magit-push-to-remote ?p t))
-
-\(fn REMOTE ARGS)" t nil)
- (autoload 'magit-patch-popup "magit-remote" nil t)
-
-(autoload 'magit-format-patch "magit-remote" "\
-Create patches for the commits in RANGE.
-When a single commit is given for RANGE, create a patch for the
-changes introduced by that commit (unlike 'git format-patch'
-which creates patches for all commits that are reachable from
-HEAD but not from the specified commit).
-
-\(fn RANGE ARGS)" t nil)
-
-(autoload 'magit-request-pull "magit-remote" "\
-Request upstream to pull from you public repository.
-
-URL is the url of your publically accessible repository.
-START is a commit that already is in the upstream repository.
-END is the last commit, usually a branch name, which upstream
-is asked to pull. START has to be reachable from that commit.
-
-\(fn URL START END)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-sequence" "magit-sequence.el" (22216
-;;;;;; 31956 0 0))
-;;; Generated autoloads from magit-sequence.el
-
-(autoload 'magit-sequencer-continue "magit-sequence" "\
-Resume the current cherry-pick or revert sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-sequencer-skip "magit-sequence" "\
-Skip the stopped at commit during a cherry-pick or revert sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-sequencer-abort "magit-sequence" "\
-Abort the current cherry-pick or revert sequence.
-This discards all changes made since the sequence started.
-
-\(fn)" t nil)
- (autoload 'magit-cherry-pick-popup "magit-sequence" nil t)
-
-(autoload 'magit-cherry-pick "magit-sequence" "\
-Cherry-pick COMMIT.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then pick all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
-
-(autoload 'magit-cherry-apply "magit-sequence" "\
-Apply the changes in COMMIT but do not commit them.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then apply all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
- (autoload 'magit-revert-popup "magit-sequence" nil t)
-
-(autoload 'magit-revert "magit-sequence" "\
-Revert COMMIT by creating a new commit.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
-
-(autoload 'magit-revert-no-commit "magit-sequence" "\
-Revert COMMIT by applying it in reverse to the worktree.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
- (autoload 'magit-am-popup "magit-sequence" nil t)
-
-(autoload 'magit-am-apply-patches "magit-sequence" "\
-Apply the patches FILES.
-
-\(fn &optional FILES ARGS)" t nil)
-
-(autoload 'magit-am-apply-maildir "magit-sequence" "\
-Apply the patches from MAILDIR.
-
-\(fn &optional MAILDIR ARGS)" t nil)
-
-(autoload 'magit-am-continue "magit-sequence" "\
-Resume the current patch applying sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-am-skip "magit-sequence" "\
-Skip the stopped at patch during a patch applying sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-am-abort "magit-sequence" "\
-Abort the current patch applying sequence.
-This discards all changes made since the sequence started.
-
-\(fn)" t nil)
- (autoload 'magit-rebase-popup "magit-sequence" nil t)
-
-(autoload 'magit-rebase-onto-pushremote "magit-sequence" "\
-Rebase the current branch onto `branch.<name>.pushRemote'.
-If that variable is unset, then rebase onto `remote.pushDefault'.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-rebase-onto-upstream "magit-sequence" "\
-Rebase the current branch onto its upstream branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-rebase "magit-sequence" "\
-Rebase the current branch onto a branch read in the minibuffer.
-All commits that are reachable from head but not from the
-selected branch TARGET are being rebased.
-
-\(fn TARGET ARGS)" t nil)
-
-(autoload 'magit-rebase-subset "magit-sequence" "\
-Rebase a subset of the current branches history onto a new base.
-Rebase commits from START to `HEAD' onto NEWBASE.
-START has to be selected from a list of recent commits.
-
-\(fn NEWBASE START ARGS)" t nil)
-
-(autoload 'magit-rebase-interactive "magit-sequence" "\
-Start an interactive rebase sequence.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-autosquash "magit-sequence" "\
-Combine squash and fixup commits with their intended targets.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-rebase-edit-commit "magit-sequence" "\
-Edit a single older commit using rebase.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-reword-commit "magit-sequence" "\
-Reword a single older commit using rebase.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-continue "magit-sequence" "\
-Restart the current rebasing operation.
-
-\(fn)" t nil)
-
-(autoload 'magit-rebase-skip "magit-sequence" "\
-Skip the current commit and restart the current rebase operation.
-
-\(fn)" t nil)
-
-(autoload 'magit-rebase-edit "magit-sequence" "\
-Edit the todo list of the current rebase operation.
-
-\(fn)" t nil)
-
-(autoload 'magit-rebase-abort "magit-sequence" "\
-Abort the current rebase operation, restoring the original branch.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-stash" "magit-stash.el" (22216 31956
-;;;;;; 0 0))
-;;; Generated autoloads from magit-stash.el
- (autoload 'magit-stash-popup "magit-stash" nil t)
-
-(autoload 'magit-stash "magit-stash" "\
-Create a stash of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-index "magit-stash" "\
-Create a stash of the index only.
-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.
-
-\(fn MESSAGE)" t nil)
-
-(autoload 'magit-stash-worktree "magit-stash" "\
-Create a stash of the working tree only.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-keep-index "magit-stash" "\
-Create a stash of the index and working tree, keeping index intact.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-snapshot "magit-stash" "\
-Create a snapshot of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-snapshot-index "magit-stash" "\
-Create a snapshot of the index only.
-Unstaged and untracked changes are not stashed.
-
-\(fn)" t nil)
-
-(autoload 'magit-snapshot-worktree "magit-stash" "\
-Create a snapshot of the working tree only.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-apply "magit-stash" "\
-Apply a stash to the working tree.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index.
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-drop "magit-stash" "\
-Remove a stash from the stash list.
-When the region is active offer to drop all contained stashes.
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-clear "magit-stash" "\
-Remove all stashes saved in REF's reflog by deleting REF.
-
-\(fn REF)" t nil)
-
-(autoload 'magit-stash-branch "magit-stash" "\
-Create and checkout a new BRANCH from STASH.
-
-\(fn STASH BRANCH)" t nil)
-
-(autoload 'magit-stash-format-patch "magit-stash" "\
-Create a patch from STASH
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-list "magit-stash" "\
-List all stashes in a buffer.
-
-\(fn)" t nil)
-
-(autoload 'magit-stash-show "magit-stash" "\
-Show all diffs of a stash in a buffer.
-
-\(fn STASH &optional ARGS FILES)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-submodule" "magit-submodule.el" (22216
-;;;;;; 31956 0 0))
-;;; Generated autoloads from magit-submodule.el
- (autoload 'magit-submodule-popup "magit-submodule" nil t)
-
-(autoload 'magit-submodule-add "magit-submodule" "\
-Add the repository at URL as a submodule.
-Optional PATH is the path to the submodule relative to the root
-of the superproject. If it is nil then the path is determined
-based on URL.
-
-\(fn URL &optional PATH)" t nil)
-
-(autoload 'magit-submodule-setup "magit-submodule" "\
-Clone and register missing submodules and checkout appropriate commits.
-
-\(fn)" t nil)
-
-(autoload 'magit-submodule-init "magit-submodule" "\
-Register submodules listed in \".gitmodules\" into \".git/config\".
-
-\(fn)" t nil)
-
-(autoload 'magit-submodule-update "magit-submodule" "\
-Clone missing submodules and checkout appropriate commits.
-With a prefix argument also register submodules in \".git/config\".
-
-\(fn &optional INIT)" t nil)
-
-(autoload 'magit-submodule-sync "magit-submodule" "\
-Update each submodule's remote URL according to \".gitmodules\".
-
-\(fn)" t nil)
-
-(autoload 'magit-submodule-fetch "magit-submodule" "\
-Fetch all submodules.
-With a prefix argument fetch all remotes.
-
-\(fn &optional ALL)" t nil)
-
-(autoload 'magit-submodule-deinit "magit-submodule" "\
-Unregister the submodule at PATH.
-
-\(fn PATH)" t nil)
-
-(autoload 'magit-insert-submodule-commits "magit-submodule" "\
-For internal use, don't add to a hook.
-
-\(fn SECTION RANGE)" nil nil)
-
-(autoload 'magit-insert-unpulled-module-commits "magit-submodule" "\
-Insert sections for all submodules with unpulled commits.
-These sections can be expanded to show the respective commits.
-
-\(fn)" nil nil)
-
-(autoload 'magit-insert-unpushed-module-commits "magit-submodule" "\
-Insert sections for all submodules with unpushed commits.
-These sections can be expanded to show the respective commits.
-
-\(fn)" nil nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-wip" "magit-wip.el" (22216 31956 0 0))
-;;; Generated autoloads from magit-wip.el
-
-(defvar magit-wip-after-save-mode nil "\
-Non-nil if Magit-Wip-After-Save mode is enabled.
-See the command `magit-wip-after-save-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `magit-wip-after-save-mode'.")
-
-(custom-autoload 'magit-wip-after-save-mode "magit-wip" nil)
-
-(autoload 'magit-wip-after-save-mode "magit-wip" "\
-Toggle Magit-Wip-After-Save-Local mode in all buffers.
-With prefix ARG, enable Magit-Wip-After-Save mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Magit-Wip-After-Save-Local mode is enabled in all buffers where
-`magit-wip-after-save-local-mode-turn-on' would do it.
-See `magit-wip-after-save-local-mode' for more information on Magit-Wip-After-Save-Local mode.
-
-\(fn &optional ARG)" t nil)
-
-(defvar magit-wip-after-apply-mode nil "\
-Non-nil if Magit-Wip-After-Apply mode is enabled.
-See the command `magit-wip-after-apply-mode' for a description of this minor mode.")
-
-(custom-autoload 'magit-wip-after-apply-mode "magit-wip" nil)
-
-(autoload 'magit-wip-after-apply-mode "magit-wip" "\
-Commit to work-in-progress refs.
-
-After applying a change using any \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected files to the current wip refs. For each branch there
-may be two wip refs; one contains snapshots of the files as found
-in the worktree and the other contains snapshots of the entries
-in the index.
-
-\(fn &optional ARG)" t nil)
-
-(defvar magit-wip-before-change-mode nil "\
-Non-nil if Magit-Wip-Before-Change mode is enabled.
-See the command `magit-wip-before-change-mode' for a description of this minor mode.")
-
-(custom-autoload 'magit-wip-before-change-mode "magit-wip" nil)
-
-(autoload 'magit-wip-before-change-mode "magit-wip" "\
-Commit to work-in-progress refs before certain destructive changes.
-
-Before invoking a revert command or an \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected tracked files to the current wip refs. For each branch
-there may be two wip refs; one contains snapshots of the files
-as found in the worktree and the other contains snapshots of the
-entries in the index.
-
-Only changes to files which could potentially be affected by the
-command which is about to be called are committed.
-
-\(fn &optional ARG)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil nil ("magit-core.el" "magit-git.el" "magit-mode.el"
-;;;;;; "magit-pkg.el" "magit-process.el" "magit-section.el" "magit-utils.el")
-;;;;;; (22216 31956 166032 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; End:
-;;; magit-autoloads.el ends here
+++ /dev/null
-;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-git)
-
-(require 'autorevert)
-
-(defgroup magit-auto-revert nil
- "Revert buffers when files in repository change."
- :group 'auto-revert
- :group 'magit-extensions)
-
-(defcustom auto-revert-buffer-list-filter nil
- "Filter that determines which buffers `auto-revert-buffers' reverts.
-
-This option is provided by `magit', which also redefines
-`auto-revert-buffers' to respect it. Magit users who do not turn
-on the local mode `auto-revert-mode' themselves, are best served
-by setting the value to `magit-auto-revert-repository-buffers-p'.
-
-However the default is nil, to not disturb users who do use the
-local mode directly. If you experience delays when running Magit
-commands, then you should consider using one of the predicates
-provided by Magit - especially if you also use Tramp.
-
-Users who do turn on `auto-revert-mode' in buffers in which Magit
-doesn't do that for them, should likely not use any filter.
-Users who turn on `global-auto-revert-mode', do not have to worry
-about this option, because it is disregarded if the global mode
-is enabled."
- :package-version '(magit . "2.4.2")
- :group 'auto-revert
- :group 'magit-auto-revert
- :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
- "Whether `magit-auto-revert-mode' only reverts tracked files."
- :package-version '(magit . "2.4.0")
- :group 'magit-auto-revert
- :type 'boolean
- :set (lambda (var val)
- (set var val)
- (when (and (bound-and-true-p magit-auto-revert-mode)
- (featurep 'magit-autorevert))
- (magit-auto-revert-mode -1)
- (magit-auto-revert-mode))))
-
-(defcustom magit-auto-revert-immediately t
- "Whether Magit reverts buffers immediately.
-
-If this is non-nil and either `global-auto-revert-mode' or
-`magit-auto-revert-mode' is enabled, then Magit immediately
-reverts buffers by explicitly calling `auto-revert-buffers'
-after running git for side-effects.
-
-If `auto-revert-use-notify' is non-nil (and file notifications
-are actually supported), then `magit-auto-revert-immediately'
-does not have to be non-nil, because the reverts happen
-immediately anyway.
-
-If `magit-auto-revert-immediately' and `auto-revert-use-notify'
-are both nil, then reverts happen after `auto-revert-interval'
-seconds of user inactivity. That is not desirable."
- :package-version '(magit . "2.4.0")
- :group 'magit-auto-revert
- :type 'boolean)
-
-(defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
- (if file
- (--when-let (find-buffer-visiting file)
- (with-current-buffer it
- (magit-turn-on-auto-revert-mode-if-desired)))
- (when (and buffer-file-name
- (file-readable-p buffer-file-name)
- (magit-toplevel)
- (or (not magit-auto-revert-tracked-only)
- (magit-file-tracked-p buffer-file-name)))
- (auto-revert-mode))))
-
-;;;###autoload
-(defvar magit-revert-buffers t)
-(make-obsolete-variable 'magit-revert-buffers 'magit-auto-revert-mode
- "Magit 2.4.0")
-
-;;;###autoload
-(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
- magit-turn-on-auto-revert-mode-if-desired
- :package-version '(magit . "2.4.0")
- :group 'magit
- :group 'magit-auto-revert
- ;; When `global-auto-revert-mode' is enabled, then this mode is
- ;; redundant. When `magit-revert-buffers' is nil, then the user has
- ;; opted out of the automatic reverts while the old implementation
- ;; was still in use. In all other cases enable the mode because if
- ;; buffers are not automatically reverted that would make many very
- ;; common tasks much more cumbersome.
- :init-value (and (not global-auto-revert-mode) magit-revert-buffers))
-
-;; `:init-value t' only sets the value of the mode variable
-;; but does not cause the mode function to be called.
-(cl-eval-when (load eval)
- (when magit-auto-revert-mode
- (magit-auto-revert-mode)))
-
-;; If the user has set the obsolete `magit-revert-buffers' to nil
-;; after loading magit, then we should still respect that setting.
-(defun magit-auto-revert-mode--maybe-turn-off-after-init ()
- (unless magit-revert-buffers
- (magit-auto-revert-mode -1)))
-(unless after-init-time
- (add-hook 'after-init-hook
- #'magit-auto-revert-mode--maybe-turn-off-after-init t))
-
-(put 'magit-auto-revert-mode 'function-documentation
- "Toggle Magit Auto Revert mode.
-With a prefix argument ARG, enable Magit Auto Revert mode if ARG
-is positive, and disable it otherwise. If called from Lisp,
-enable the mode if ARG is omitted or nil.
-
-Magit Auto Revert mode is a global minor mode that reverts
-buffers associated with a file that is located inside a Git
-repository when the file changes on disk. Use `auto-revert-mode'
-to revert a particular buffer. Or use `global-auto-revert-mode'
-to revert all file-visiting buffers, not just those that visit
-a file located inside a Git repository.
-
-This global mode works by turning on the buffer-local mode
-`auto-revert-mode' at the time a buffer is first created. The
-local mode is turned on if the visited file is being tracked in
-a Git repository at the time when the buffer is created.
-
-If `magit-auto-revert-tracked-only' is non-nil (the default),
-then only tracked files are reverted. But if you stage a
-previously untracked file using `magit-stage', then this mode
-notices that.
-
-Unlike `global-auto-revert-mode', this mode never reverts any
-buffers that are not visiting files.
-
-The behavior of this mode can be customized using the options
-in the `autorevert' and `magit-autorevert' groups.
-
-This function calls the hook `magit-auto-revert-mode-hook'.")
-
-(defun magit-auto-revert-buffers ()
- (when (and magit-auto-revert-immediately
- (or global-auto-revert-mode
- (and magit-auto-revert-mode auto-revert-buffer-list)))
- (let ((auto-revert-buffer-list-filter
- (or auto-revert-buffer-list-filter
- 'magit-auto-revert-repository-buffer-p)))
- (auto-revert-buffers))))
-
-(defvar magit-auto-revert-toplevel nil)
-
-(when (< emacs-major-version 25)
- (defvar auto-revert-buffers-counter 1
- "Incremented each time `auto-revert-buffers' is called"))
-
-(defun magit-auto-revert-buffer-p (buffer)
- "Return t if BUFFER visits a file inside the current repository.
-The current repository is the one in which `default-directory' is
-located. If there is no current repository, then return t for
-any BUFFER."
- (magit-auto-revert-repository-buffer-p buffer t))
-
-(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback)
- "Return t if BUFFER visits a file inside the current repository.
-The current repository is the one in which `default-directory' is
-located. If there is no current repository, then return FALLBACK
-\(which defaults to nil) for any BUFFER."
- ;; Call `magit-toplevel' just once per cycle.
- (unless (and magit-auto-revert-toplevel
- (= (cdr magit-auto-revert-toplevel)
- auto-revert-buffers-counter))
- (setq magit-auto-revert-toplevel
- (cons (or (magit-toplevel) 'no-repo)
- auto-revert-buffers-counter)))
- (let ((top (car magit-auto-revert-toplevel)))
- (if (eq top 'no-repo)
- fallback
- (let ((dir (with-current-buffer buffer default-directory)))
- (and (equal (file-remote-p dir)
- (file-remote-p top))
- ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
- (file-in-directory-p dir top))))))
-
-(defun auto-revert-buffers--buffer-list-filter ()
- (when (< emacs-major-version 25)
- (cl-incf auto-revert-buffers-counter))
- (when auto-revert-buffer-list-filter
- (setq auto-revert-buffer-list
- (--filter auto-revert-buffer-list-filter
- auto-revert-buffer-list))))
-
-(advice-add 'auto-revert-buffers :before
- 'auto-revert-buffers--buffer-list-filter)
-
-(custom-add-to-group 'magit 'auto-revert-check-vc-info 'custom-variable)
-
-;;; magit-autorevert.el ends soon
-(provide 'magit-autorevert)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-autorevert.el ends here
+++ /dev/null
-;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Use a binary search to find the commit that introduced a bug.
-
-;;; Code:
-
-(require 'magit)
-
-(defface magit-bisect-good
- '((t :foreground "DarkOliveGreen"))
- "Face for good bisect revisions."
- :group 'magit-faces)
-
-(defface magit-bisect-skip
- '((t :foreground "DarkGoldenrod"))
- "Face for skipped bisect revisions."
- :group 'magit-faces)
-
-(defface magit-bisect-bad
- '((t :foreground "IndianRed4"))
- "Face for bad bisect revisions."
- :group 'magit-faces)
-
-;;;###autoload (autoload 'magit-bisect-popup "magit-bisect" nil t)
-(magit-define-popup magit-bisect-popup
- "Popup console for bisect commands."
- 'magit-commands
- :man-page "git-bisect"
- :actions '((?B "Start" magit-bisect-start)
- (?s "Start script" magit-bisect-run))
- :sequence-actions '((?b "Bad" magit-bisect-bad)
- (?g "Good" magit-bisect-good)
- (?k "Skip" magit-bisect-skip)
- (?r "Reset" magit-bisect-reset)
- (?s "Run script" magit-bisect-run))
- :sequence-predicate 'magit-bisect-in-progress-p)
-
-;;;###autoload
-(defun magit-bisect-start (bad good)
- "Start a bisect session.
-
-Bisecting a bug means to find the commit that introduced it.
-This command starts such a bisect session by asking for a know
-good and a bad commit. To move the session forward use the
-other actions from the bisect popup (\
-\\<magit-status-mode-map>\\[magit-bisect-popup])."
- (interactive (if (magit-bisect-in-progress-p)
- (user-error "Already bisecting")
- (magit-bisect-start-read-args)))
- (magit-git-bisect "start" (list bad good) t))
-
-(defun magit-bisect-start-read-args ()
- (let ((b (magit-read-branch-or-commit "Start bisect with bad revision")))
- (list b (magit-read-other-branch-or-commit "Good revision" b))))
-
-;;;###autoload
-(defun magit-bisect-reset ()
- "After bisecting, cleanup bisection state and return to original `HEAD'."
- (interactive)
- (when (magit-confirm 'reset-bisect)
- (magit-run-git "bisect" "reset")
- (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT")))))
-
-;;;###autoload
-(defun magit-bisect-good ()
- "While bisecting, mark the current commit as good.
-Use this after you have asserted that the commit does not contain
-the bug in question."
- (interactive)
- (magit-git-bisect "good"))
-
-;;;###autoload
-(defun magit-bisect-bad ()
- "While bisecting, mark the current commit as bad.
-Use this after you have asserted that the commit does contain the
-bug in question."
- (interactive)
- (magit-git-bisect "bad"))
-
-;;;###autoload
-(defun magit-bisect-skip ()
- "While bisecting, skip the current commit.
-Use this if for some reason the current commit is not a good one
-to test. This command lets Git choose a different one."
- (interactive)
- (magit-git-bisect "skip"))
-
-;;;###autoload
-(defun magit-bisect-run (cmdline &optional bad good)
- "Bisect automatically by running commands after each step.
-
-Unlike `git bisect run' this can be used before bisecting has
-begun. In that case it behaves like `git bisect start; git
-bisect run'."
- (interactive (let ((args (and (not (magit-bisect-in-progress-p))
- (magit-bisect-start-read-args))))
- (cons (read-shell-command "Bisect shell command: ") args)))
- (when (and bad good)
- (magit-bisect-start bad good))
- (magit-git-bisect "run" (list cmdline)))
-
-(defun magit-git-bisect (subcommand &optional args no-assert)
- (unless (or no-assert (magit-bisect-in-progress-p))
- (user-error "Not bisecting"))
- (magit-with-toplevel
- (magit-run-git-with-logfile
- (magit-git-dir "BISECT_CMD_OUTPUT") "bisect" subcommand args)))
-
-(defun magit-bisect-in-progress-p ()
- (file-exists-p (magit-git-dir "BISECT_LOG")))
-
-(defun magit-insert-bisect-output ()
- "While bisecting, insert section with output from `git bisect'."
- (when (magit-bisect-in-progress-p)
- (let ((lines
- (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT"))
- (list "Bisecting: (no saved bisect output)"
- "It appears you have invoked `git bisect' from a shell."
- "There is nothing wrong with that, we just cannot display"
- "anything useful here. Consult the shell output instead.")))
- (done-re "^[a-z0-9]\\{40\\} is the first bad commit$"))
- (magit-insert-section (bisect-output t)
- (magit-insert-heading
- (propertize (or (and (string-match done-re (car lines)) (pop lines))
- (--first (string-match done-re it) lines)
- (pop lines))
- 'face 'magit-section-heading))
- (dolist (line lines)
- (insert line "\n"))))
- (insert "\n")))
-
-(defun magit-insert-bisect-rest ()
- "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-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis)
- "bisect" "visualize" "git" "log"
- "--format=%h%d %s" "--decorate=full"))))
-
-(defun magit-insert-bisect-log ()
- "While bisecting, insert section logging bisect progress."
- (when (magit-bisect-in-progress-p)
- (magit-insert-section (bisect-log)
- (magit-insert-heading "Bisect Log:")
- (magit-git-wash #'magit-wash-bisect-log "bisect" "log")
- (insert ?\n))))
-
-(defun magit-wash-bisect-log (_args)
- (let (beg)
- (while (progn (setq beg (point-marker))
- (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t))
- (magit-bind-match-strings (heading) nil
- (magit-delete-match)
- (save-restriction
- (narrow-to-region beg (point))
- (goto-char (point-min))
- (magit-insert-section (bisect-log heading t)
- (insert (propertize heading 'face 'magit-section-secondary-heading))
- (magit-insert-heading)
- (magit-wash-sequence
- (apply-partially 'magit-log-wash-rev 'bisect-log
- (magit-abbrev-length)))
- (insert ?\n)))))
- (when (re-search-forward
- "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t)
- (magit-bind-match-strings (hash) nil
- (magit-delete-match)
- (magit-insert-section (bisect-log)
- (insert hash " is the first bad commit\n"))))))
-
-;;; magit-bisect.el ends soon
-(provide 'magit-bisect)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-bisect.el ends here
+++ /dev/null
-;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2012-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Annotates each line in file-visiting buffer with information from
-;; the revision which last modified the line.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defgroup magit-blame nil
- "Blame support for Magit."
- :group 'magit-extensions)
-
-(defcustom magit-blame-heading-format "%-20a %C %s"
- "Format string used for blame headings.
-
-The following placeholders are recognized:
-
- %H hash
- %s summary
- %a author
- %A author time
- %c committer
- %C committer time
-
-The author and committer time formats can be specified with
-`magit-blame-time-format'."
- :group 'magit-blame
- :type 'string)
-
-(defcustom magit-blame-time-format "%F %H:%M"
- "Format for time strings in blame headings."
- :group 'magit-blame
- :type 'string)
-
-(defcustom magit-blame-show-headings t
- "Whether to initially show blame block headings.
-The headings can also be toggled locally using command
-`magit-blame-toggle-headings'."
- :group 'magit-blame
- :type 'boolean)
-
-(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode)
- "List of modes not compatible with Magit-Blame mode.
-This modes are turned off when Magit-Blame mode is turned on,
-and then turned on again when turning off the latter."
- :group 'magit-blame
- :type '(repeat (symbol :tag "Mode")))
-
-(make-variable-buffer-local 'magit-blame-disabled-modes)
-
-(defcustom magit-blame-mode-lighter " Blame"
- "The mode-line lighter of the Magit-Blame mode."
- :group 'magit-blame
- :type '(choice (const :tag "No lighter" "") string))
-
-(unless (find-lisp-object-file-name 'magit-blame-goto-chunk-hook 'defvar)
- (add-hook 'magit-blame-goto-chunk-hook 'magit-blame-maybe-update-revision-buffer))
-(defcustom magit-blame-goto-chunk-hook '(magit-blame-maybe-update-revision-buffer)
- "Hook run by `magit-blame-next-chunk' and `magit-blame-previous-chunk'."
- :package-version '(magit . "2.1.0")
- :group 'magit-blame
- :type 'hook
- :options '(magit-blame-maybe-update-revision-buffer))
-
-(defface magit-blame-heading
- '((((class color) (background light))
- :background "grey80"
- :foreground "black")
- (((class color) (background dark))
- :background "grey25"
- :foreground "black"))
- "Face for blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-summary
- '((t :inherit magit-blame-heading))
- "Face used for commit summary in blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-hash
- '((t :inherit magit-blame-heading))
- "Face used for commit hash in blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-name
- '((t :inherit magit-blame-heading))
- "Face used for author and committer names in blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-date
- '((t :inherit magit-blame-heading))
- "Face used for dates in blame headings."
- :group 'magit-faces)
-
-;;; Code
-
-(defvar magit-blame-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "\r" 'magit-show-commit)
- (define-key map "\s" 'magit-diff-show-or-scroll-up)
- (define-key map "\d" 'magit-diff-show-or-scroll-down)
- (define-key map "b" 'magit-blame-popup)
- (define-key map "n" 'magit-blame-next-chunk)
- (define-key map "N" 'magit-blame-next-chunk-same-commit)
- (define-key map "p" 'magit-blame-previous-chunk)
- (define-key map "P" 'magit-blame-previous-chunk-same-commit)
- (define-key map "q" 'magit-blame-quit)
- (define-key map "t" 'magit-blame-toggle-headings)
- (define-key map "\M-w" 'magit-blame-copy-hash)
- map)
- "Keymap for `magit-blame-mode'.")
-
-(defun magit-blame-put-keymap-before-view-mode ()
- "Put `magit-blame-mode' ahead of `view-mode' in `minor-mode-map-alist'."
- (--when-let (assq 'magit-blame-mode
- (cl-member 'view-mode minor-mode-map-alist :key #'car))
- (setq minor-mode-map-alist
- (cons it (delq it minor-mode-map-alist))))
- (remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode))
-
-(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)
-
-(defvar-local magit-blame-buffer-read-only nil)
-(defvar-local magit-blame-cache nil)
-(defvar-local magit-blame-process nil)
-(defvar-local magit-blame-recursive-p nil)
-(defvar-local magit-blame-separator nil)
-
-(define-minor-mode magit-blame-mode
- "Display blame information inline.
-\n\\{magit-blame-mode-map}"
- :lighter magit-blame-mode-lighter
- (cond (magit-blame-mode
- (when (called-interactively-p 'any)
- (setq magit-blame-mode nil)
- (user-error
- (concat "Don't call `magit-blame-mode' directly; "
- "instead use `magit-blame' or `magit-blame-popup'")))
- (setq magit-blame-buffer-read-only buffer-read-only)
- (read-only-mode 1)
- (dolist (mode magit-blame-disable-modes)
- (when (and (boundp mode) (symbol-value mode))
- (funcall mode -1)
- (push mode magit-blame-disabled-modes)))
- (setq magit-blame-separator (magit-blame-format-separator)))
- (t
- (unless magit-blame-buffer-read-only
- (read-only-mode -1))
- (dolist (mode magit-blame-disabled-modes)
- (funcall mode 1))
- (when (process-live-p magit-blame-process)
- (kill-process magit-blame-process))
- (save-excursion
- (save-restriction
- (widen)
- (dolist (ov (overlays-in (point-min) (point-max)))
- (when (overlay-get ov 'magit-blame)
- (delete-overlay ov))))))))
-
-(defun auto-revert-handler--unless-magit-blame-mode ()
- "If Magit-Blame mode is on, then do nothing. See #1731."
- magit-blame-mode)
-
-(advice-add 'auto-revert-handler :before-until
- 'auto-revert-handler--unless-magit-blame-mode)
-
-;;;###autoload (autoload 'magit-blame-popup "magit-blame" nil t)
-(magit-define-popup magit-blame-popup
- "Popup console for blame commands."
- 'magit-commands
- :man-page "git-blame"
- :switches '((?w "Ignore whitespace" "-w")
- (?r "Do not treat root commits as boundaries" "--root"))
- :options '((?C "Detect lines moved or copied within a file" "-C")
- (?M "Detect lines moved or copied between files" "-M"))
- :actions '((?b "Blame" magit-blame))
- :default-arguments '("-w")
- :default-action 'magit-blame)
-
-;;;###autoload
-(defun magit-blame (revision file &optional args line)
- "Display edit history of FILE up to REVISION.
-
-Interactively blame the file being visited in the current buffer.
-If the buffer visits a revision of that file, then blame up to
-that revision, otherwise blame the file's full history, including
-uncommitted changes.
-
-If Magit-Blame mode is already turned on then blame recursively, by
-visiting REVISION:FILE (using `magit-find-file'), where revision
-is the revision before the revision that added the lines at
-point.
-
-ARGS is a list of additional arguments to pass to `git blame';
-only arguments available from `magit-blame-popup' should be used.
-\n(fn REVISION FILE &optional ARGS)" ; LINE is for internal use
- (interactive
- (let ((args (magit-blame-arguments)))
- (if magit-blame-mode
- (--if-let (magit-blame-chunk-get :previous-hash)
- (list it (magit-blame-chunk-get :previous-file)
- args (magit-blame-chunk-get :previous-start))
- (user-error "Block has no further history"))
- (--if-let (magit-file-relative-name nil 'tracked)
- (list (or magit-buffer-refname magit-buffer-revision) it args)
- (if buffer-file-name
- (user-error "Buffer isn't visiting a tracked file")
- (user-error "Buffer isn't visiting a file"))))))
- (magit-with-toplevel
- (if revision
- (magit-find-file revision file)
- (let ((default-directory default-directory))
- (--if-let (find-buffer-visiting file)
- (progn (switch-to-buffer it)
- (save-buffer))
- (find-file file))))
- ;; ^ Make sure this doesn't affect the value used below. b640c6f
- (widen)
- (when line
- (setq magit-blame-recursive-p t)
- (goto-char (point-min))
- (forward-line (1- line)))
- (unless magit-blame-mode
- (setq magit-blame-cache (make-hash-table :test 'equal))
- (let ((show-headings magit-blame-show-headings))
- (magit-blame-mode 1)
- (setq-local magit-blame-show-headings show-headings))
- (message "Blaming...")
- (let ((magit-process-popup-time -1)
- (inhibit-magit-refresh t))
- (magit-run-git-async
- "blame" "--incremental" args
- "-L" (format "%s,%s"
- (line-number-at-pos (window-start))
- (line-number-at-pos (1- (window-end nil t))))
- revision "--" file))
- (setq magit-blame-process magit-this-process)
- (set-process-filter magit-this-process 'magit-blame-process-filter)
- (set-process-sentinel
- magit-this-process
- `(lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (magit-process-sentinel process event)
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (when magit-blame-mode
- (let ((magit-process-popup-time -1)
- (inhibit-magit-refresh t)
- (default-directory ,default-directory))
- (magit-run-git-async "blame" "--incremental" ,@args
- ,revision "--" ,file))
- (setq magit-blame-process magit-this-process)
- (set-process-filter
- magit-this-process 'magit-blame-process-filter)
- (set-process-sentinel
- magit-this-process 'magit-blame-process-sentinel)))))))))
-
-(defun magit-blame-process-sentinel (process event)
- (let ((status (process-status process)))
- (when (memq status '(exit signal))
- (magit-process-sentinel process event)
- (if (eq status 'exit)
- (message "Blaming...done")
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (magit-blame-mode -1))
- (message "Blaming...failed")))))
-
-(defvar magit-blame-log nil
- "Whether to log blame output to the process buffer.
-This is intended for debugging purposes.")
-
-(defun magit-blame-process-filter (process string)
- (when magit-blame-log
- (magit-process-filter process string))
- (--when-let (process-get process 'partial-line)
- (setq string (concat it string))
- (setf (process-get process 'partial-line) nil))
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (when magit-blame-mode
- (let ((chunk (process-get process 'chunk))
- (lines (split-string string "\n" t)))
- (unless (string-match-p "\n\\'" string)
- (process-put process 'chunk chunk)
- (process-put process 'partial-line (car (last lines)))
- (setq lines (butlast lines)))
- (dolist (line lines)
- (cond
- ((equal line ""))
- ((not chunk)
- (string-match
- "^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)" line)
- (setq chunk
- (list :hash (let ((hash (match-string 1 line)))
- (unless (equal hash (make-string 40 ?0))
- hash))
- :previous-start (string-to-number (match-string 2 line))
- :start (string-to-number (match-string 3 line))
- :lines (string-to-number (match-string 4 line)))))
- ((string-match "^filename \\(.+\\)" line)
- (let* ((hash (plist-get chunk :hash))
- (file (match-string 1 line)))
- (--if-let (gethash hash magit-blame-cache)
- (setq chunk (nconc chunk it))
- (plist-put chunk :filename file)
- (puthash hash chunk magit-blame-cache)))
- (magit-blame-make-overlay chunk)
- (setq chunk nil))
- ((string-match "^previous \\(.\\{40\\}\\) \\(.+\\)" line)
- (plist-put chunk :previous-hash (match-string 1 line))
- (plist-put chunk :previous-file (match-string 2 line)))
- ((string-match "^\\([^ ]+?-mail\\) <\\([^>]+\\)>" line)
- (plist-put chunk (intern (concat ":" (match-string 1 line)))
- (string-to-number (match-string 2 line))))
- ((string-match "^\\([^ ]+?-\\(?:time\\|tz\\)\\) \\(.+\\)" line)
- (plist-put chunk (intern (concat ":" (match-string 1 line)))
- (string-to-number (match-string 2 line))))
- ((string-match "^\\([^ ]+\\) \\(.+\\)" line)
- (plist-put chunk (intern (concat ":" (match-string 1 line)))
- (match-string 2 line))))
- (process-put process 'chunk chunk))))))
-
-(defun magit-blame-assert-buffer (process)
- (unless (buffer-live-p (process-get process 'command-buf))
- (kill-process process)
- (user-error "Buffer being blamed has been killed")))
-
-(defun magit-blame-make-overlay (chunk)
- (let ((ov (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (forward-line (1- (plist-get chunk :start)))
- (--when-let (--first (overlay-get it 'magit-blame)
- (overlays-at (point)))
- (delete-overlay it))
- (make-overlay (point)
- (progn (forward-line
- (plist-get chunk :lines))
- (point))))))
- (heading (magit-blame-format-heading chunk)))
- (overlay-put ov 'magit-blame chunk)
- (overlay-put ov 'magit-blame-heading heading)
- (overlay-put ov 'before-string
- (if magit-blame-show-headings
- heading
- magit-blame-separator))))
-
-(defun magit-blame-format-separator ()
- (propertize
- (concat (propertize " " 'display '(space :height (2)))
- (propertize "\n" 'line-height t))
- 'face (list :background (face-attribute 'magit-blame-heading :background))))
-
-(defun magit-blame-format-heading (chunk)
- (with-temp-buffer
- (insert (format-spec
- (concat magit-blame-heading-format "\n")
- `((?H . ,(propertize (or (plist-get chunk :hash) "")
- 'face 'magit-blame-hash))
- (?s . ,(propertize (or (plist-get chunk :summary) "")
- 'face 'magit-blame-summary))
- (?a . ,(propertize (or (plist-get chunk :author) "")
- 'face 'magit-blame-name))
- (?A . ,(propertize (magit-blame-format-time-string
- magit-blame-time-format
- (plist-get chunk :author-time)
- (plist-get chunk :author-tz))
- 'face 'magit-blame-date))
- (?c . ,(propertize (or (plist-get chunk :committer) "")
- 'face 'magit-blame-name))
- (?C . ,(propertize (magit-blame-format-time-string
- magit-blame-time-format
- (plist-get chunk :committer-time)
- (plist-get chunk :committer-tz))
- 'face 'magit-blame-date)))))
- (goto-char (point-min))
- (while (not (eobp))
- (let ((face (get-text-property (point) 'face))
- (next (or (next-single-property-change (point) 'face)
- (point-max))))
- (unless face
- (put-text-property (point) next 'face 'magit-blame-heading))
- (goto-char next)))
- (buffer-string)))
-
-(defun magit-blame-format-time-string (format time tz)
- (format-time-string
- format (seconds-to-time (+ time (* (/ tz 100) 60 60) (* (% tz 100) 60)))))
-
-(defun magit-blame-quit ()
- "Turn off Magit-Blame mode.
-If the buffer was created during a recursive blame,
-then also kill the buffer."
- (interactive)
- (if magit-blame-recursive-p
- (kill-buffer)
- (magit-blame-mode -1)))
-
-(defun magit-blame-next-chunk ()
- "Move to the next chunk."
- (interactive)
- (--if-let (next-single-char-property-change (point) 'magit-blame)
- (progn (goto-char it)
- (run-hooks 'magit-blame-goto-chunk-hook))
- (user-error "No more chunks")))
-
-(defun magit-blame-previous-chunk ()
- "Move to the previous chunk."
- (interactive)
- (--if-let (previous-single-char-property-change (point) 'magit-blame)
- (progn (goto-char it)
- (run-hooks 'magit-blame-goto-chunk-hook))
- (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)"
- (interactive)
- (-if-let (hash (magit-blame-chunk-get :hash))
- (let ((pos (point)) ov)
- (save-excursion
- (while (and (not ov)
- (not (= pos (if previous (point-min) (point-max))))
- (setq pos (funcall
- (if previous
- 'previous-single-char-property-change
- 'next-single-char-property-change)
- pos 'magit-blame)))
- (--when-let (magit-blame-overlay-at pos)
- (when (equal (magit-blame-chunk-get :hash pos) hash)
- (setq ov it)))))
- (if ov
- (goto-char (overlay-start ov))
- (user-error "No more chunks from same commit")))
- (user-error "This chunk hasn't been blamed yet")))
-
-(defun magit-blame-previous-chunk-same-commit ()
- "Move to the previous chunk from the same commit."
- (interactive)
- (magit-blame-next-chunk-same-commit 'previous-single-char-property-change))
-
-(defun magit-blame-toggle-headings ()
- "Show or hide blame chunk headings."
- (interactive)
- (setq-local magit-blame-show-headings (not magit-blame-show-headings))
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (while (not (eobp))
- (let ((next (next-single-char-property-change (point) 'magit-blame)))
- (--when-let (magit-blame-overlay-at (point))
- (overlay-put it 'before-string
- (if magit-blame-show-headings
- (overlay-get it 'magit-blame-heading)
- magit-blame-separator)))
- (goto-char (or next (point-max))))))))
-
-(defun magit-blame-copy-hash ()
- "Save hash of the current chunk's commit to the kill ring."
- (interactive)
- (kill-new (message "%s" (magit-blame-chunk-get :hash))))
-
-(defun magit-blame-chunk-get (key &optional pos)
- (--when-let (magit-blame-overlay-at pos)
- (plist-get (overlay-get it 'magit-blame) key)))
-
-(defun magit-blame-overlay-at (&optional pos)
- (--first (overlay-get it 'magit-blame)
- (overlays-at (or pos (point)))))
-
-(defun magit-blame-maybe-update-revision-buffer ()
- (unless magit--update-revision-buffer
- (setq magit--update-revision-buffer nil)
- (-when-let* ((commit (magit-blame-chunk-get :hash))
- (buffer (magit-mode-get-buffer 'magit-revision-mode nil t)))
- (setq magit--update-revision-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (-let [(rev buf) magit--update-revision-buffer]
- (setq magit--update-revision-buffer nil)
- (when (buffer-live-p buf)
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-show-commit rev (magit-diff-arguments))))))))))
-
-;;; magit-blame.el ends soon
-(provide 'magit-blame)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-blame.el ends here
+++ /dev/null
-;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements commands for creating Git commits. These
-;; commands just initiate the commit, support for writing the commit
-;; messages is implemented in `git-commit.el'.
-
-;;; Code:
-
-(require 'magit)
-(require 'magit-sequence)
-
-(eval-when-compile (require 'epa)) ; for `epa-protocol'
-(eval-when-compile (require 'epg))
-(declare-function epg-sub-key-id 'epg)
-(declare-function epg-key-sub-key-list 'epg)
-(declare-function epg-key-user-id-list 'epg)
-(declare-function epg-user-id-string 'epg)
-(declare-function epg-decode-dn 'epg)
-(declare-function epg-list-keys 'epg)
-
-;;; Options
-
-(defcustom magit-commit-arguments nil
- "The arguments used when committing."
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-commit-ask-to-stage 'verbose
- "Whether to ask to stage everything when committing and nothing is staged."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type '(choice (const :tag "Ask showing diff" verbose)
- (const :tag "Ask" t)
- (const :tag "Don't ask" nil)))
-
-(defcustom magit-commit-show-diff t
- "Whether the relevant diff is automatically shown when committing."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-extend-override-date t
- "Whether using `magit-commit-extend' changes the committer date."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-reword-override-date t
- "Whether using `magit-commit-reword' changes the committer date."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-squash-confirm t
- "Whether the commit targeted by squash and fixup has to be confirmed.
-When non-nil then the commit at point (if any) is used as default
-choice, otherwise it has to be confirmed. This option only
-affects `magit-commit-squash' and `magit-commit-fixup'. The
-\"instant\" variants always require confirmation because making
-an error while using those is harder to recover from."
- :package-version '(magit . "2.1.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Code
-
-(defun magit-commit-popup (&optional arg)
- "Popup console for commit commands."
- (interactive "P")
- (--if-let (magit-commit-message-buffer)
- (switch-to-buffer it)
- (magit-invoke-popup 'magit-commit-popup nil arg)))
-
-(defvar magit-commit-popup
- '(:variable magit-commit-arguments
- :man-page "git-commit"
- :switches ((?a "Stage all modified and deleted files" "--all")
- (?e "Allow empty commit" "--allow-empty")
- (?v "Show diff of changes to be committed" "--verbose")
- (?n "Bypass git hooks" "--no-verify")
- (?s "Add Signed-off-by line" "--signoff")
- (?R "Claim authorship and reset author date" "--reset-author"))
- :options ((?A "Override the author" "--author=")
- (?S "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key)
- (?C "Reuse commit message" "--reuse-message="))
- :actions ((?c "Commit" magit-commit)
- (?e "Extend" magit-commit-extend)
- (?f "Fixup" magit-commit-fixup)
- (?F "Instant Fixup" magit-commit-instant-fixup) nil
- (?w "Reword" magit-commit-reword)
- (?s "Squash" magit-commit-squash)
- (?S "Instant Squash" magit-commit-instant-squash) nil
- (?a "Amend" magit-commit-amend)
- (?A "Augment" magit-commit-augment))
- :max-action-columns 4
- :default-action magit-commit))
-
-(magit-define-popup-keys-deferred 'magit-commit-popup)
-
-(defun magit-commit-arguments nil
- (if (eq magit-current-popup 'magit-commit-popup)
- magit-current-popup-args
- magit-commit-arguments))
-
-(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)))))
-
-;;;###autoload
-(defun magit-commit (&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))))
- (when (setq args (magit-commit-assert args))
- (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-run-git-with-editor "commit" "--amend" args))
-
-;;;###autoload
-(defun magit-commit-extend (&optional args override-date)
- "Amend the last commit, without editing the 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)"
- (interactive (list (magit-commit-arguments)
- (if current-prefix-arg
- (not magit-commit-extend-override-date)
- magit-commit-extend-override-date)))
- (when (setq args (magit-commit-assert args (not override-date)))
- (let ((process-environment process-environment))
- (unless override-date
- (setenv "GIT_COMMITTER_DATE" (magit-rev-format "%cD")))
- (magit-run-git-with-editor "commit" "--amend" "--no-edit" args))))
-
-;;;###autoload
-(defun magit-commit-reword (&optional args override-date)
- "Reword the last commit, ignoring staged changes.
-
-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)"
- (interactive (list (magit-commit-arguments)
- (if current-prefix-arg
- (not magit-commit-reword-override-date)
- magit-commit-reword-override-date)))
- (let ((process-environment process-environment))
- (unless override-date
- (setenv "GIT_COMMITTER_DATE" (magit-rev-format "%cD")))
- (magit-run-git-with-editor "commit" "--amend" "--only" args)))
-
-;;;###autoload
-(defun magit-commit-fixup (&optional commit args)
- "Create a fixup commit.
-
-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'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--fixup" commit args))
-
-;;;###autoload
-(defun magit-commit-squash (&optional commit args)
- "Create a squash commit, without editing the squash 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'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args))
-
-;;;###autoload
-(defun magit-commit-augment (&optional commit args)
- "Create a squash commit, editing the squash 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'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args nil t))
-
-;;;###autoload
-(defun magit-commit-instant-fixup (&optional commit args)
- "Create a fixup commit targeting COMMIT and instantly rebase."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--fixup" commit args t))
-
-;;;###autoload
-(defun magit-commit-instant-squash (&optional commit args)
- "Create a squash commit targeting COMMIT and instantly rebase."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args t))
-
-(defun magit-commit-squash-internal
- (option commit &optional args rebase edit confirmed)
- (-when-let (args (magit-commit-assert args t))
- (if (and commit
- (or confirmed
- (not (or rebase
- current-prefix-arg
- magit-commit-squash-confirm))))
- (let ((magit-commit-show-diff nil))
- (magit-run-git-with-editor "commit"
- (unless edit "--no-edit")
- (concat option "=" commit)
- args))
- (magit-log-select
- `(lambda (commit)
- (magit-commit-squash-internal ,option commit ',args ,rebase ,edit t)
- ,@(when rebase
- `((magit-rebase-interactive-1 commit
- (list "--autosquash" "--autostash")
- "" "true"))))
- (format "Type %%p on a commit to %s into it,"
- (substring option 2)))
- (when magit-commit-show-diff
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-diff-staged nil (magit-diff-arguments)))))))
-
-(defun magit-commit-assert (args &optional strict)
- (cond
- ((or (magit-anything-staged-p)
- (and (magit-anything-unstaged-p)
- ;; ^ Everything of nothing is still nothing.
- (member "--all" args))
- (and (not strict)
- ;; ^ For amend variants that don't make sense otherwise.
- (or (member "--amend" args)
- (member "--allow-empty" args))))
- (or args (list "--")))
- ((and (magit-rebase-in-progress-p)
- (not (magit-anything-unstaged-p))
- (y-or-n-p "Nothing staged. Continue in-progress rebase? "))
- (magit-run-git-sequencer "rebase" "--continue")
- nil)
- ((and (file-exists-p (magit-git-dir "MERGE_MSG"))
- (not (magit-anything-unstaged-p)))
- (or args (list "--")))
- ((not (magit-anything-unstaged-p))
- (user-error "Nothing staged (or unstaged)"))
- (magit-commit-ask-to-stage
- (when (eq magit-commit-ask-to-stage 'verbose)
- (magit-diff-unstaged))
- (prog1 (when (y-or-n-p "Nothing staged. Stage and commit everything? ")
- (magit-run-git "add" "-u" ".")
- (or args (list "--")))
- (when (and (eq magit-commit-ask-to-stage 'verbose)
- (derived-mode-p 'magit-diff-mode))
- (magit-mode-bury-buffer))))
- (t
- (user-error "Nothing staged"))))
-
-(defun magit-commit-diff ()
- (--when-let (and git-commit-mode
- magit-commit-show-diff
- (pcase last-command
- (`magit-commit
- (apply-partially 'magit-diff-staged nil))
- (`magit-commit-amend 'magit-diff-while-amending)
- (`magit-commit-reword 'magit-diff-while-amending)))
- (condition-case nil
- (let ((magit-inhibit-save-previous-winconf 'unset)
- (magit-display-buffer-noselect t)
- (inhibit-quit nil))
- (message "Diffing changes to be committed (C-g to abort diffing)")
- (funcall it (car (magit-diff-arguments))))
- (quit))))
-
-(add-hook 'server-switch-hook 'magit-commit-diff)
-
-(add-to-list 'with-editor-server-window-alist
- (cons git-commit-filename-regexp 'switch-to-buffer))
-
-(defvar magit-gpg-secret-key-hist nil)
-
-(defun magit-read-gpg-secret-key (prompt &optional _initial-input)
- (require 'epa)
- (let ((keys (--map (list (epg-sub-key-id (car (epg-key-sub-key-list it)))
- (-when-let (id-obj (car (epg-key-user-id-list it)))
- (let ((id-str (epg-user-id-string id-obj)))
- (if (stringp id-str)
- id-str
- (epg-decode-dn id-obj)))))
- (epg-list-keys (epg-make-context epa-protocol) nil t))))
- (magit-completing-read prompt keys nil nil nil 'magit-gpg-secret-key-hist
- (car (or magit-gpg-secret-key-hist keys)))))
-
-(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert
- "Used by `magit-commit-add-log' to insert a single entry.")
-
-(defun magit-commit-add-log ()
- "Add a stub for the current change into the commit message buffer.
-If no commit is in progress, then initiate it. Use the function
-specified by variable `magit-commit-add-log-insert-function' to
-actually insert the entry."
- (interactive)
- (let ((hunk (magit-section-when 'hunk it))
- (log (magit-commit-message-buffer)) buf pos)
- (save-window-excursion
- (call-interactively #'magit-diff-visit-file)
- (setq buf (current-buffer)
- pos (point)))
- (unless log
- (unless (magit-commit-assert nil)
- (user-error "Abort"))
- (magit-commit)
- (while (not (setq log (magit-commit-message-buffer)))
- (sit-for 0.01)))
- (save-excursion
- (with-current-buffer buf
- (goto-char pos)
- (funcall magit-commit-add-log-insert-function log
- (magit-file-relative-name)
- (and hunk (add-log-current-defun)))))))
-
-(defun magit-commit-add-log-insert (buffer file defun)
- (with-current-buffer buffer
- (undo-boundary)
- (goto-char (point-max))
- (while (re-search-backward (concat "^" comment-start) nil t))
- (cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file)
- nil t)
- (when (equal (match-string 1) defun)
- (setq defun nil))
- (re-search-forward ": "))
- (t
- (when (re-search-backward "^[\\*(].+\n" nil t)
- (goto-char (match-end 0)))
- (while (re-search-forward "^[^\\*#\n].*\n" nil t))
- (if defun
- (progn (insert (format "* %s (%s): \n" file defun))
- (setq defun nil))
- (insert (format "* %s: \n" file)))
- (backward-char)
- (unless (looking-at "\n[\n\\']")
- (insert ?\n)
- (backward-char))))
- (when defun
- (forward-line)
- (let ((limit (save-excursion
- (and (re-search-forward "^\\*" nil t)
- (point)))))
- (unless (or (looking-back (format "(%s): " defun)
- (line-beginning-position))
- (re-search-forward (format "^(%s): " defun) limit t))
- (while (re-search-forward "^[^\\*#\n].*\n" limit t))
- (insert (format "(%s): \n" defun))
- (backward-char))))))
-
-;;; magit-commit.el ends soon
-(provide 'magit-commit)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-commit.el ends here
+++ /dev/null
-;;; magit-core.el --- core functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library requires several other libraries, so that yet other
-;; libraries can just require this one, instead of having to require
-;; all the other ones. In other words this separates the low-level
-;; stuff from the rest. It also defines some Custom groups.
-
-;;; Code:
-
-(require 'magit-utils)
-(require 'magit-section)
-(require 'magit-git)
-(require 'magit-mode)
-(require 'magit-popup)
-(require 'magit-process)
-(require 'magit-autorevert)
-
-(defgroup magit nil
- "Controlling Git from Emacs."
- :group 'tools)
-
-(defgroup magit-commands nil
- "Options controlling behavior of certain commands."
- :group 'magit)
-
-(defgroup magit-modes nil
- "Modes used or provided by Magit."
- :group 'magit)
-
-(defgroup magit-extensions nil
- "Extensions to Magit."
- :group 'magit)
-
-(defgroup magit-faces nil
- "Faces used by Magit."
- :group 'magit
- :group 'faces)
-
-(custom-add-to-group 'magit-modes 'magit-popup 'custom-group)
-(custom-add-to-group 'magit-faces 'magit-popup-faces 'custom-group)
-(custom-add-to-group 'magit-modes 'git-commit 'custom-group)
-(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group)
-(custom-add-to-group 'magit-modes 'git-rebase 'custom-group)
-(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group)
-(custom-add-to-group 'magit-process 'with-editor 'custom-group)
-
-(custom-add-to-group 'magit 'vc-follow-symlinks 'custom-variable)
-
-;;; magit-core.el ends soon
-(provide 'magit-core)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-core.el ends here
+++ /dev/null
-;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonas@bernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for looking at Git diffs and
-;; commits.
-
-;;; Code:
-
-(require 'git-commit)
-(require 'magit-core)
-
-;; For `magit-diff-popup'
-(declare-function magit-stash-show 'magit-stash)
-;; For `magit-diff-visit-file'
-(declare-function magit-dired-jump 'magit)
-(declare-function magit-find-file-noselect 'magit)
-(declare-function magit-status-internal 'magit)
-;; For `magit-diff-wash-revision'
-(declare-function magit-insert-tags-header 'magit)
-;; For `magit-diff-while-committing'
-(declare-function magit-commit-message-buffer 'magit)
-;; For `magit-insert-revision-gravatar'
-(defvar gravatar-size)
-;; For `magit-show-commit' and `magit-diff-show-or-scroll'
-(declare-function magit-blame-chunk-get 'magit-blame)
-(declare-function magit-blame-mode 'magit-blame)
-(defvar magit-blame-mode)
-(defvar git-rebase-line)
-
-(require 'diff-mode)
-(require 'smerge-mode)
-
-;;; Options
-;;;; Diff Mode
-
-(defgroup magit-diff nil
- "Inspect and manipulate Git diffs."
- :group 'magit-modes)
-
-(custom-add-to-group 'magit-diff 'smerge-refine-ignore-whitespace
- 'custom-variable)
-
-(defcustom magit-diff-mode-hook nil
- "Hook run after entering Magit-Diff mode."
- :group 'magit-diff
- :type 'hook)
-
-(defcustom magit-diff-sections-hook
- '(magit-insert-diff
- magit-insert-xref-buttons)
- "Hook run to insert sections into a `magit-diff-mode' buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'hook)
-
-(defcustom magit-diff-expansion-threshold 1.0
- "After how many seconds not to expand anymore diffs.
-
-Except in status buffers, diffs are usually start out fully
-expanded. Because that can take a long time, all diffs that
-haven't been fontified during a refresh before the threshold
-defined here are instead displayed with their bodies collapsed.
-
-Note that this can cause sections that were previously expanded
-to be collapsed. So you should not pick a very low value here.
-
-The hook function `magit-diff-expansion-threshold' has to be a
-member of `magit-section-set-visibility-hook' for this option
-to have any effect"
- :package-version '(magit . "2.1.0")
- :group 'magit-diff
- :type 'float)
-
-(defcustom magit-diff-highlight-hunk-body t
- "Whether to highlight bodies of selected hunk sections.
-This only has an effect if `magit-diff-highlight' is a
-member of `magit-section-highlight-hook', which see."
- :package-version '(magit . "2.1.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-show-lines-boundary t
- "Whether to delimit hunk-internal region with thin lines.
-
-When a hunk-internal region (used to stage just the lines that
-fall into the region instead of the complete hunk) only covers
-context lines, then these lines are the only visual indicator
-for the region. In character-only terminals it's not possible
-to draw thin lines."
- :package-version '(magit . "2.1.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-refine-hunk nil
- "Whether to show word-granularity differences within diff hunks.
-
-nil never show fine differences.
-t show fine differences for the current diff hunk only.
-`all' show fine differences for all displayed diff hunks."
- :group 'magit-diff
- :safe (lambda (val) (memq val '(nil t all)))
- :type '(choice (const :tag "Never" nil)
- (const :tag "Current" t)
- (const :tag "All" all)))
-
-(put 'magit-diff-refine-hunk 'permanent-local t)
-
-(defcustom magit-diff-paint-whitespace t
- "Specify where to highlight whitespace errors.
-See `magit-highlight-trailing-whitespace',
-`magit-highlight-indentation'. The symbol t means in all diffs,
-`status' means only in the status buffer, and nil means nowhere."
- :group 'magit-diff
- :safe (lambda (val) (memq val '(t nil status)))
- :type '(choice (const :tag "Always" t)
- (const :tag "Never" nil)
- (const :tag "In status buffer" status)))
-
-(defcustom magit-diff-highlight-trailing t
- "Whether to highlight whitespace at the end of a line in diffs.
-Used only when `magit-diff-paint-whitespace' is non-nil."
- :group 'magit-diff
- :safe 'booleanp
- :type 'boolean)
-
-(defcustom magit-diff-highlight-indentation nil
- "Highlight the \"wrong\" indentation style.
-Used only when `magit-diff-paint-whitespace' is non-nil.
-
-The value is a list of cons cells. The car is a regular
-expression, and the cdr is the value that applies to repositories
-whose directory matches the regular expression. If more than one
-element matches, then the *last* element in the list applies.
-The default value should therefore come first in the list.
-
-If the value is `tabs', highlight indentation with tabs. If the
-value is an integer, highlight indentation with at least that
-many spaces. Otherwise, highlight neither."
- :group 'magit-diff
- :type `(repeat (cons (string :tag "Directory regexp")
- (choice (const :tag "Tabs" tabs)
- (integer :tag "Spaces" :value ,tab-width)
- (const :tag "Neither" nil)))))
-
-;;;; Revision Mode
-
-(defgroup magit-revision nil
- "Inspect and manipulate Git commits."
- :group 'magit-modes)
-
-(defcustom magit-revision-mode-hook nil
- "Hook run after entering Magit-Revision mode."
- :group 'magit-revision
- :type 'hook)
-
-(defcustom magit-revision-sections-hook
- '(magit-insert-revision-tag
- magit-insert-revision-headers
- magit-insert-revision-message
- magit-insert-revision-notes
- magit-insert-revision-diff
- magit-insert-xref-buttons)
- "Hook run to insert sections into a `magit-revision-mode' buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'hook)
-
-(defcustom magit-revision-headers-format "\
-Author: %aN <%aE>
-AuthorDate: %ad
-Commit: %cN <%cE>
-CommitDate: %cd
-"
- "Format string used to insert headers in revision buffers.
-
-All headers in revision buffers are inserted by the section
-inserter `magit-insert-revision-headers'. Some of the headers
-are created by calling `git show --format=FORMAT' where FORMAT
-is the format specified here. Other headers are hard coded or
-subject to option `magit-revision-insert-related-refs'."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'string)
-
-(defcustom magit-revision-insert-related-refs t
- "Whether to show related refs in revision buffers."
- :package-version '(magit . "2.1.0")
- :group 'magit-revision
- :type 'boolean)
-
-(defcustom magit-revision-show-gravatars nil
- "Whether to show gravatar images in revision buffers.
-
-If non-nil, then the value has to be a cons-cell which specifies
-where the gravatar images for the author and/or the committer are
-inserted inside the text that was previously inserted according
-to `magit-revision-header-format'.
-
-Both cells are regular expressions. The car specifies where to
-insert the author gravatar image. The top halve of the image is
-inserted right after the matched text, the bottom halve on the
-next line at the same offset. The cdr specifies where to insert
-the committer image, accordingly. Either the car or the cdr may
-be nil."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type '(choice (const :tag "Don't show gravatars" nil)
- (cons :tag "Show gravatars"
- (regexp :tag "Author regexp" "^Author: ")
- (regexp :tag "Committer regexp" "^Commit: "))))
-
-(defcustom magit-revision-use-gravatar-kludge nil
- "Whether to work around a bug which affects display of gravatars.
-
-Gravatar images are spliced into two halves which are then
-displayed on separate lines. On OS X the splicing has a bug in
-some Emacs builds, which causes the top and bottom halves to be
-interchanged. Enabling this option works around this issue by
-interchanging the halves once more, which cancels out the effect
-of the bug.
-
-See https://github.com/magit/magit/issues/2265
-and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'boolean)
-
-;;; Faces
-
-(defface magit-diff-file-heading
- '((t :weight bold))
- "Face for diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-file-heading-highlight
- '((t :inherit (magit-diff-file-heading magit-section-highlight)))
- "Face for current diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-file-heading-selection
- '((((class color) (background light))
- :inherit magit-diff-file-heading-highlight
- :foreground "salmon4")
- (((class color) (background dark))
- :inherit magit-diff-file-heading-highlight
- :foreground "LightSalmon3"))
- "Face for selected diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading
- '((((class color) (background light))
- :background "grey80"
- :foreground "grey30")
- (((class color) (background dark))
- :background "grey25"
- :foreground "grey70"))
- "Face for diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading-highlight
- '((((class color) (background light))
- :background "grey75"
- :foreground "grey30")
- (((class color) (background dark))
- :background "grey35"
- :foreground "grey70"))
- "Face for current diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading-selection
- '((((class color) (background light))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "salmon4")
- (((class color) (background dark))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "LightSalmon3"))
- "Face for selected diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-lines-heading
- '((((class color) (background light))
- :inherit magit-diff-hunk-heading-highlight
- :background "LightSalmon3")
- (((class color) (background dark))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "grey80"
- :background "salmon4"))
- "Face for diff hunk heading when lines are marked."
- :group 'magit-faces)
-
-(defface magit-diff-lines-boundary
- '((t :inherit magit-diff-lines-heading))
- "Face for boundary of marked lines in diff hunk."
- :group 'magit-faces)
-
-(defface magit-diff-conflict-heading
- '((t :inherit magit-diff-hunk-heading))
- "Face for conflict markers."
- :group 'magit-faces)
-
-(defface magit-diff-added
- '((((class color) (background light))
- :background "#ddffdd"
- :foreground "#22aa22")
- (((class color) (background dark))
- :background "#335533"
- :foreground "#ddffdd"))
- "Face for lines in a diff that have been added."
- :group 'magit-faces)
-
-(defface magit-diff-removed
- '((((class color) (background light))
- :background "#ffdddd"
- :foreground "#aa2222")
- (((class color) (background dark))
- :background "#553333"
- :foreground "#ffdddd"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-our
- '((t :inherit magit-diff-removed))
- "Face for lines in a diff for our side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-base
- '((((class color) (background light))
- :background "#ffffcc"
- :foreground "#aaaa11")
- (((class color) (background dark))
- :background "#555522"
- :foreground "#ffffcc"))
- "Face for lines in a diff for the base side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-their
- '((t :inherit magit-diff-added))
- "Face for lines in a diff for their side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-context
- '((((class color) (background light)) :foreground "grey50")
- (((class color) (background dark)) :foreground "grey70"))
- "Face for lines in a diff that are unchanged."
- :group 'magit-faces)
-
-(defface magit-diff-added-highlight
- '((((class color) (background light))
- :background "#cceecc"
- :foreground "#22aa22")
- (((class color) (background dark))
- :background "#336633"
- :foreground "#cceecc"))
- "Face for lines in a diff that have been added."
- :group 'magit-faces)
-
-(defface magit-diff-removed-highlight
- '((((class color) (background light))
- :background "#eecccc"
- :foreground "#aa2222")
- (((class color) (background dark))
- :background "#663333"
- :foreground "#eecccc"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-our-highlight
- '((t :inherit magit-diff-removed-highlight))
- "Face for lines in a diff for our side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-base-highlight
- '((((class color) (background light))
- :background "#eeeebb"
- :foreground "#aaaa11")
- (((class color) (background dark))
- :background "#666622"
- :foreground "#eeeebb"))
- "Face for lines in a diff for the base side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-their-highlight
- '((t :inherit magit-diff-added-highlight))
- "Face for lines in a diff for their side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-context-highlight
- '((((class color) (background light))
- :background "grey95"
- :foreground "grey50")
- (((class color) (background dark))
- :background "grey20"
- :foreground "grey70"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-whitespace-warning
- '((t :inherit trailing-whitespace))
- "Face for highlighting whitespace errors added lines."
- :group 'magit-faces)
-
-(defface magit-diffstat-added
- '((((class color) (background light)) :foreground "#22aa22")
- (((class color) (background dark)) :foreground "#448844"))
- "Face for plus sign in diffstat."
- :group 'magit-faces)
-
-(defface magit-diffstat-removed
- '((((class color) (background light)) :foreground "#aa2222")
- (((class color) (background dark)) :foreground "#aa4444"))
- "Face for minus sign in diffstat."
- :group 'magit-faces)
-
-;;; Commands
-
-(defconst magit-diff-popup-common
- '(:variable magit-diff-arguments
- :man-page "git-diff"
- :options ((?f "Limit to files" "-- " magit-read-files)
- (?u "Context lines" "-U")
- (?m "Detect renames" "-M")
- (?c "Detect copies" "-C")
- (?a "Diff algorithm" "--diff-algorithm="
- magit-diff-select-algorithm))))
-
-(defvar magit-diff-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff")
- (?s "Show stats" "--stat"))
- :actions ((?d "Dwim" magit-diff-dwim)
- (?u "Diff unstaged" magit-diff-unstaged)
- (?c "Show commit" magit-show-commit)
- (?r "Diff range" magit-diff)
- (?s "Diff staged" magit-diff-staged)
- (?t "Show stash" magit-stash-show)
- (?p "Diff paths" magit-diff-paths)
- (?w "Diff worktree" magit-diff-working-tree))
- :default-action magit-diff-dwim
- :max-action-columns 3))
-
-(defvar magit-diff-refresh-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff"))
- :actions ((?g "Refresh" magit-diff-refresh)
- (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
- (?s "Set defaults" magit-diff-set-default-arguments) nil
- (?w "Save defaults" magit-diff-save-default-arguments))
- :max-action-columns 2))
-
-(defvar magit-diff-mode-refresh-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff")
- (?s "Show stats" "--stat"))
- :actions ((?g "Refresh" magit-diff-refresh)
- (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
- (?s "Set defaults" magit-diff-set-default-arguments)
- (?r "Switch range type" magit-diff-switch-range-type)
- (?w "Save defaults" magit-diff-save-default-arguments)
- (?f "Flip revisions" magit-diff-flip-revs))
- :max-action-columns 2))
-
-(defvar magit-revision-mode-refresh-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff")
- (?s "Show stats" "--stat"))
- :actions ((?g "Refresh" magit-diff-refresh)
- (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
- (?s "Set defaults" magit-diff-set-default-arguments) nil
- (?w "Save defaults" magit-diff-save-default-arguments))
- :max-action-columns 2))
-
-(magit-define-popup-keys-deferred 'magit-diff-popup)
-(magit-define-popup-keys-deferred 'magit-diff-refresh-popup)
-(magit-define-popup-keys-deferred 'magit-diff-mode-refresh-popup)
-(magit-define-popup-keys-deferred 'magit-revision-mode-refresh-popup)
-
-(defcustom magit-diff-arguments '("--stat" "--no-ext-diff")
- "The diff arguments used in buffers whose mode derives from `magit-diff-mode'."
- :group 'magit-diff
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-diff-section-arguments '("--no-ext-diff")
- "The diff arguments used in buffers that show other things besides diffs."
- :group 'magit-diff
- :group 'magit-status
- :type '(repeat (string :tag "Argument")))
-
-(defvar magit-diff-section-file-args nil)
-(put 'magit-diff-section-file-args 'permanent-local t)
-(put 'magit-diff-section-arguments 'permanent-local t)
-
-(defun magit-diff-arguments (&optional refresh)
- (cond ((memq magit-current-popup '(magit-diff-popup magit-diff-refresh-popup))
- (magit-popup-export-file-args magit-current-popup-args))
- ((derived-mode-p 'magit-diff-mode)
- (list (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args)))
- (refresh
- (list magit-diff-section-arguments
- magit-diff-section-file-args))
- (t
- (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
- (with-current-buffer buffer
- (list (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args)))
- (list (default-value 'magit-diff-arguments) nil)))))
-
-(defun magit-diff-popup (arg)
- "Popup console for diff commands."
- (interactive "P")
- (let ((magit-diff-arguments
- ;; We cannot possibly know what suffix command the user is
- ;; about to invoke, so we also don't know from which buffer
- ;; we should get the current values. However it is much
- ;; more likely that we will end up updating the diff buffer,
- ;; and we therefore use the value from that buffer.
- (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
- (with-current-buffer buffer
- (magit-popup-import-file-args (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args)))
- (default-value 'magit-diff-arguments))))
- (magit-invoke-popup 'magit-diff-popup nil arg)))
-
-(defun magit-diff-refresh-popup (arg)
- "Popup console for changing diff arguments in the current buffer."
- (interactive "P")
- (let ((magit-diff-refresh-popup
- (pcase major-mode
- (`magit-revision-mode magit-revision-mode-refresh-popup)
- (`magit-diff-mode magit-diff-mode-refresh-popup)
- (_ magit-diff-refresh-popup)))
- (magit-diff-arguments
- (if (derived-mode-p 'magit-diff-mode)
- (magit-popup-import-file-args (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args))
- (magit-popup-import-file-args magit-diff-section-arguments
- magit-diff-section-file-args))))
- (magit-invoke-popup 'magit-diff-refresh-popup nil arg)))
-
-(defun magit-diff-select-algorithm (&rest _ignore)
- (magit-read-char-case nil t
- (?d "[d]efault" "default")
- (?m "[m]inimal" "minimal")
- (?p "[p]atience" "patience")
- (?h "[h]istogram" "histogram")))
-
-;;;###autoload
-(defun magit-diff-dwim (&optional args files)
- "Show changes for the thing at point."
- (interactive (magit-diff-arguments))
- (pcase (magit-diff--dwim)
- (`unstaged (magit-diff-unstaged args files))
- (`staged (magit-diff-staged nil args files))
- (`(commit . ,value)
- (magit-diff (format "%s^..%s" value value) args files))
- (`(stash . ,value) (magit-stash-show value args))
- ((and range (pred stringp))
- (magit-diff range args files))
- (_
- (call-interactively #'magit-diff))))
-
-(defun magit-diff--dwim ()
- "Return information for performing DWIM diff.
-
-The information can be in three forms:
-1. TYPE
- A symbol describing a type of diff where no additional information
- is needed to generate the diff. Currently, this includes `staged'
- and `unstaged'.
-2. (TYPE . VALUE)
- Like #1 but the diff requires additional information, which is
- given by VALUE. Currently, this includes `commit' and `stash',
- where VALUE is the given commit or stash, respectively.
-3. RANGE
- A string indicating a diff range.
-
-If no DWIM context is found, nil is returned."
- (cond
- ((--when-let (magit-region-values 'commit 'branch)
- (deactivate-mark)
- (concat (car (last it)) ".." (car it))))
- (magit-buffer-refname
- (cons 'commit magit-buffer-refname))
- ((derived-mode-p 'magit-revision-mode)
- (cons 'commit (car magit-refresh-args)))
- ((derived-mode-p 'magit-diff-mode)
- (nth 0 magit-refresh-args))
- (t
- (magit-section-case
- ([* unstaged] 'unstaged)
- ([* staged] 'staged)
- (unpushed (magit-section-value it))
- (unpulled (magit-section-value it))
- (branch (let ((current (magit-get-current-branch))
- (atpoint (magit-section-value it)))
- (if (equal atpoint current)
- (--if-let (magit-get-upstream-branch)
- (format "%s...%s" it current)
- (if (magit-anything-modified-p)
- current
- (cons 'commit current)))
- (format "%s..%s" atpoint current))))
- (commit (cons 'commit (magit-section-value it)))
- (stash (cons 'stash (magit-section-value it)))))))
-
-(defun magit-diff-read-range-or-commit (prompt &optional secondary-default mbase)
- "Read range or revision with special diff range treatment.
-If MBASE is non-nil, prompt for which rev to place at the end of
-a \"revA...revB\" range. Otherwise, always construct
-\"revA..revB\" range."
- (--if-let (magit-region-values 'commit 'branch)
- (let ((revA (car (last it)))
- (revB (car it)))
- (deactivate-mark)
- (if mbase
- (let ((base (magit-git-string "merge-base" revA revB)))
- (cond
- ((string= (magit-rev-parse revA) base)
- (format "%s..%s" revA revB))
- ((string= (magit-rev-parse revB) base)
- (format "%s..%s" revB revA))
- (t
- (let ((main (magit-completing-read "View changes along"
- (list revA revB)
- nil t nil nil revB)))
- (format "%s...%s"
- (if (string= main revB) revA revB) main)))))
- (format "%s..%s" revA revB)))
- (magit-read-range prompt
- (or (pcase (magit-diff--dwim)
- (`(commit . ,value)
- (format "%s^..%s" value value))
- ((and range (pred stringp))
- range))
- secondary-default
- (magit-get-current-branch)))))
-
-(defun magit-diff-setup (rev-or-range const args files)
- (require 'magit)
- (magit-mode-setup #'magit-diff-mode rev-or-range const args files))
-
-;;;###autoload
-(defun magit-diff (rev-or-range &optional args files)
- "Show differences between two commits.
-
-REV-OR-RANGE should be a range or a single revision. If it is a
-revision, then show changes in the working tree relative to that
-revision. If it is a range, but one side is omitted, then show
-changes relative to `HEAD'.
-
-If the region is active, use the revisions on the first and last
-line of the region as the two sides of the range. With a prefix
-argument, instead of diffing the revisions, choose a revision to
-view changes along, starting at the common ancestor of both
-revisions (i.e., use a \"...\" range)."
- (interactive (cons (magit-diff-read-range-or-commit "Diff for range"
- nil current-prefix-arg)
- (magit-diff-arguments)))
- (magit-diff-setup rev-or-range nil args files))
-
-;;;###autoload
-(defun magit-diff-working-tree (&optional rev args files)
- "Show changes between the current working tree and the `HEAD' commit.
-With a prefix argument show changes between the working tree and
-a commit read from the minibuffer."
- (interactive
- (cons (and current-prefix-arg
- (magit-read-branch-or-commit "Diff working tree and commit"))
- (magit-diff-arguments)))
- (magit-diff-setup (or rev "HEAD") nil args files))
-
-;;;###autoload
-(defun magit-diff-staged (&optional rev args files)
- "Show changes between the index and the `HEAD' commit.
-With a prefix argument show changes between the index and
-a commit read from the minibuffer."
- (interactive
- (cons (and current-prefix-arg
- (magit-read-branch-or-commit "Diff index and commit"))
- (magit-diff-arguments)))
- (magit-diff-setup rev (list "--cached") args files))
-
-;;;###autoload
-(defun magit-diff-unstaged (&optional args files)
- "Show changes between the working tree and the index."
- (interactive (magit-diff-arguments))
- (magit-diff-setup nil nil args files))
-
-;;;###autoload
-(defun magit-diff-while-committing (&optional args files)
- "While committing, show the changes that are about to be committed.
-While amending, invoking the command again toggles between
-showing just the new changes or all the changes that will
-be committed."
- (interactive (magit-diff-arguments))
- (let ((toplevel (magit-toplevel))
- (diff-buf (magit-mode-get-buffer 'magit-diff-mode)))
- (if (magit-commit-message-buffer)
- (if (and (or ;; most likely an explicit amend
- (not (magit-anything-staged-p))
- ;; explicitly toggled from within diff
- (and (eq (current-buffer) diff-buf)))
- (or (not diff-buf)
- (with-current-buffer diff-buf
- (or ;; default to include last commit
- (not (equal (magit-toplevel) toplevel))
- ;; toggle to include last commit
- (not (car magit-refresh-args))))))
- (magit-diff-while-amending args files)
- (magit-diff-staged nil args files))
- (user-error "No commit in progress"))))
-
-(define-key git-commit-mode-map
- (kbd "C-c C-d") 'magit-diff-while-committing)
-
-(defun magit-diff-while-amending (&optional args files)
- (magit-diff-setup "HEAD^" (list "--cached") args files))
-
-;;;###autoload
-(defun magit-diff-paths (a b)
- "Show changes between any two files on disk."
- (interactive (list (read-file-name "First file: " nil nil t)
- (read-file-name "Second file: " nil nil t)))
- (magit-diff-setup nil (list "--no-index")
- nil (list (expand-file-name a)
- (expand-file-name b))))
-
-;;;###autoload
-(defun magit-show-commit (rev &optional args files module)
- "Show the revision at point.
-If there is no revision at point or with a prefix argument prompt
-for a revision."
- (interactive
- (let* ((mcommit (magit-section-when module-commit))
- (atpoint (or (and (bound-and-true-p magit-blame-mode)
- (magit-blame-chunk-get :hash))
- mcommit
- (magit-branch-or-commit-at-point)
- (magit-tag-at-point))))
- (nconc (cons (or (and (not current-prefix-arg) atpoint)
- (magit-read-branch-or-commit "Show commit" atpoint))
- (magit-diff-arguments))
- (and mcommit (list (magit-section-parent-value
- (magit-current-section)))))))
- (require 'magit)
- (magit-with-toplevel
- (when module
- (setq default-directory
- (expand-file-name (file-name-as-directory module))))
- (unless (magit-rev-verify-commit rev)
- (user-error "%s is not a commit" rev))
- (-when-let (buffer (magit-mode-get-buffer 'magit-revision-mode))
- (with-current-buffer buffer
- (let ((prev (car magit-refresh-args)))
- (unless (equal rev prev)
- (dolist (child (cdr (magit-section-children magit-root-section)))
- (when (eq (magit-section-type child) 'file)
- (magit-section-cache-visibility child)))))))
- (magit-mode-setup #'magit-revision-mode rev nil args files)))
-
-(defun magit-diff-refresh (args files)
- "Set the local diff arguments for the current buffer."
- (interactive (magit-diff-arguments t))
- (cond ((derived-mode-p 'magit-diff-mode)
- (setcdr (cdr magit-refresh-args) (list args files)))
- (t
- (setq-local magit-diff-section-arguments args)
- (setq-local magit-diff-section-file-args files)))
- (magit-refresh))
-
-(defun magit-diff-set-default-arguments (args files)
- "Set the global diff arguments for the current buffer."
- (interactive (magit-diff-arguments t))
- (cond ((derived-mode-p 'magit-diff-mode)
- (customize-set-variable 'magit-diff-arguments args)
- (setcdr (cdr magit-refresh-args) (list args files)))
- (t
- (customize-set-variable 'magit-diff-section-arguments args)
- (kill-local-variable 'magit-diff-section-arguments)
- (kill-local-variable 'magit-diff-section-file-args)))
- (magit-refresh))
-
-(defun magit-diff-save-default-arguments (args files)
- "Set and save the global diff arguments for the current buffer."
- (interactive (magit-diff-arguments t))
- (cond ((derived-mode-p 'magit-diff-mode)
- (customize-save-variable 'magit-diff-arguments args)
- (setcdr (cdr magit-refresh-args) (list args files)))
- (t
- (customize-save-variable 'magit-diff-section-arguments args)
- (kill-local-variable 'magit-diff-section-arguments)
- (kill-local-variable 'magit-diff-section-file-args)))
- (magit-refresh))
-
-(defun magit-diff-switch-range-type ()
- "Convert diff range type.
-Change \"revA..revB\" to \"revB...revA\", or vice versa."
- (interactive)
- (let ((range (car magit-refresh-args)))
- (if (and range
- (derived-mode-p 'magit-diff-mode)
- (string-match magit-range-re range))
- (progn
- (setcar magit-refresh-args
- (concat (match-string 1 range)
- (if (string= (match-string 2 range) "..")
- "..."
- "..")
- (match-string 3 range)))
- (magit-refresh))
- (user-error "No range to change"))))
-
-(defun magit-diff-flip-revs ()
- "Swap revisions in diff range.
-Change \"revA..revB\" to \"revB..revA\"."
- (interactive)
- (let ((range (car magit-refresh-args)))
- (if (and range
- (derived-mode-p 'magit-diff-mode)
- (string-match magit-range-re range))
- (progn
- (setcar magit-refresh-args
- (concat (match-string 3 range)
- (match-string 2 range)
- (match-string 1 range)))
- (magit-refresh))
- (user-error "No range to swap"))))
-
-(defun magit-diff-less-context (&optional count)
- "Decrease the context for diff hunks by COUNT lines."
- (interactive "p")
- (magit-diff-set-context `(lambda (cur) (max 0 (- (or cur 0) ,count)))))
-
-(defun magit-diff-more-context (&optional count)
- "Increase the context for diff hunks by COUNT lines."
- (interactive "p")
- (magit-diff-set-context `(lambda (cur) (+ (or cur 0) ,count))))
-
-(defun magit-diff-default-context ()
- "Reset context for diff hunks to the default height."
- (interactive)
- (magit-diff-set-context #'ignore))
-
-(defun magit-diff-set-context (fn)
- (let* ((def (--if-let (magit-get "diff.context") (string-to-number it) 3))
- (val (car (magit-diff-arguments t)))
- (arg (--first (string-match "^-U\\([0-9]+\\)?$" it) val))
- (num (--if-let (and arg (match-string 1 arg)) (string-to-number it) def))
- (val (delete arg val))
- (num (funcall fn num))
- (arg (and num (not (= num def)) (format "-U%i" num)))
- (val (if arg (cons arg val) val)))
- (if (derived-mode-p 'magit-diff-mode)
- (setcar (cddr magit-refresh-args) val)
- (setq magit-diff-section-arguments val)))
- (magit-refresh))
-
-(defun magit-diff-context-p ()
- (--if-let (--first (string-match "^-U\\([0-9]+\\)$" it)
- (car (magit-diff-arguments t)))
- (not (equal "-U0" it))
- t))
-
-(defun magit-diff-toggle-refine-hunk (&optional style)
- "Turn diff-hunk refining on or off.
-
-If hunk refining is currently on, then hunk refining is turned off.
-If hunk refining is off, then hunk refining is turned on, in
-`selected' mode (only the currently selected hunk is refined).
-
-With a prefix argument, the \"third choice\" is used instead:
-If hunk refining is currently on, then refining is kept on, but
-the refining mode (`selected' or `all') is switched.
-If hunk refining is off, then hunk refining is turned on, in
-`all' mode (all hunks refined).
-
-Customize variable `magit-diff-refine-hunk' to change the default mode."
- (interactive "P")
- (setq-local magit-diff-refine-hunk
- (if style
- (if (eq magit-diff-refine-hunk 'all) t 'all)
- (not magit-diff-refine-hunk)))
- (magit-diff-update-hunk-refinement))
-
-(defun magit-diff-visit-file (file &optional other-window force-worktree)
- "From a diff, visit the corresponding file at the appropriate position.
-
-When the file is already being displayed in another window of the
-same frame, then just select that window and adjust point. With
-a prefix argument also display in another window.
-
-If the diff shows changes in the worktree, the index, or `HEAD',
-then visit the actual file. Otherwise when the diff is about
-an older commit, then visit the respective blob using
-`magit-find-file'. Also see `magit-diff-visit-file-worktree'
-which, as the name suggests always visits the actual file."
- (interactive (list (--if-let (magit-file-at-point)
- (expand-file-name it)
- (user-error "No file at point"))
- current-prefix-arg))
- (if (file-accessible-directory-p file)
- (magit-diff-visit-directory file other-window)
- (let ((current (magit-current-section))
- (rev (cond (force-worktree nil)
- ((derived-mode-p 'magit-revision-mode)
- (car magit-refresh-args))
- ((derived-mode-p 'magit-diff-mode)
- (--when-let (car magit-refresh-args)
- (and (string-match "\\.\\.\\([^.].*\\)?[ \t]*\\'" it)
- (match-string 1 it))))))
- (unmerged-p (magit-anything-unmerged-p file))
- hunk line col buffer)
- (when (and rev (magit-rev-head-p rev))
- (setq rev nil))
- (setq hunk
- (pcase (magit-diff-scope)
- ((or `hunk `region) current)
- ((or `file `files) (car (magit-section-children current)))
- (`list (car (magit-section-children
- (car (magit-section-children current)))))))
- (when (and hunk
- ;; Currently the `hunk' type is also abused for file
- ;; mode changes. Luckily such sections have no value.
- (magit-section-value hunk))
- (setq line (magit-diff-hunk-line hunk)
- col (magit-diff-hunk-column hunk)))
- (setq buffer (if rev
- (magit-find-file-noselect rev file)
- (or (get-file-buffer file)
- (find-file-noselect file))))
- (magit-display-file-buffer buffer)
- (with-current-buffer buffer
- (when line
- (goto-char (point-min))
- (forward-line (1- line))
- (when col
- (move-to-column col)))
- (when unmerged-p
- (smerge-start-session))
- (run-hooks 'magit-diff-visit-file-hook)))))
-
-(defvar magit-display-file-buffer-function
- 'magit-display-file-buffer-traditional
- "The function used by `magit-diff-visit-file' to display blob buffers.
-
-Other commands such as `magit-find-file' do not use this
-function. Instead they use high-level functions to select the
-window to be used to display the buffer. This variable and the
-related functions are an experimental feature and should be
-treated as such.")
-
-(defun magit-display-file-buffer (buffer)
- (funcall magit-display-file-buffer-function buffer))
-
-(defun magit-display-file-buffer-traditional (buffer)
- (if (or current-prefix-arg (get-buffer-window buffer))
- (pop-to-buffer buffer)
- (switch-to-buffer buffer)))
-
-(defun magit-diff-visit-file-worktree (file &optional other-window)
- "From a diff, visit the corresponding file at the appropriate position.
-
-When the file is already being displayed in another window of the
-same frame, then just select that window and adjust point. With
-a prefix argument also display in another window.
-
-The actual file in the worktree is visited. The positions in the
-hunk headers get less useful the \"older\" the changes are, and
-as a result, jumping to the appropriate position gets less
-reliable.
-
-Also see `magit-diff-visit-file' which visits the respective
-blob, unless the diff shows changes in the worktree, the index,
-or `HEAD'."
- (interactive (list (or (magit-file-at-point)
- (user-error "No file at point"))
- current-prefix-arg))
- (magit-diff-visit-file file other-window t))
-
-(defun magit-diff-hunk-line (section)
- (let* ((value (magit-section-value section))
- (prefix (- (length value) 2))
- (cpos (marker-position (magit-section-content section)))
- (stop (line-number-at-pos))
- (cstart (save-excursion (goto-char cpos) (line-number-at-pos)))
- (line (car (last value))))
- (string-match "^\\+\\([0-9]+\\)" line)
- (setq line (string-to-number (match-string 1 line)))
- (when (> cstart stop)
- (save-excursion
- (goto-char cpos)
- (re-search-forward "^[-+]")
- (setq stop (line-number-at-pos))))
- (save-excursion
- (goto-char cpos)
- (while (< (line-number-at-pos) stop)
- (unless (string-match-p
- "-" (buffer-substring (point) (+ (point) prefix)))
- (cl-incf line))
- (forward-line)))
- line))
-
-(defun magit-diff-hunk-column (section)
- (if (or (< (point) (magit-section-content section))
- (save-excursion (beginning-of-line) (looking-at-p "-")))
- 0
- (max 0 (- (+ (current-column) 2)
- (length (magit-section-value section))))))
-
-(defun magit-diff-visit-directory (directory &optional other-window)
- (if (equal (magit-toplevel directory)
- (magit-toplevel))
- (magit-dired-jump other-window)
- (let ((display-buffer-overriding-action
- (if other-window
- '(nil (inhibit-same-window t))
- '(display-buffer-same-window))))
- (magit-status-internal directory))))
-
-(defun magit-diff-show-or-scroll-up ()
- "Update the commit or diff buffer for the thing at point.
-
-Either show the commit or stash at point in the appropriate
-buffer, or if that buffer is already being displayed in the
-current frame and contains information about that commit or
-stash, then instead scroll the buffer up. If there is no
-commit or stash at point, then prompt for a commit."
- (interactive)
- (magit-diff-show-or-scroll 'scroll-up))
-
-(defun magit-diff-show-or-scroll-down ()
- "Update the commit or diff buffer for the thing at point.
-
-Either show the commit or stash at point in the appropriate
-buffer, or if that buffer is already being displayed in the
-current frame and contains information about that commit or
-stash, then instead scroll the buffer down. If there is no
-commit or stash at point, then prompt for a commit."
- (interactive)
- (magit-diff-show-or-scroll 'scroll-down))
-
-(defun magit-diff-show-or-scroll (fn)
- (let (rev cmd buf win)
- (cond
- (magit-blame-mode
- (setq rev (magit-blame-chunk-get :hash)
- cmd 'magit-show-commit
- buf (magit-mode-get-buffer 'magit-revision-mode)))
- ((derived-mode-p 'git-rebase-mode)
- (save-excursion
- (goto-char (line-beginning-position))
- (--if-let (and (looking-at git-rebase-line)
- (match-string 2))
- (setq rev it
- cmd 'magit-show-commit
- buf (magit-mode-get-buffer 'magit-revision-mode))
- (user-error "No commit on this line"))))
- (t
- (magit-section-case
- ((commit branch)
- (setq rev (magit-section-value it)
- cmd 'magit-show-commit
- buf (magit-mode-get-buffer 'magit-revision-mode)))
- (stash
- (setq rev (magit-section-value it)
- cmd 'magit-stash-show
- buf (magit-mode-get-buffer 'magit-diff-mode))))))
- (if rev
- (if (and buf
- (setq win (get-buffer-window buf))
- (with-current-buffer buf
- (equal (if (eq cmd 'magit-stash-show)
- (concat rev "^2^.." rev)
- rev)
- (car magit-refresh-args))))
- (with-selected-window win
- (condition-case nil
- (funcall fn)
- (error
- (goto-char (pcase fn
- (`scroll-up (point-min))
- (`scroll-down (point-max)))))))
- (let ((magit-display-buffer-noselect t))
- (if (eq cmd 'magit-show-commit)
- (apply #'magit-show-commit rev (magit-diff-arguments))
- (funcall cmd rev))))
- (call-interactively #'magit-show-commit))))
-
-;;; Diff Mode
-
-(defvar magit-diff-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-c\C-d" 'magit-diff-while-committing)
- (define-key map "\C-c\C-b" 'magit-go-backward)
- (define-key map "\C-c\C-f" 'magit-go-forward)
- (define-key map "\s" 'scroll-up)
- (define-key map "\d" 'scroll-down)
- (define-key map "j" 'magit-jump-to-diffstat-or-diff)
- map)
- "Keymap for `magit-diff-mode'.")
-
-(define-derived-mode magit-diff-mode magit-mode "Magit Diff"
- "Mode for looking at a Git diff.
-
-This mode is documented in info node `(magit)Diff buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] to visit the hunk or file at point.
-
-Staging and applying changes is documented in info node
-`(magit)Staging and unstaging' and info node `(magit)Applying'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\{magit-diff-mode-map}"
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-diff-refresh-buffer (rev-or-range const _args files)
- "Refresh the current `magit-diff-mode' buffer.
-
-In such buffers the buffer-local value of `magit-refresh-args'
-has the same form as the arguments of this function. The value
-is set in `magit-mode-setup'."
- (setq header-line-format
- (propertize
- (if (member "--no-index" const)
- (apply #'format " Differences between %s and %s" files)
- (concat (if rev-or-range
- (if (string-match-p "\\.\\." rev-or-range)
- (format " Changes in %s" rev-or-range)
- (format " Changes from %s to working tree" rev-or-range))
- (if (member "--cached" const)
- " Staged changes"
- " Unstaged changes"))
- (pcase (length files)
- (0)
- (1 (concat " in file " (car files)))
- (_ (concat " in files "
- (mapconcat #'identity files ", "))))))
- 'face 'magit-header-line))
- (magit-insert-section (diffbuf)
- (run-hook-with-args 'magit-diff-sections-hook rev-or-range)))
-
-(defun magit-insert-diff (rev-or-range)
- "Insert the diff into this `magit-diff-mode' buffer."
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" rev-or-range "-p" "--no-prefix"
- (and (member "--stat" (nth 2 magit-refresh-args)) "--numstat")
- (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args) "--"
- (nth 3 magit-refresh-args)))
-
-(defvar magit-file-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [C-return] 'magit-diff-visit-file-worktree)
- (define-key map "\C-j" 'magit-diff-visit-file-worktree)
- (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "a" 'magit-apply)
- (define-key map "C" 'magit-commit-add-log)
- (define-key map "K" 'magit-file-untrack)
- (define-key map "R" 'magit-file-rename)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for `file' sections.")
-
-(defvar magit-hunk-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [C-return] 'magit-diff-visit-file-worktree)
- (define-key map "\C-j" 'magit-diff-visit-file-worktree)
- (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "a" 'magit-apply)
- (define-key map "C" 'magit-commit-add-log)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for `hunk' sections.")
-
-(defconst magit-diff-headline-re
- (concat "^\\(@@@?\\|diff\\|Submodule\\|"
- "\\* Unmerged path\\|merged\\|changed in both\\|"
- "added in remote\\|removed in remote\\)"))
-
-(defconst magit-diff-statline-re
- (concat "^ ?"
- "\\(.*\\)" ; file
- "\\( +| +\\)" ; separator
- "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?"
- "\\(\\+*\\)" ; add
- "\\(-*\\)$")) ; del
-
-(defconst magit-diff-submodule-re
- (concat "^Submodule \\([^ ]+\\) \\(?:"
- "\\([^ ]+ (new submodule)\\)\\|"
- "\\([^ ]+ (submodule deleted)\\)\\|"
- "\\(contains \\(?:modified\\|untracked\\) content\\)\\|"
- "\\([^ :]+\\)\\( (rewind)\\)?:\\)$"))
-
-(defun magit-diff-wash-diffs (args &optional limit)
- (when (member "--stat" args)
- (magit-diff-wash-diffstat))
- (when (re-search-forward magit-diff-headline-re limit t)
- (goto-char (line-beginning-position))
- (magit-wash-sequence (apply-partially 'magit-diff-wash-diff args))
- (insert ?\n)))
-
-(defun magit-jump-to-diffstat-or-diff ()
- "Jump to the diffstat or diff.
-When point is on a file inside the diffstat section, then jump
-to the respective diff section, otherwise jump to the diffstat
-section or a child thereof."
- (interactive)
- (--if-let (magit-get-section
- (append (magit-section-case
- ([file diffstat] `((file . ,(magit-section-value it))))
- (file `((file . ,(magit-section-value it)) (diffstat)))
- (t '((diffstat))))
- (magit-section-ident magit-root-section)))
- (magit-section-goto it)
- (user-error "No diffstat in this buffer")))
-
-(defun magit-diff-wash-diffstat ()
- (let (heading (beg (point)))
- (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t)
- (setq heading (match-string 1))
- (magit-delete-match)
- (goto-char beg)
- (magit-insert-section it (diffstat)
- (insert (propertize heading 'face 'magit-diff-file-heading))
- (magit-insert-heading)
- (let (files)
- (while (looking-at "^[-0-9]+\t[-0-9]+\t\\(.+\\)$")
- (push (magit-decode-git-path (match-string 1)) files)
- (magit-delete-line))
- (setq files (nreverse files))
- (while (looking-at magit-diff-statline-re)
- (magit-bind-match-strings (file sep cnt add del) nil
- (magit-delete-line)
- (when (string-match " +$" file)
- (setq sep (concat (match-string 0 file) sep))
- (setq file (substring file 0 (match-beginning 0))))
- (let ((le (length file)) ld)
- (setq file (magit-decode-git-path file))
- (setq ld (length file))
- (when (> le ld)
- (setq sep (concat (make-string (- le ld) ?\s) sep))))
- (magit-insert-section (file (pop files))
- (insert (propertize file 'face 'magit-filename) sep cnt " ")
- (when add
- (insert (propertize add 'face 'magit-diffstat-added)))
- (when del
- (insert (propertize del 'face 'magit-diffstat-removed)))
- (insert "\n")))))
- (if (looking-at "^$") (forward-line) (insert "\n"))))))
-
-(defun magit-diff-wash-diff (args)
- (cond
- ((looking-at magit-diff-submodule-re)
- (magit-diff-wash-submodule))
- ((looking-at "^\\* Unmerged path \\(.*\\)")
- (let ((file (magit-decode-git-path (match-string 1))))
- (magit-delete-line)
- (unless (and (derived-mode-p 'magit-status-mode)
- (not (member "--cached" args)))
- (magit-insert-section (file file)
- (insert (propertize
- (format "unmerged %s%s" file
- (pcase (cddr (car (magit-file-status file)))
- (`(?D ?D) " (both deleted)")
- (`(?D ?U) " (deleted by us)")
- (`(?U ?D) " (deleted by them)")
- (`(?A ?A) " (both added)")
- (`(?A ?U) " (added by us)")
- (`(?U ?A) " (added by them)")
- (`(?U ?U) "")))
- 'face 'magit-diff-file-heading))
- (insert ?\n))))
- t)
- ((looking-at (concat "^\\(merged\\|changed in both\\|"
- "added in remote\\|removed in remote\\)"))
- (let ((status (pcase (match-string 1)
- ("merged" "merged")
- ("changed in both" "conflict")
- ("added in remote" "new file")
- ("removed in remote" "deleted")))
- file orig base modes)
- (magit-delete-line)
- (while (looking-at
- "^ \\([^ ]+\\) +[0-9]\\{6\\} \\([a-z0-9]\\{40\\}\\) \\(.+\\)$")
- (magit-bind-match-strings (side _blob name) nil
- (pcase side
- ("result" (setq file name))
- ("our" (setq orig name))
- ("their" (setq file name))
- ("base" (setq base name))))
- (magit-delete-line))
- (when orig (setq orig (magit-decode-git-path orig)))
- (when file (setq file (magit-decode-git-path file)))
- (magit-diff-insert-file-section (or file base) orig status modes nil)))
- ((looking-at
- "^diff --\\(?:\\(git\\) \\(?:\\(.+?\\) \\2\\)?\\|\\(cc\\|combined\\) \\(.+\\)\\)")
- (let ((status (cond ((equal (match-string 1) "git") "modified")
- ((derived-mode-p 'magit-revision-mode) "resolved")
- (t "unmerged")))
- (file (or (match-string 2) (match-string 4)))
- (beg (point))
- orig header modes)
- (save-excursion
- (forward-line 1)
- (setq header (buffer-substring
- beg (if (re-search-forward magit-diff-headline-re nil t)
- (match-beginning 0)
- (point-max)))))
- (magit-delete-line)
- (while (not (or (eobp) (looking-at magit-diff-headline-re)))
- (if (looking-at "^old mode \\([^\n]+\\)\nnew mode \\([^\n]+\\)\n")
- (progn (setq modes (match-string 0))
- (magit-delete-match))
- (cond
- ((looking-at "^--- \\([^/].*?\\)\t?$") ; i.e. not /dev/null
- (setq orig (match-string 1)))
- ((looking-at "^\\+\\+\\+ \\([^/].*?\\)\t?$")
- (setq file (match-string 1)))
- ((looking-at "^\\(copy\\|rename\\) from \\(.+\\)$")
- (setq orig (match-string 2)))
- ((looking-at "^\\(copy\\|rename\\) to \\(.+\\)$")
- (setq file (match-string 2))
- (setq status (if (equal (match-string 1) "copy") "new file" "renamed")))
- ((looking-at "^\\(new file\\|deleted\\)")
- (setq status (match-string 1))))
- (magit-delete-line)))
- (when orig
- (setq orig (magit-decode-git-path orig)))
- (setq file (magit-decode-git-path file))
- ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used.
- (when (derived-mode-p 'magit-log-mode)
- (setq file (substring file 2))
- (when orig
- (setq orig (substring orig 2))))
- (magit-diff-insert-file-section file orig status modes header)))))
-
-(defun magit-diff-insert-file-section (file orig status modes header)
- (magit-insert-section section
- (file file (or (equal status "deleted")
- (derived-mode-p 'magit-status-mode)))
- (insert (propertize (format "%-10s %s\n" status
- (if (or (not orig) (equal orig file))
- file
- (format "%s -> %s" orig file)))
- 'face 'magit-diff-file-heading))
- (magit-insert-heading)
- (unless (equal orig file)
- (setf (magit-section-source section) orig))
- (setf (magit-section-diff-header section) header)
- (when modes
- (magit-insert-section (hunk)
- (insert modes)))
- (magit-wash-sequence #'magit-diff-wash-hunk)))
-
-(defun magit-diff-wash-submodule ()
- (magit-bind-match-strings (module new deleted dirty range rewind) nil
- (magit-delete-line)
- (when (and dirty
- (looking-at magit-diff-submodule-re)
- (string= (match-string 1) module))
- (setq range (match-string 5))
- (magit-delete-line))
- (while (looking-at "^ \\([<>]\\) \\(.+\\)$")
- (magit-delete-line))
- (if range
- (let ((default-directory
- (file-name-as-directory
- (expand-file-name module (magit-toplevel)))))
- (setf (magit-section-value
- (magit-insert-section (file module t)
- (magit-insert-heading
- (concat (propertize (concat "modified " module)
- 'face 'magit-diff-file-heading)
- " ("
- (if rewind "rewind" "new commits")
- (and dirty ", modified content")
- ")"))
- (unless rewind
- (magit-git-wash
- (apply-partially 'magit-log-wash-log 'module)
- "log" "--oneline" "--left-right" range)
- (delete-char -1))))
- module))
- (magit-insert-section (file module)
- (insert (propertize (if new
- (concat "new module " module)
- (concat "modified " module))
- 'face 'magit-diff-file-heading))
- (cond (dirty (insert " (modified content)"))
- (deleted (insert " (deleted submodule)")))
- (insert ?\n)))))
-
-(defun magit-diff-wash-hunk ()
- (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?")
- (let ((heading (match-string 0))
- (value (cons (match-string 2) (split-string (match-string 1)))))
- (magit-delete-line)
- (magit-insert-section it (hunk value)
- (insert (propertize (concat heading "\n") 'face 'magit-diff-hunk-heading))
- (magit-insert-heading)
- (while (not (or (eobp) (looking-at "^[^-+\s\\]")))
- (forward-line))
- (setf (magit-section-end it) (point))
- (setf (magit-section-washer it) #'magit-diff-paint-hunk)))
- t))
-
-(defun magit-diff-expansion-threshold (section)
- "Keep new diff sections collapsed if washing takes too long."
- (and (memq (magit-section-type section) '(file))
- (> (float-time (time-subtract (current-time) magit-refresh-start-time))
- magit-diff-expansion-threshold)
- 'hide))
-
-;;; Revision Mode
-
-(define-derived-mode magit-revision-mode magit-diff-mode "Magit Rev"
- "Mode for looking at a Git commit.
-
-This mode is documented in info node `(magit)Revision buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] to visit the hunk or file at point.
-
-Staging and applying changes is documented in info node
-`(magit)Staging and unstaging' and info node `(magit)Applying'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\{magit-revision-mode-map}"
- :group 'magit-revision
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-revision-refresh-buffer (rev __const _args _files)
- (setq header-line-format
- (propertize (format " %s %s" (capitalize (magit-object-type rev)) rev)
- 'face 'magit-header-line))
- (magit-insert-section (commitbuf)
- (run-hook-with-args 'magit-revision-sections-hook rev)))
-
-(defun magit-insert-revision-diff (rev)
- "Insert the diff into this `magit-revision-mode' buffer."
- ;; Before v2.2.0, "--format=" did not mean "no output".
- ;; Instead the default format was used. So use "--format=%n"
- ;; and then delete the empty lines.
- (magit-git-wash (lambda (args)
- (delete-region (point) (progn (forward-line 3) (point)))
- (magit-diff-wash-diffs args))
- "show" "-p" "--cc" "--format=%n" "--no-prefix"
- (and (member "--stat" (nth 2 magit-refresh-args)) "--numstat")
- (nth 2 magit-refresh-args) (concat rev "^{commit}") "--"
- (nth 3 magit-refresh-args)))
-
-(defun magit-insert-revision-tag (rev)
- "Insert tag message and headers into a revision buffer.
-This function only inserts anything when `magit-show-commit' is
-called with a tag as argument, when that is called with a commit
-or a ref which is not a branch, then it inserts nothing."
- (when (equal (magit-object-type rev) "tag")
- (magit-insert-section (taginfo)
- (let ((beg (point)))
- (magit-git-insert "cat-file" "tag" rev)
- (goto-char beg)
- (forward-line 3)
- (delete-region beg (point)))
- (looking-at "^tagger \\([^<]+\\) <\\([^>]+\\)")
- (let ((heading (format "Tagger: %s <%s>"
- (match-string 1)
- (match-string 2))))
- (magit-delete-line)
- (insert (propertize heading 'face 'magit-section-secondary-heading)))
- (magit-insert-heading)
- (goto-char (point-max))
- (insert ?\n))))
-
-(defun magit-insert-revision-message (rev)
- "Insert the commit message into a revision buffer."
- (magit-insert-section (message)
- (let ((beg (point)))
- (magit-rev-insert-format "%B" rev)
- (if (= (point) (+ beg 2))
- (progn (backward-delete-char 2)
- (insert "(no message)\n"))
- (goto-char beg)
- (forward-line)
- (put-text-property beg (point) 'face 'magit-section-secondary-heading)
- (magit-insert-heading)
- (goto-char (point-max))))))
-
-(defun magit-insert-revision-notes (rev)
- "Insert commit notes into a revision buffer."
- (magit-insert-section (notes)
- (let ((beg (point)))
- (magit-git-insert "notes" "show" rev)
- (if (= (point) beg)
- (magit-cancel-section)
- (goto-char beg)
- (forward-line)
- (put-text-property beg (point) 'face 'magit-section-secondary-heading)
- (magit-insert-heading)
- (goto-char (point-max))
- (insert ?\n)))))
-
-(defun magit-insert-revision-headers (rev)
- "Insert headers about the commit into a revision buffer."
- (magit-insert-section (headers)
- ;; Before v2.2.0, "%D" was not supported.
- (--when-let (magit-rev-format "%d" rev "--decorate=full")
- (insert (magit-format-ref-labels (substring it 2 -1)) ?\s))
- (insert (propertize (magit-rev-parse (concat rev "^{commit}"))
- 'face 'magit-hash))
- (magit-insert-heading)
- (let ((beg (point)))
- (magit-rev-insert-format magit-revision-headers-format rev)
- (magit-insert-revision-gravatars rev beg))
- (when magit-revision-insert-related-refs
- (dolist (parent (magit-commit-parents rev))
- (magit-insert-section (commit parent)
- (let ((line (magit-rev-format "%h %s" parent)))
- (string-match "^\\([^ ]+\\) \\(.*\\)" line)
- (magit-bind-match-strings (hash msg) line
- (insert "Parent: ")
- (insert (propertize hash 'face 'magit-hash))
- (insert " " msg "\n")))))
- (-when-let (merged (magit-list-merged-branches rev))
- (insert "Merged: ")
- (let (branch)
- (while (and (< (+ (- (point) (line-beginning-position))
- (length (car merged)) 9)
- (window-width))
- (setq branch (pop merged)))
- (insert ?\s)
- (magit-insert-section (branch branch)
- (insert (propertize branch 'face 'magit-branch-local)))))
- (when merged
- (insert (format " (%s more)" (length merged))))
- (insert ?\n))
- (-when-let (containing (magit-list-containing-branches rev))
- (insert "Containing:")
- (let (branch)
- (while (and (< (+ (- (point) (line-beginning-position))
- (length (car containing)) 9)
- (window-width))
- (setq branch (pop containing)))
- (insert ?\s)
- (magit-insert-section (branch branch)
- (insert (propertize branch 'face 'magit-branch-local)))))
- (when containing
- (insert (format " (%s more)" (length containing))))
- (insert ?\n))
- (-when-let (follows (magit-get-current-tag rev t))
- (let ((tag (car follows))
- (cnt (cadr follows)))
- (magit-insert-section (tag tag)
- (insert (format "Follows: %s (%s)\n"
- (propertize tag 'face 'magit-tag)
- (propertize (number-to-string cnt)
- 'face 'magit-branch-local))))))
- (-when-let (precedes (magit-get-next-tag rev t))
- (let ((tag (car precedes))
- (cnt (cadr precedes)))
- (magit-insert-section (tag tag)
- (insert (format "Precedes: %s (%s)\n"
- (propertize tag 'face 'magit-tag)
- (propertize (number-to-string cnt)
- 'face 'magit-tag))))))
- (insert ?\n))))
-
-(defun magit-insert-revision-gravatars (rev beg)
- (when (and magit-revision-show-gravatars (window-system))
- (require 'gravatar)
- (magit-insert-revision-gravatar beg (magit-rev-format "%aE" rev)
- (car magit-revision-show-gravatars))
- (magit-insert-revision-gravatar beg (magit-rev-format "%cE" rev)
- (cdr magit-revision-show-gravatars))
- (goto-char (point-max))))
-
-(defun magit-insert-revision-gravatar (beg email regexp)
- (when (and email (goto-char beg) (re-search-forward regexp nil t))
- (ignore-errors
- (let* ((offset (length (match-string 0)))
- (font-obj (query-font (font-at (point) (get-buffer-window))))
- (size (* 2 (+ (aref font-obj 4) (aref font-obj 5))))
- (align-to (+ offset (ceiling (/ size (aref font-obj 7) 1.0))))
- (gravatar-size (- size 2))
- (slice1 '(slice .0 .0 1.0 0.5))
- (slice2 '(slice .0 .5 1.0 1.0)))
- (gravatar-retrieve
- email
- (lambda (image offset align-to slice1 slice2)
- (unless (eq image 'error)
- (insert (propertize " " 'display `((,@image :ascent center :relief 1)
- ,slice1)))
- (insert (propertize " " 'display `((space :align-to ,align-to))))
- (forward-line)
- (forward-char offset)
- (insert (propertize " " 'display `((,@image :ascent center :relief 1)
- ,slice2)))
- (insert (propertize " " 'display `((space :align-to ,align-to))))))
- (list offset align-to
- (if magit-revision-use-gravatar-kludge slice2 slice1)
- (if magit-revision-use-gravatar-kludge slice1 slice2)))))))
-
-;;; Diff Sections
-
-(defvar magit-unstaged-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-unstaged)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for the `unstaged' section.")
-
-(magit-define-section-jumper magit-jump-to-unstaged "Unstaged changes" unstaged)
-
-(defun magit-insert-unstaged-changes ()
- "Insert section showing unstaged changes."
- (magit-insert-section (unstaged)
- (magit-insert-heading "Unstaged changes:")
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" magit-diff-section-arguments "--no-prefix"
- "--" magit-diff-section-file-args)))
-
-(defvar magit-staged-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-staged)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for the `staged' section.")
-
-(magit-define-section-jumper magit-jump-to-staged "Staged changes" staged)
-
-(defun magit-insert-staged-changes ()
- "Insert section showing staged changes."
- (magit-insert-section (staged)
- (magit-insert-heading "Staged changes:")
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" "--cached" magit-diff-section-arguments "--no-prefix"
- "--" magit-diff-section-file-args)))
-
-;;; Diff Type
-
-(defun magit-diff-type (&optional section)
- "Return the diff type of SECTION.
-
-The returned type is one of the symbols `staged', `unstaged',
-`committed', or `undefined'. This type serves a similar purpose
-as the general type common to all sections (which is stored in
-the `type' slot of the corresponding `magit-section' struct) but
-takes additional information into account. When the SECTION
-isn't related to diffs and the buffer containing it also isn't
-a diff-only buffer, then return nil.
-
-Currently the type can also be one of `tracked' and `untracked'
-but these values are not handled explicitly everywhere they
-should be and a possible fix could be to just return nil here.
-
-The section has to be a `diff' or `hunk' section, or a section
-whose children are of type `diff'. If optional SECTION is nil,
-return the diff type for the current section. In buffers whose
-major mode is `magit-diff-mode' SECTION is ignored and the type
-is determined using other means. In `magit-revision-mode'
-buffers the type is always `committed'.
-
-Do not confuse this with `magit-diff-scope' (which see)."
- (--when-let (or section (magit-current-section))
- (cond ((derived-mode-p 'magit-revision-mode 'magit-stash-mode) 'committed)
- ((derived-mode-p 'magit-diff-mode)
- (let ((range (nth 0 magit-refresh-args))
- (const (nth 1 magit-refresh-args)))
- (cond ((member "--no-index" const) 'undefined)
- ((not range)
- (if (member "--cached" const)
- 'staged
- 'unstaged))
- ((member "--cached" const)
- (if (magit-rev-head-p range)
- 'staged
- 'undefined)) ; i.e. committed and staged
- (t 'committed))))
- ((derived-mode-p 'magit-status-mode)
- (let ((stype (magit-section-type it)))
- (if (memq stype '(staged unstaged tracked untracked))
- stype
- (pcase stype
- (`file (let* ((parent (magit-section-parent it))
- (type (magit-section-type parent)))
- (if (eq type 'file)
- (magit-diff-type parent)
- type)))
- (`hunk (-> it magit-section-parent magit-section-parent
- magit-section-type))))))
- ((derived-mode-p 'magit-log-mode)
- (if (or (and (magit-section-match 'commit section)
- (magit-section-children section))
- (magit-section-match [* file commit] section))
- 'committed
- 'undefined))
- (t 'undefined))))
-
-(cl-defun magit-diff-scope (&optional (section nil ssection) strict)
- "Return the diff scope of SECTION or the selected section(s).
-
-A diff's \"scope\" describes what part of a diff is selected, it is
-a symbol, one of `region', `hunk', `hunks', `file', `files', or
-`list'. Do not confuse this with the diff \"type\", as returned by
-`magit-diff-type'.
-
-If optional SECTION is non-nil, then return the scope of that,
-ignoring the sections selected by the region. Otherwise return
-the scope of the current section, or if the region is active and
-selects a valid group of diff related sections, the type of these
-sections, i.e. `hunks' or `files'. If SECTION, or if that is nil
-the current section, is a `hunk' section; and the region region
-starts and ends inside the body of a that section, then the type
-is `region'.
-
-If optional STRICT is non-nil then return nil if the diff type of
-the section at point is `untracked' or the section at point is not
-actually a `diff' but a `diffstat' section."
- (let ((siblings (and (not ssection) (magit-region-sections))))
- (setq section (or section (car siblings) (magit-current-section)))
- (when (and section
- (or (not strict)
- (and (not (eq (magit-diff-type section) 'untracked))
- (not (eq (--when-let (magit-section-parent section)
- (magit-section-type it))
- 'diffstat)))))
- (pcase (list (magit-section-type section)
- (and siblings t)
- (and (region-active-p) t)
- ssection)
- (`(hunk nil t ,_)
- (if (magit-section-internal-region-p section) 'region 'hunk))
- (`(hunk t t nil) 'hunks)
- (`(hunk ,_ ,_ ,_) 'hunk)
- (`(file t t nil) 'files)
- (`(file ,_ ,_ ,_) 'file)
- (`(,(or `staged `unstaged `untracked)
- nil ,_ ,_) 'list)))))
-
-;;; Diff Highlight
-
-(defun magit-diff-unhighlight (section selection)
- "Remove the highlighting of the diff-related SECTION."
- (when (eq (magit-section-type section) 'hunk)
- (magit-diff-paint-hunk section selection nil)
- t))
-
-(defun magit-diff-highlight (section selection)
- "Highlight the diff-related SECTION and return t.
-If SECTION is not a diff-related section, then do nothing and
-return nil. If SELECTION is non-nil then it is a list of sections
-selected by the region, including SECTION. All of these sections
-are highlighted."
- (if (and (magit-section-match 'commit section)
- (magit-section-children section))
- (progn (if selection
- (dolist (section selection)
- (magit-diff-highlight-list section selection))
- (magit-diff-highlight-list section))
- t)
- (-when-let (scope (magit-diff-scope section t))
- (cond ((eq scope 'region)
- (magit-diff-paint-hunk section selection t))
- (selection
- (dolist (section selection)
- (magit-diff-highlight-recursive section selection)))
- (t
- (magit-diff-highlight-recursive section)))
- t)))
-
-(defun magit-diff-highlight-recursive (section &optional selection)
- (pcase (magit-diff-scope section)
- (`list (magit-diff-highlight-list section selection))
- (`file (magit-diff-highlight-file section selection))
- (`hunk (magit-diff-highlight-heading section selection)
- (magit-diff-paint-hunk section selection t))
- (_ (magit-section-highlight section nil))))
-
-(defun magit-diff-highlight-list (section &optional selection)
- (let ((beg (magit-section-start section))
- (cnt (magit-section-content section))
- (end (magit-section-end section)))
- (unless (and (region-active-p)
- (= end (1+ (region-end))))
- (magit-section-make-overlay beg cnt 'magit-section-highlight)
- (unless (magit-section-hidden section)
- (dolist (child (magit-section-children section))
- (magit-diff-highlight-recursive child selection))))
- (when magit-diff-highlight-hunk-body
- (magit-section-make-overlay (1- end) end 'magit-section-highlight))))
-
-(defun magit-diff-highlight-file (section &optional selection)
- (magit-diff-highlight-heading section selection)
- (unless (magit-section-hidden section)
- (dolist (child (magit-section-children section))
- (magit-diff-highlight-recursive child selection))))
-
-(defun magit-diff-highlight-heading (section &optional selection)
- (magit-section-make-overlay
- (magit-section-start section)
- (or (magit-section-content section)
- (magit-section-end section))
- (pcase (list (magit-section-type section)
- (and (member section selection) t))
- (`(file t) 'magit-diff-file-heading-selection)
- (`(file nil) 'magit-diff-file-heading-highlight)
- (`(hunk t) 'magit-diff-hunk-heading-selection)
- (`(hunk nil) 'magit-diff-hunk-heading-highlight))))
-
-;;; Hunk Paint
-
-(cl-defun magit-diff-paint-hunk
- (section &optional selection
- (highlight (magit-section-selected-p section selection)))
- (let (paint)
- (unless magit-diff-highlight-hunk-body
- (setq highlight nil))
- (cond (highlight
- (unless (magit-section-hidden section)
- (add-to-list 'magit-section-highlighted-sections section)
- (cond ((memq section magit-section-unhighlight-sections)
- (setq magit-section-unhighlight-sections
- (delq section magit-section-unhighlight-sections)))
- (magit-diff-highlight-hunk-body
- (setq paint t)))))
- (t
- (cond ((and (magit-section-hidden section)
- (memq section magit-section-unhighlight-sections))
- (add-to-list 'magit-section-highlighted-sections section)
- (setq magit-section-unhighlight-sections
- (delq section magit-section-unhighlight-sections)))
- (t
- (setq paint t)))))
- (when paint
- (save-excursion
- (goto-char (magit-section-start section))
- (let ((end (magit-section-end section))
- (merging (looking-at "@@@"))
- (stage nil))
- (forward-line)
- (while (< (point) end)
- (put-text-property
- (point) (1+ (line-end-position)) 'face
- (cond
- ((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}")
- (setq stage (pcase (list (match-string 1) highlight)
- (`("<" nil) 'magit-diff-our)
- (`("<" t) 'magit-diff-our-highlight)
- (`("|" nil) 'magit-diff-base)
- (`("|" t) 'magit-diff-base-highlight)
- (`("=" nil) 'magit-diff-their)
- (`("=" t) 'magit-diff-their-highlight)
- (`(">" nil) nil)))
- 'magit-diff-conflict-heading)
- ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+"))
- (magit-diff-paint-whitespace merging)
- (or stage
- (if highlight 'magit-diff-added-highlight 'magit-diff-added)))
- ((looking-at (if merging "^\\(-\\| -\\)" "^-"))
- (if highlight 'magit-diff-removed-highlight 'magit-diff-removed))
- (t
- (if highlight 'magit-diff-context-highlight 'magit-diff-context))))
- (forward-line))))))
- (magit-diff-update-hunk-refinement section))
-
-(defun magit-diff-paint-whitespace (merging)
- (when (and magit-diff-paint-whitespace
- (or (derived-mode-p 'magit-status-mode)
- (not (eq magit-diff-paint-whitespace 'status))))
- (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+]"))
- (indent
- (if (local-variable-p 'magit-diff-highlight-indentation)
- magit-diff-highlight-indentation
- (setq-local
- magit-diff-highlight-indentation
- (cdr (--first (string-match-p (car it) default-directory)
- (nreverse
- (default-value
- 'magit-diff-highlight-indentation))))))))
- (when (and magit-diff-highlight-trailing
- (looking-at (concat prefix ".*?\\([ \t]+\\)$")))
- (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
- (overlay-put ov 'face 'magit-diff-whitespace-warning)
- (overlay-put ov 'evaporate t)))
- (when (or (and (eq indent 'tabs)
- (looking-at (concat prefix "\\( *\t[ \t]*\\)")))
- (and (integerp indent)
- (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)"
- prefix indent))))
- (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
- (overlay-put ov 'face 'magit-diff-whitespace-warning)
- (overlay-put ov 'evaporate t))))))
-
-(defun magit-diff-update-hunk-refinement (&optional section)
- (if section
- (unless (magit-section-hidden section)
- (pcase (list magit-diff-refine-hunk
- (magit-section-refined section)
- (eq section (magit-current-section)))
- ((or `(all nil ,_) `(t nil t))
- (setf (magit-section-refined section) t)
- (save-excursion
- (goto-char (magit-section-start section))
- ;; `diff-refine-hunk' does not handle combined diffs.
- (unless (looking-at "@@@")
- (diff-refine-hunk))))
- ((or `(nil t ,_) `(t t nil))
- (setf (magit-section-refined section) nil)
- (remove-overlays (magit-section-start section)
- (magit-section-end section)
- 'diff-mode 'fine))))
- (cl-labels ((recurse (section)
- (if (magit-section-match 'hunk section)
- (magit-diff-update-hunk-refinement section)
- (--each (magit-section-children section)
- (recurse it)))))
- (recurse magit-root-section))))
-
-
-;;; Highlight Region
-
-(defvar magit-diff-unmarked-lines-keep-foreground t)
-
-(defun magit-diff-update-hunk-region (section)
- (when (and (eq (magit-diff-scope section t) 'region)
- (not (and (eq this-command 'mouse-drag-region)
- (eq (mark) (point)))))
- (let ((sbeg (magit-section-start section))
- (cbeg (magit-section-content section))
- (rbeg (save-excursion (goto-char (region-beginning))
- (line-beginning-position)))
- (rend (save-excursion (goto-char (region-end))
- (line-end-position)))
- (send (magit-section-end section))
- (face (if magit-diff-highlight-hunk-body
- 'magit-diff-context-highlight
- 'magit-diff-context)))
- (when magit-diff-unmarked-lines-keep-foreground
- (setq face (list :background (face-attribute face :background))))
- (cl-flet ((ov (start end &rest args)
- (let ((ov (make-overlay start end nil t)))
- (overlay-put ov 'evaporate t)
- (while args (overlay-put ov (pop args) (pop args)))
- (push ov magit-region-overlays)
- ov)))
- (ov sbeg cbeg 'face 'magit-diff-lines-heading
- 'display (concat (magit-diff-hunk-region-header section) "\n"))
- (ov cbeg rbeg 'face face 'priority 2)
- (when (and (window-system) magit-diff-show-lines-boundary)
- (ov rbeg (1+ rbeg) 'before-string
- (propertize (concat (propertize "\s" 'display '(space :height (1)))
- (propertize "\n" 'line-height t))
- 'face 'magit-diff-lines-boundary))
- (ov rend (1+ rend) 'after-string
- (propertize (concat (propertize "\s" 'display '(space :height (1)))
- (propertize "\n" 'line-height t))
- 'face 'magit-diff-lines-boundary)))
- (ov (1+ rend) send 'face face 'priority 2)))))
-
-;;; Diff Extract
-
-(defun magit-diff-file-header (section)
- (when (eq (magit-section-type section) 'hunk)
- (setq section (magit-section-parent section)))
- (when (eq (magit-section-type section) 'file)
- (magit-section-diff-header section)))
-
-(defun magit-diff-hunk-region-header (section)
- (let ((patch (magit-diff-hunk-region-patch section)))
- (string-match "\n" patch)
- (substring patch 0 (1- (match-end 0)))))
-
-(defun magit-diff-hunk-region-patch (section &optional args)
- (let ((op (if (member "--reverse" args) "+" "-"))
- (sbeg (magit-section-start section))
- (rbeg (save-excursion
- (goto-char (region-beginning))
- (line-beginning-position)))
- (rend (region-end))
- (send (magit-section-end section))
- (patch nil))
- (save-excursion
- (goto-char sbeg)
- (while (< (point) send)
- (looking-at "\\(.\\)\\([^\n]*\n\\)")
- (cond ((or (string-match-p "[@ ]" (match-string-no-properties 1))
- (and (>= (point) rbeg)
- (<= (point) rend)))
- (push (match-string-no-properties 0) patch))
- ((equal op (match-string-no-properties 1))
- (push (concat " " (match-string-no-properties 2)) patch)))
- (forward-line)))
- (with-temp-buffer
- (insert (mapconcat 'identity (reverse patch) ""))
- (diff-fixup-modifs (point-min) (point-max))
- (setq patch (buffer-string)))
- patch))
-
-;;; magit-diff.el ends soon
-(provide 'magit-diff)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-diff.el ends here
+++ /dev/null
-;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library provides basic support for Ediff.
-
-;;; Code:
-
-(require 'magit)
-
-(require 'ediff)
-(require 'smerge-mode)
-
-(defvar smerge-ediff-buf)
-(defvar smerge-ediff-windows)
-
-(defgroup magit-ediff nil
- "Ediff support for Magit."
- :group 'magit-extensions)
-
-(unless (find-lisp-object-file-name 'magit-ediff-quit-hook 'defvar)
- (add-hook 'magit-ediff-quit-hook 'magit-ediff-restore-previous-winconf)
- (add-hook 'magit-ediff-quit-hook 'magit-ediff-cleanup-auxiliary-buffers))
-(defcustom magit-ediff-quit-hook
- '(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.
-The `ediff-quit-hook' is ignored by Ediff sessions which were
-invoked using Magit."
- :package-version '(magit . "2.2.0")
- :group 'magit-ediff
- :type 'hook
- :options '(magit-ediff-cleanup-auxiliary-buffers
- magit-ediff-restore-previous-winconf))
-
-(defcustom magit-ediff-dwim-show-on-hunks nil
- "Whether `magit-ediff-dwim' runs show variants on hunks.
-If non-nil, `magit-ediff-show-staged' or
-`magit-ediff-show-unstaged' are called based on what section the
-hunk is in. Otherwise, `magit-ediff-dwim' runs
-`magit-ediff-stage' when point is on an uncommitted hunk."
- :package-version '(magit . "2.2.0")
- :group 'magit-ediff
- :type 'boolean)
-
-(defvar magit-ediff-previous-winconf nil)
-
-;;;###autoload (autoload 'magit-ediff-popup "magit-ediff" nil t)
-(magit-define-popup magit-ediff-popup
- "Popup console for ediff commands."
- 'magit-diff nil nil
- :actions '((?E "Dwim" magit-ediff-dwim)
- (?u "Show unstaged" magit-ediff-show-unstaged)
- (?s "Stage" magit-ediff-stage)
- (?i "Show staged" magit-ediff-show-staged)
- (?m "Resolve" magit-ediff-resolve)
- (?w "Show worktree" magit-ediff-show-working-tree)
- (?r "Diff range" magit-ediff-compare)
- (?c "Show commit" magit-ediff-show-commit))
- :max-action-columns 2)
-
-;;;###autoload
-(defun magit-ediff-resolve (file)
- "Resolve outstanding conflicts in FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-In the rare event that you want to manually resolve all
-conflicts, including those already resolved by Git, use
-`ediff-merge-revisions-with-ancestor'."
- (interactive
- (let ((current (magit-current-file))
- (unmerged (magit-unmerged-files)))
- (unless unmerged
- (user-error "There are no unresolved conflicts"))
- (list (magit-completing-read "Resolve file" unmerged nil t nil nil
- (car (member current unmerged))))))
- (magit-with-toplevel
- (with-current-buffer (find-file-noselect file)
- (smerge-ediff)
- (setq-local
- ediff-quit-hook
- (lambda ()
- (let ((bufC ediff-buffer-C)
- (bufS smerge-ediff-buf))
- (with-current-buffer bufS
- (when (yes-or-no-p (format "Conflict resolution finished; save %s?"
- buffer-file-name))
- (erase-buffer)
- (insert-buffer-substring bufC)
- (save-buffer))))
- (when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A))
- (when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B))
- (when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C))
- (when (buffer-live-p ediff-ancestor-buffer)
- (kill-buffer ediff-ancestor-buffer))
- (let ((magit-ediff-previous-winconf smerge-ediff-windows))
- (run-hooks 'magit-ediff-quit-hook)))))))
-
-;;;###autoload
-(defun magit-ediff-stage (file)
- "Stage and unstage changes to FILE using Ediff.
-FILE has to be relative to the top directory of the repository."
- (interactive
- (list (magit-completing-read "Selectively stage file" nil
- (magit-tracked-files) nil nil nil
- (magit-current-file))))
- (magit-with-toplevel
- (let* ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-buffer (concat file ".~{index}~")))
- (bufBrw (and bufB (with-current-buffer bufB (not buffer-read-only))))
- (bufC (get-file-buffer file)))
- (ediff-buffers3
- (or bufA (magit-find-file-noselect "HEAD" file))
- (with-current-buffer (magit-find-file-index-noselect file t)
- (setq buffer-read-only nil)
- (current-buffer))
- (or bufC (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- (and (buffer-live-p ediff-buffer-B)
- (buffer-modified-p ediff-buffer-B)
- (with-current-buffer ediff-buffer-B
- (magit-update-index)))
- (and (buffer-live-p ediff-buffer-C)
- (buffer-modified-p ediff-buffer-C)
- (with-current-buffer ediff-buffer-C
- (when (y-or-n-p
- (format "Save file %s? " buffer-file-name))
- (save-buffer))))
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(if bufB
- (unless bufBrw '((with-current-buffer ediff-buffer-B
- (setq buffer-read-only t))))
- '((ediff-kill-buffer-carefully ediff-buffer-B)))
- ,@(unless bufC '((ediff-kill-buffer-carefully ediff-buffer-C)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers3))))
-
-;;;###autoload
-(defun magit-ediff-compare (revA revB fileA fileB)
- "Compare REVA:FILEA with REVB:FILEB using Ediff.
-
-FILEA and FILEB have to be relative to the top directory of the
-repository. If REVA or REVB is nil then this stands for the
-working tree state.
-
-If the region is active, use the revisions on the first and last
-line of the region. With a prefix argument, instead of diffing
-the revisions, choose a revision to view changes along, starting
-at the common ancestor of both revisions (i.e., use a \"...\"
-range)."
- (interactive (-let [(revA revB) (magit-ediff-compare--read-revisions
- nil current-prefix-arg)]
- (nconc (list revA revB)
- (magit-ediff-compare--read-files revA revB))))
- (magit-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (if revA
- (magit-get-revision-buffer revA fileA)
- (get-file-buffer fileA)))
- (bufB (if revB
- (magit-get-revision-buffer revB fileB)
- (get-file-buffer fileB))))
- (ediff-buffers
- (or bufA (if revA
- (magit-find-file-noselect revA fileA)
- (find-file-noselect fileA)))
- (or bufB (if revB
- (magit-find-file-noselect revB fileB)
- (find-file-noselect fileB)))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-revision))))
-
-(defun magit-ediff-compare--read-revisions (&optional arg mbase)
- (let ((input (or arg (magit-diff-read-range-or-commit "Compare range or commit"
- nil mbase)))
- revA revB)
- (if (string-match magit-range-re input)
- (progn (setq revA (or (match-string 1 input) "HEAD")
- revB (or (match-string 3 input) "HEAD"))
- (when (string= (match-string 2 input) "...")
- (setq revA (magit-git-string "merge-base" revA revB))))
- (setq revA input))
- (list revA revB)))
-
-(defun magit-ediff-compare--read-files (revA revB &optional fileB)
- (unless fileB
- (setq fileB (magit-read-file-choice
- (format "File to compare between %s and %s"
- revA (or revB "the working tree"))
- (magit-changed-files revA revB)
- (format "No changed files between %s and %s"
- revA (or revB "the working tree")))))
- (list (or (car (member fileB (magit-revision-files revA)))
- (cdr (assoc fileB (magit-renamed-files revB revA)))
- (magit-read-file-choice
- (format "File in %s to compare with %s in %s"
- revA fileB (or revB "the working tree"))
- (magit-changed-files revB revA)
- (format "File in %s to compare with %s in %s"
- revA fileB (or revB "the working tree"))))
- fileB))
-
-;;;###autoload
-(defun magit-ediff-dwim ()
- "Compare, stage, or resolve using Ediff.
-This command tries to guess what file, and what commit or range
-the user wants to compare, stage, or resolve using Ediff. It
-might only be able to guess either the file, or range or commit,
-in which case the user is asked about the other. It might not
-always guess right, in which case the appropriate `magit-ediff-*'
-command has to be used explicitly. If it cannot read the user's
-mind at all, then it asks the user for a command to run."
- (interactive)
- (magit-section-case
- (hunk (save-excursion
- (goto-char (magit-section-start (magit-section-parent it)))
- (magit-ediff-dwim)))
- (t
- (let ((range (magit-diff--dwim))
- (file (magit-current-file))
- command revA revB)
- (pcase range
- ((and (guard (not magit-ediff-dwim-show-on-hunks))
- (or `unstaged `staged))
- (setq command (if (magit-anything-unmerged-p)
- #'magit-ediff-resolve
- #'magit-ediff-stage)))
- (`unstaged (setq command #'magit-ediff-show-unstaged))
- (`staged (setq command #'magit-ediff-show-staged))
- (`(commit . ,value)
- (setq command #'magit-ediff-show-commit
- revB value))
- ((pred stringp)
- (-let [(a b) (magit-ediff-compare--read-revisions range)]
- (setq command #'magit-ediff-compare
- revA a
- revB b)))
- (_
- (when (derived-mode-p 'magit-diff-mode)
- (pcase (magit-diff-type)
- (`committed (-let [(a b) (magit-ediff-compare--read-revisions
- (car magit-refresh-args))]
- (setq revA a revB b)))
- ((guard (not magit-ediff-dwim-show-on-hunks))
- (setq command #'magit-ediff-stage))
- (`unstaged (setq command #'magit-ediff-show-unstaged))
- (`staged (setq command #'magit-ediff-show-staged))
- (`undefined (setq command nil))
- (_ (setq command nil))))))
- (cond ((not command)
- (call-interactively
- (magit-read-char-case
- "Failed to read your mind; do you want to " t
- (?c "[c]ommit" 'magit-ediff-show-commit)
- (?r "[r]ange" 'magit-ediff-compare)
- (?s "[s]tage" 'magit-ediff-stage)
- (?v "resol[v]e" 'magit-ediff-resolve))))
- ((eq command 'magit-ediff-compare)
- (apply 'magit-ediff-compare revA revB
- (magit-ediff-compare--read-files revA revB file)))
- ((eq command 'magit-ediff-show-commit)
- (magit-ediff-show-commit revB))
- (file
- (funcall command file))
- (t
- (call-interactively command)))))))
-
-;;;###autoload
-(defun magit-ediff-show-staged (file)
- "Show staged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository."
- (interactive
- (list (magit-read-file-choice "Show staged changes for file"
- (magit-staged-files)
- "No staged files")))
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-buffer (concat file ".~{index}~"))))
- (ediff-buffers
- (or bufA (magit-find-file-noselect "HEAD" file))
- (or bufB (magit-find-file-index-noselect file t))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers)))
-
-;;;###autoload
-(defun magit-ediff-show-unstaged (file)
- "Show unstaged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository."
- (interactive
- (list (magit-read-file-choice "Show unstaged changes for file"
- (magit-modified-files)
- "No unstaged files")))
- (magit-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (get-buffer (concat file ".~{index}~")))
- (bufB (get-file-buffer file)))
- (ediff-buffers
- (or bufA (magit-find-file-index-noselect file t))
- (or bufB (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers))))
-
-;;;###autoload
-(defun magit-ediff-show-working-tree (file)
- "Show changes between HEAD and working tree using Ediff.
-FILE must be relative to the top directory of the repository."
- (interactive
- (list (magit-read-file-choice "Show changes in file"
- (magit-changed-files "HEAD")
- "No changed files")))
- (magit-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-file-buffer file)))
- (ediff-buffers
- (or bufA (magit-find-file-noselect "HEAD" file))
- (or bufB (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers))))
-
-;;;###autoload
-(defun magit-ediff-show-commit (commit)
- "Show changes introduced by COMMIT using Ediff."
- (interactive (list (magit-read-branch-or-commit "Revision")))
- (let ((revA (concat commit "^"))
- (revB commit))
- (apply #'magit-ediff-compare
- revA revB
- (magit-ediff-compare--read-files revA revB (magit-current-file)))))
-
-(defun magit-ediff-cleanup-auxiliary-buffers ()
- (let* ((ctl-buf ediff-control-buffer)
- (ctl-win (ediff-get-visible-buffer-window ctl-buf))
- (ctl-frm ediff-control-frame)
- (main-frame (cond ((window-live-p ediff-window-A)
- (window-frame ediff-window-A))
- ((window-live-p ediff-window-B)
- (window-frame ediff-window-B)))))
- (ediff-kill-buffer-carefully ediff-diff-buffer)
- (ediff-kill-buffer-carefully ediff-custom-diff-buffer)
- (ediff-kill-buffer-carefully ediff-fine-diff-buffer)
- (ediff-kill-buffer-carefully ediff-tmp-buffer)
- (ediff-kill-buffer-carefully ediff-error-buffer)
- (ediff-kill-buffer-carefully ediff-msg-buffer)
- (ediff-kill-buffer-carefully ediff-debug-buffer)
- (when (boundp 'ediff-patch-diagnostics)
- (ediff-kill-buffer-carefully ediff-patch-diagnostics))
- (cond ((and (ediff-window-display-p)
- (frame-live-p ctl-frm))
- (delete-frame ctl-frm))
- ((window-live-p ctl-win)
- (delete-window ctl-win)))
- (unless (ediff-multiframe-setup-p)
- (ediff-kill-bottom-toolbar))
- (ediff-kill-buffer-carefully ctl-buf)
- (when (frame-live-p main-frame)
- (select-frame main-frame))))
-
-(defun magit-ediff-restore-previous-winconf ()
- (set-window-configuration magit-ediff-previous-winconf))
-
-;;; magit-ediff.el ends soon
-(provide 'magit-ediff)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-ediff.el ends here
+++ /dev/null
-;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Additional functionality for Magit.
-
-;;; Code:
-
-(require 'magit)
-
-(defgroup magit-extras nil
- "Additional functionality for Magit."
- :group 'magit-extensions)
-
-;;; External Tools
-
-(defcustom magit-gitk-executable
- (or (and (eq system-type 'windows-nt)
- (let ((exe (expand-file-name
- "gitk" (file-name-nondirectory magit-git-executable))))
- (and (file-executable-p exe) exe)))
- (executable-find "gitk") "gitk")
- "The Gitk executable."
- :group 'magit-extras
- :set-after '(magit-git-executable)
- :type 'string)
-
-;;;###autoload
-(defun magit-run-git-gui ()
- "Run `git gui' for the current git repository."
- (interactive)
- (magit-with-toplevel
- (call-process magit-git-executable nil 0 nil "gui")))
-
-;;;###autoload
-(defun magit-run-git-gui-blame (commit filename &optional linenum)
- "Run `git gui blame' on the given FILENAME and COMMIT.
-Interactively run it for the current file and the HEAD, with a
-prefix or when the current file cannot be determined let the user
-choose. When the current buffer is visiting FILENAME instruct
-blame to center around the line point is on."
- (interactive
- (let (revision filename)
- (when (or current-prefix-arg
- (not (setq revision "HEAD"
- filename (magit-file-relative-name nil 'tracked))))
- (setq revision (magit-read-branch-or-commit "Blame from revision")
- filename (magit-read-file-from-rev revision "Blame file")))
- (list revision filename
- (and (equal filename
- (ignore-errors
- (magit-file-relative-name buffer-file-name)))
- (line-number-at-pos)))))
- (magit-with-toplevel
- (apply #'call-process magit-git-executable nil 0 nil "gui" "blame"
- `(,@(and linenum (list (format "--line=%d" linenum)))
- ,commit
- ,filename))))
-
-;;;###autoload
-(defun magit-run-gitk ()
- "Run `gitk' in the current repository."
- (interactive)
- (call-process magit-gitk-executable nil 0))
-
-;;;###autoload
-(defun magit-run-gitk-branches ()
- "Run `gitk --branches' in the current repository."
- (interactive)
- (call-process magit-gitk-executable nil 0 nil "--branches"))
-
-;;;###autoload
-(defun magit-run-gitk-all ()
- "Run `gitk --all' in the current repository."
- (interactive)
- (call-process magit-gitk-executable nil 0 nil "--all"))
-
-;;; Clean
-
-;;;###autoload
-(defun magit-clean (&optional arg)
- "Remove untracked files from the working tree.
-With a prefix argument also remove ignored files,
-with two prefix arguments remove ignored files only.
-\n(git clean -f -d [-x|-X])"
- (interactive "p")
- (when (yes-or-no-p (format "Remove %s files? "
- (pcase arg
- (1 "untracked")
- (4 "untracked and ignored")
- (_ "ignored"))))
- (magit-wip-commit-before-change)
- (magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X")))))
-
-(put 'magit-clean 'disabled t)
-
-;;; Gitignore
-
-;;;###autoload
-(defun magit-gitignore (file-or-pattern &optional local)
- "Instruct Git to ignore FILE-OR-PATTERN.
-With a prefix argument only ignore locally."
- (interactive (list (magit-gitignore-read-pattern current-prefix-arg)
- current-prefix-arg))
- (let ((gitignore
- (if local
- (magit-git-dir (convert-standard-filename "info/exclude"))
- (expand-file-name ".gitignore" (magit-toplevel)))))
- (make-directory (file-name-directory gitignore) t)
- (with-temp-buffer
- (when (file-exists-p gitignore)
- (insert-file-contents gitignore))
- (goto-char (point-max))
- (unless (bolp)
- (insert "\n"))
- (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" file-or-pattern))
- (insert "\n")
- (write-region nil nil gitignore))
- (if local
- (magit-refresh)
- (magit-run-git "add" ".gitignore"))))
-
-;;;###autoload
-(defun magit-gitignore-locally (file-or-pattern)
- "Instruct Git to locally ignore FILE-OR-PATTERN."
- (interactive (list (magit-gitignore-read-pattern t)))
- (magit-gitignore file-or-pattern t))
-
-(defun magit-gitignore-read-pattern (local)
- (let* ((default (magit-current-file))
- (choices
- (delete-dups
- (--mapcat
- (cons (concat "/" it)
- (-when-let (ext (file-name-extension it))
- (list (concat "/" (file-name-directory "foo") "*." ext)
- (concat "*." ext))))
- (magit-untracked-files)))))
- (when default
- (setq default (concat "/" default))
- (unless (member default choices)
- (setq default (concat "*." (file-name-extension default)))
- (unless (member default choices)
- (setq default nil))))
- (magit-completing-read (concat "File or pattern to ignore"
- (and local " locally"))
- choices nil nil nil nil default)))
-
-;;; ChangeLog
-
-;;;###autoload
-(defun magit-add-change-log-entry (&optional whoami file-name other-window)
- "Find change log file and add date entry and item for current change.
-This differs from `add-change-log-entry' (which see) in that
-it acts on the current hunk in a Magit buffer instead of on
-a position in a file-visiting buffer."
- (interactive (list current-prefix-arg
- (prompt-for-change-log-name)))
- (let (buf pos)
- (save-window-excursion
- (call-interactively #'magit-diff-visit-file)
- (setq buf (current-buffer)
- pos (point)))
- (save-excursion
- (with-current-buffer buf
- (goto-char pos)
- (add-change-log-entry whoami file-name other-window)))))
-
-;;;###autoload
-(defun magit-add-change-log-entry-other-window (&optional whoami file-name)
- "Find change log file in other window and add entry and item.
-This differs from `add-change-log-entry-other-window' (which see)
-in that it acts on the current hunk in a Magit buffer instead of
-on a position in a file-visiting buffer."
- (interactive (and current-prefix-arg
- (list current-prefix-arg
- (prompt-for-change-log-name))))
- (magit-add-change-log-entry whoami file-name t))
-
-;;; magit-extras.el ends soon
-(provide 'magit-extras)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-extras.el ends here
+++ /dev/null
-;;; magit-git.el --- Git functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements wrappers for various Git plumbing commands.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-utils)
-(require 'magit-section)
-
-(declare-function magit-process-buffer 'magit-process)
-(declare-function magit-process-file 'magit-process)
-(declare-function magit-process-insert-section 'magit-process)
-(defvar magit-process-error-message-re)
-(defvar magit-refresh-args) ; from `magit-mode' for `magit-current-file'
-(defvar magit-branch-prefer-remote-upstream)
-
-(defvar magit-tramp-process-environment nil)
-
-(require 'crm)
-
-;;; Options
-
-;; For now this is shared between `magit-process' and `magit-git'.
-(defgroup magit-process nil
- "Git and other external processes used by Magit."
- :group 'magit)
-
-(defvar magit-git-environment nil
- "Prepended to `process-environment' while running git.")
-
-(defcustom magit-git-executable
- ;; Git might be installed in a different location on a remote, so
- ;; it is better not to use the full path to the executable, except
- ;; on Window were we would otherwise end up using one one of the
- ;; wrappers "cmd/git.exe" or "cmd/git.cmd", which are much slower
- ;; than using "bin/git.exe" directly.
- (or (and (eq system-type 'windows-nt)
- (--when-let (executable-find "git.exe")
- (or (ignore-errors
- ;; Git for Windows 2.x provides cygpath so we can
- ;; ask it for native paths. Using an upper case
- ;; alias makes this fail on 1.x (which is good,
- ;; because we would not want to end up using some
- ;; other cygpath).
- (prog1 (car
- (process-lines
- it "-c"
- "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
- "X" "git"))
- (setq magit-git-environment
- (list (concat "PATH="
- (car (process-lines
- it "-c"
- "alias.P=!cygpath -wp \"$PATH\""
- "P")))))))
- ;; For 1.x, we search for bin/ next to cmd/.
- (let ((alt (directory-file-name (file-name-directory it))))
- (if (and (equal (file-name-nondirectory alt) "cmd")
- (setq alt (expand-file-name
- (convert-standard-filename "bin/git.exe")
- (file-name-directory alt)))
- (file-executable-p alt))
- alt
- it)))))
- "git")
- "The Git executable used by Magit."
- :group 'magit-process
- :type 'string)
-
-(defcustom magit-git-global-arguments
- '("--no-pager" "--literal-pathspecs" "-c" "core.preloadindex=true")
- "Global git arguments.
-
-The arguments set here are used every time the git executable is
-run as a subprocess. They are placed right after the executable
-itself and before the git command - as in `git HERE... COMMAND
-REST'. See the manpage `git(1)' for valid arguments.
-
-Be careful what you add here, especially if you are using Tramp
-to connect to servers with ancient Git versions. Never remove
-anything that is part of the default value, unless you really
-know what you are doing. And think very hard before adding
-something; it will be used every time Magit runs Git for any
-purpose."
- :package-version '(magit . "2.1.0")
- :group 'magit
- :type '(repeat string))
-
-(define-obsolete-variable-alias 'magit-git-standard-options
- 'magit-git-global-arguments "2.1.0")
-
-(defcustom magit-git-debug nil
- "Whether to enable additional reporting of git errors.
-
-Magit basically calls git for one of these two reasons: for
-side-effects or to do something with its standard output.
-
-When git is run for side-effects then its output, including error
-messages, go into the process buffer which is shown when using \
-\\<magit-status-mode-map>\\[magit-process].
-
-When git's output is consumed in some way, then it would be too
-expensive to also insert it into this buffer, but when this
-option is non-nil and git returns with a non-zero exit status,
-then at least its standard error is inserted into this buffer.
-
-This is only intended for debugging purposes. Do not enable this
-permanently, that would negatively affect performance"
- :group 'magit
- :group 'magit-process
- :type 'boolean)
-
-(defcustom magit-ref-namespaces
- '(("^@$" magit-head nil)
- ("^refs/tags/\\(.+\\)" magit-tag nil)
- ("^refs/heads/\\(.+\\)" magit-branch-local nil)
- ("^refs/remotes/\\(.+\\)" magit-branch-remote nil)
- ("^refs/bisect/\\(bad\\)" magit-bisect-bad nil)
- ("^refs/bisect/\\(skip.*\\)" magit-bisect-skip nil)
- ("^refs/bisect/\\(good.*\\)" magit-bisect-good nil)
- ("^refs/stash$" magit-refname-stash nil)
- ("^refs/wip/\\(.+\\)" magit-refname-wip nil)
- ("^\\(bad\\):" magit-bisect-bad nil)
- ("^\\(skip\\):" magit-bisect-skip nil)
- ("^\\(good\\):" magit-bisect-good nil)
- ("\\(.+\\)" magit-refname nil))
- "How refs are formatted for display.
-
-Each entry controls how a certain type of ref is displayed, and
-has the form (REGEXP FACE FORMATTER). REGEXP is a regular
-expression used to match full refs. The first entry whose REGEXP
-matches the reference is used. The first regexp submatch becomes
-the \"label\" that represents the ref and is propertized with
-font FONT. If FORMATTER is non-nil it should be a function that
-takes two arguments, the full ref and the face. It is supposed
-to return a propertized label that represents the ref."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type '(repeat
- (list regexp
- face
- (choice (const :tag "first submatch is label" nil)
- (function :tag "format using function")))))
-
-(defcustom magit-prefer-remote-upstream nil
- "Whether to favor remote branches when reading the upstream branch.
-
-This controls whether commands that read a branch from the user
-and then set it as the upstream branch, offer a local or a remote
-branch as default completion candidate, when they have the choice.
-
-This affects all commands that use `magit-read-upstream-branch'
-or `magit-read-starting-point', which includes all commands that
-change the upstream and many which create new branches."
- :package-version '(magit . "2.4.2")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Git
-
-(defun magit-process-git-arguments (args)
- "Prepare ARGS for a function that invokes Git.
-
-Magit has many specialized functions for running Git; they all
-pass arguments through this function before handing them to Git,
-to do the following.
-
-* Flatten ARGS, removing nil arguments.
-* Prepend `magit-git-global-arguments' to ARGS."
- (append magit-git-global-arguments (-flatten args)))
-
-(defun magit-git-exit-code (&rest args)
- "Execute Git with ARGS, returning its exit code."
- (apply #'magit-process-file magit-git-executable nil nil nil
- (magit-process-git-arguments args)))
-
-(defun magit-git-success (&rest args)
- "Execute Git with ARGS, returning t if its exit code is 0."
- (= (magit-git-exit-code args) 0))
-
-(defun magit-git-failure (&rest args)
- "Execute Git with ARGS, returning t if its exit code is 1."
- (= (magit-git-exit-code args) 1))
-
-(defun magit-git-str (&rest args)
- "Execute Git with ARGS, returning the first line of its output.
-If there is no output return nil. If the output begins with a
-newline return an empty string. Like `magit-git-string' but
-ignore `magit-git-debug'."
- (with-temp-buffer
- (apply #'magit-process-file magit-git-executable nil (list t nil) nil
- (magit-process-git-arguments args))
- (unless (bobp)
- (goto-char (point-min))
- (buffer-substring-no-properties (point) (line-end-position)))))
-
-(defun magit-git-true (&rest args)
- "Execute Git with ARGS, returning t if it prints \"true\".
-Return t if the first (and usually only) output line is the
-string \"true\", otherwise return nil."
- (equal (magit-git-str args) "true"))
-
-(defun magit-git-false (&rest args)
- "Execute Git with ARGS, returning t if it prints \"false\".
-Return t if the first (and usually only) output line is the
-string \"false\", otherwise return nil."
- (equal (magit-git-str args) "false"))
-
-(defun magit-git-insert (&rest args)
- "Execute Git with ARGS, inserting its output at point.
-If Git exits with a non-zero exit status, then show a message and
-add a section in the respective process buffer."
- (setq args (magit-process-git-arguments args))
- (if magit-git-debug
- (let (log)
- (unwind-protect
- (progn
- (setq log (make-temp-file "magit-stderr"))
- (delete-file log)
- (let ((exit (apply #'magit-process-file magit-git-executable
- nil (list t log) nil args)))
- (when (> exit 0)
- (let ((msg "Git failed"))
- (when (file-exists-p log)
- (setq msg (with-temp-buffer
- (insert-file-contents log)
- (goto-char (point-max))
- (and (re-search-backward
- magit-process-error-message-re nil t)
- (match-string 1))))
- (let ((magit-git-debug nil))
- (with-current-buffer (magit-process-buffer t)
- (magit-process-insert-section default-directory
- magit-git-executable
- args exit log))))
- (message "%s" msg)))
- exit))
- (ignore-errors (delete-file log))))
- (apply #'magit-process-file magit-git-executable
- nil (list t nil) nil args)))
-
-(defun magit-git-string (&rest args)
- "Execute Git with ARGS, returning the first line of its output.
-If there is no output return nil. If the output begins with a
-newline return an empty string."
- (with-temp-buffer
- (apply #'magit-git-insert args)
- (unless (bobp)
- (goto-char (point-min))
- (buffer-substring-no-properties (point) (line-end-position)))))
-
-(defun magit-git-lines (&rest args)
- "Execute Git with ARGS, returning its output as a list of lines.
-Empty lines anywhere in the output are omitted.
-
-If Git exits with a non-zero exit status, then report show a
-message and add a section in the respective process buffer."
- (with-temp-buffer
- (apply #'magit-git-insert args)
- (split-string (buffer-string) "\n" t)))
-
-(defun magit-git-items (&rest args)
- "Execute Git with ARGS, returning its null-separated output as a list.
-Empty items anywhere in the output are omitted.
-
-If Git exits with a non-zero exit status, then report show a
-message and add a section in the respective process buffer."
- (with-temp-buffer
- (apply #'magit-git-insert args)
- (split-string (buffer-string) "\0" t)))
-
-(defun magit-git-wash (washer &rest args)
- "Execute Git with ARGS, inserting washed output at point.
-Actually first insert the raw output at point. If there is no
-output call `magit-cancel-section'. Otherwise temporarily narrow
-the buffer to the inserted text, move to its beginning, and then
-call function WASHER with no argument."
- (declare (indent 1))
- (let ((beg (point)))
- (setq args (-flatten args))
- (magit-git-insert args)
- (if (= (point) beg)
- (magit-cancel-section)
- (unless (bolp)
- (insert "\n"))
- (save-restriction
- (narrow-to-region beg (point))
- (goto-char beg)
- (funcall washer args))
- (when (or (= (point) beg)
- (= (point) (1+ beg)))
- (magit-cancel-section)))))
-
-(defun magit-git-version (&optional raw)
- (--when-let (let (magit-git-global-arguments)
- (ignore-errors (substring (magit-git-string "version") 12)))
- (if raw it (and (string-match "^\\([0-9]+\\.[0-9]+\\.[0-9]+\\)" it)
- (match-string 1 it)))))
-
-;;; Files
-
-(defun magit--safe-default-directory (&optional file)
- (catch 'unsafe-default-dir
- (let ((dir (file-name-as-directory
- (expand-file-name (or file default-directory))))
- (previous nil))
- (while (not (file-accessible-directory-p dir))
- (setq dir (file-name-directory (directory-file-name dir)))
- (when (equal dir previous)
- (throw 'unsafe-default-dir nil))
- (setq previous dir))
- dir)))
-
-(defmacro magit--with-safe-default-directory (file &rest body)
- (declare (indent 1) (debug (form body)))
- `(-when-let (default-directory (magit--safe-default-directory ,file))
- ,@body))
-
-(defun magit-git-dir (&optional path)
- "Return absolute path to the control directory of the current repository.
-
-All symlinks are followed. If optional PATH is non-nil, then
-it has to be a path relative to the control directory and its
-absolute path is returned."
- (magit--with-safe-default-directory nil
- (--when-let (magit-rev-parse-safe "--git-dir")
- (setq it (file-name-as-directory (magit-expand-git-file-name it)))
- (if path (expand-file-name (convert-standard-filename path) it) it))))
-
-(defun magit-toplevel (&optional directory)
- "Return the absolute path to the toplevel of the current repository.
-
-From within the working tree or control directory of a repository
-return the absolute path to the toplevel directory of the working
-tree. As a special case, from within a bare repository return
-the control directory instead. When called outside a repository
-then return nil.
-
-When optional DIRECTORY is non-nil then return the toplevel for
-that directory instead of the one for `default-directory'.
-
-Try to respect the option `find-file-visit-truename', i.e. when
-the value of that option is nil, then avoid needlessly returning
-the truename. When a symlink to a sub-directory of the working
-tree is involved, or when called from within a sub-directory of
-the gitdir or from the toplevel of a gitdir, which itself is not
-located within the working tree, then it is not possible to avoid
-returning the truename."
- (magit--with-safe-default-directory directory
- (-if-let (topdir (magit-rev-parse-safe "--show-toplevel"))
- (let (updir)
- (setq topdir (magit-expand-git-file-name topdir))
- (if (and
- ;; Always honor these settings.
- (not find-file-visit-truename)
- (not (getenv "GIT_WORK_TREE"))
- ;; `--show-cdup' is the relative path to the toplevel
- ;; from `(file-truename default-directory)'. Here we
- ;; pretend it is relative to `default-directory', and
- ;; go to that directory. Then we check whether
- ;; `--show-toplevel' still returns the same value and
- ;; whether `--show-cdup' now is the empty string. If
- ;; both is the case, then we are at the toplevel of
- ;; the same working tree, but also avoided needlessly
- ;; following any symlinks.
- (progn
- (setq updir (file-name-as-directory
- (magit-rev-parse-safe "--show-cdup")))
- (setq updir (if (file-name-absolute-p updir)
- (concat (file-remote-p default-directory) updir)
- (expand-file-name updir)))
- (let ((default-directory updir))
- (and (string-equal (magit-rev-parse-safe "--show-cdup") "")
- (--when-let (magit-rev-parse-safe "--show-toplevel")
- (string-equal (magit-expand-git-file-name it)
- topdir))))))
- updir
- (concat (file-remote-p default-directory)
- (file-name-as-directory topdir))))
- (-when-let (gitdir (magit-rev-parse-safe "--git-dir"))
- (setq gitdir (file-name-as-directory
- (if (file-name-absolute-p gitdir)
- ;; We might have followed a symlink.
- (concat (file-remote-p default-directory)
- (magit-expand-git-file-name gitdir))
- (expand-file-name gitdir))))
- (if (magit-bare-repo-p)
- gitdir
- (let* ((link (expand-file-name "gitdir" gitdir))
- (wtree (and (file-exists-p link)
- (magit-file-line link))))
- (if (and wtree
- ;; Ignore .git/gitdir files that result from a
- ;; Git bug. See #2364.
- (not (equal wtree ".git")))
- ;; Return the linked working tree.
- (file-name-directory wtree)
- ;; Step outside the control directory to enter the working tree.
- (file-name-directory (directory-file-name gitdir)))))))))
-
-(defmacro magit-with-toplevel (&rest body)
- (declare (indent defun) (debug (body)))
- (let ((toplevel (cl-gensym "toplevel")))
- `(let ((,toplevel (magit-toplevel)))
- (if ,toplevel
- (let ((default-directory ,toplevel))
- ,@body)
- (error "Not inside a Git repository: %s" default-directory)))))
-
-(defun magit-inside-gitdir-p ()
- "Return t if `default-directory' is below a repository directory."
- (magit-rev-parse-p "--is-inside-git-dir"))
-
-(defun magit-inside-worktree-p ()
- "Return t if `default-directory' is below the work tree of a repository."
- (magit-rev-parse-p "--is-inside-work-tree"))
-
-(defun magit-bare-repo-p ()
- "Return t if the current repository is bare."
- (magit-rev-parse-p "--is-bare-repository"))
-
-(defun magit-git-repo-p (directory &optional non-bare)
- "Return t if DIRECTORY is a Git repository.
-When optional NON-BARE is non-nil also return nil if DIRECTORY is
-a bare repositories."
- (or (file-regular-p (expand-file-name ".git" directory))
- (file-directory-p (expand-file-name ".git" directory))
- (and (not non-bare)
- (file-regular-p (expand-file-name "HEAD" directory))
- (file-directory-p (expand-file-name "refs" directory))
- (file-directory-p (expand-file-name "objects" directory)))))
-
-(defvar-local magit-buffer-revision nil)
-(defvar-local magit-buffer-refname nil)
-(defvar-local magit-buffer-file-name nil)
-(put 'magit-buffer-revision 'permanent-local t)
-(put 'magit-buffer-refname 'permanent-local t)
-(put 'magit-buffer-file-name 'permanent-local t)
-
-(defun magit-file-relative-name (&optional file tracked)
- "Return the path of FILE relative to the repository root.
-
-If optional FILE is nil or omitted return the relative path of
-the file being visited in the current buffer, if any, else nil.
-If the file is not inside a Git repository then return nil.
-
-If TRACKED is non-nil, return the path only if it matches a
-tracked file."
- (unless file
- (with-current-buffer (or (buffer-base-buffer)
- (current-buffer))
- (setq file (or magit-buffer-file-name buffer-file-name))))
- (when (and file (or (not tracked)
- (magit-file-tracked-p (file-relative-name file))))
- (--when-let (magit-toplevel
- (magit--safe-default-directory
- (directory-file-name (file-name-directory file))))
- (file-relative-name file it))))
-
-(defun magit-file-tracked-p (file)
- (magit-git-success "ls-files" "--error-unmatch" file))
-
-(defun magit-list-files (&rest args)
- (apply #'magit-git-items "ls-files" "-z" "--full-name" args))
-
-(defun magit-tracked-files ()
- (magit-list-files "--cached"))
-
-(defun magit-untracked-files (&optional all files)
- (magit-list-files "--other" (unless all "--exclude-standard") "--" files))
-
-(defun magit-modified-files (&optional nomodules)
- (magit-git-items "diff-files" "-z" "--name-only"
- (and nomodules "--ignore-submodules")))
-
-(defun magit-staged-files (&optional nomodules files)
- (magit-git-items "diff-index" "-z" "--name-only" "--cached"
- (and nomodules "--ignore-submodules")
- (magit-headish) "--" files))
-
-(defun magit-unstaged-files (&optional nomodules files)
- (magit-git-items "diff-index" "-z" "--name-only"
- (and nomodules "--ignore-submodules")
- (magit-headish) "--" files))
-
-(defun magit-staged-binary-files ()
- (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it)
- (list (match-string 1 it)))
- (magit-git-items "diff" "-z" "--cached"
- "--numstat" "--ignore-submodules")))
-
-(defun magit-unmerged-files ()
- (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U"))
-
-(defun magit-revision-files (rev)
- (magit-with-toplevel
- (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev)))
-
-(defun magit-changed-files (rev-or-range &optional other-rev)
- "Return list of files the have changed between two revisions.
-If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a
-range. Otherwise, it can be any revision or range accepted by
-\"git diff\" (i.e., <rev>, <revA>..<revB>, or <revA>...<revB>)."
- (magit-with-toplevel
- (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev)))
-
-(defun magit-renamed-files (revA revB)
- (--map (cons (nth 1 it) (nth 2 it))
- (-partition 3 (magit-git-items
- "diff-tree" "-r" "--diff-filter=R" "-z" "-M"
- revA revB))))
-
-(defun magit-file-status (&rest args)
- (with-temp-buffer
- (save-excursion (magit-git-insert "status" "-z" args))
- (let ((pos (point)) status)
- (while (> (skip-chars-forward "[:print:]") 0)
- (let ((x (char-after pos))
- (y (char-after (1+ pos)))
- (file (buffer-substring (+ pos 3) (point))))
- (forward-char)
- (if (memq x '(?R ?C))
- (progn
- (setq pos (point))
- (skip-chars-forward "[:print:]")
- (push (list file (buffer-substring pos (point)) x y) status)
- (forward-char))
- (push (list file nil x y) status)))
- (setq pos (point)))
- status)))
-
-(defcustom magit-cygwin-mount-points
- (when (eq system-type 'windows-nt)
- (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it)
- (cons (file-name-as-directory (match-string 2 it))
- (file-name-as-directory (match-string 1 it)))
- (lwarn '(magit) :error
- "Failed to parse Cygwin mount: %S" it))
- ;; If --exec-path is not a native Windows path,
- ;; then we probably have a cygwin git.
- (and (not (string-match-p
- "\\`[a-zA-Z]:"
- (car (process-lines "git" "--exec-path"))))
- (ignore-errors (process-lines "mount"))))
- #'> :key (-lambda ((cyg . _win)) (length cyg))))
- "Alist of (CYGWIN . WIN32) directory names.
-Sorted from longest to shortest CYGWIN name."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(alist :key-type string :value-type directory))
-
-(defun magit-expand-git-file-name (filename)
- (unless (file-name-absolute-p filename)
- (setq filename (expand-file-name filename)))
- (-if-let ((cyg . win)
- (cl-assoc filename magit-cygwin-mount-points
- :test (lambda (f cyg) (string-prefix-p cyg f))))
- (concat win (substring filename (length cyg)))
- filename))
-
-(defun magit-convert-git-filename (filename)
- (-if-let ((cyg . win)
- (cl-rassoc filename magit-cygwin-mount-points
- :test (lambda (f win) (string-prefix-p win f))))
- (concat cyg (substring filename (length win)))
- filename))
-
-(defun magit-decode-git-path (path)
- (if (eq (aref path 0) ?\")
- (string-as-multibyte (read path))
- path))
-
-(defun magit-file-at-point ()
- (magit-section-case
- (file (magit-section-value it))
- (hunk (magit-section-parent-value it))))
-
-(defun magit-current-file ()
- (or (magit-file-relative-name)
- (magit-file-at-point)
- (and (derived-mode-p 'magit-log-mode)
- (nth 3 magit-refresh-args))))
-
-;;; Predicates
-
-(defun magit-no-commit-p ()
- "Return t if there is no commit in the current Git repository."
- (not (magit-rev-verify "HEAD")))
-
-(defun magit-anything-staged-p (&optional ignore-submodules &rest files)
- "Return t if there are any staged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (magit-git-failure "diff" "--quiet" "--cached"
- (and ignore-submodules "--ignore-submodules")
- "--" files))
-
-(defun magit-anything-unstaged-p (&optional ignore-submodules &rest files)
- "Return t if there are any unstaged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (magit-git-failure "diff" "--quiet"
- (and ignore-submodules "--ignore-submodules")
- "--" files))
-
-(defun magit-anything-modified-p (&optional ignore-submodules &rest files)
- "Return t if there are any staged or unstaged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (or (apply 'magit-anything-staged-p ignore-submodules files)
- (apply 'magit-anything-unstaged-p ignore-submodules files)))
-
-(defun magit-anything-unmerged-p (&rest files)
- "Return t if there are any merge conflicts.
-If optional FILES is non-nil, then only conflicts in those files
-are considered."
- (and (magit-git-string "ls-files" "--unmerged" files) t))
-
-;;; Revisions and References
-
-(defun magit-rev-parse (&rest args)
- "Execute `git rev-parse ARGS', returning first line of output.
-If there is no output return nil."
- (apply #'magit-git-string "rev-parse" args))
-
-(defun magit-rev-parse-safe (&rest args)
- "Execute `git rev-parse ARGS', returning first line of output.
-If there is no output return nil. Like `magit-rev-parse' but
-ignore `magit-git-debug'."
- (apply #'magit-git-str "rev-parse" args))
-
-(defun magit-rev-parse-p (&rest args)
- "Execute `git rev-parse ARGS', returning t if it prints \"true\".
-Return t if the first (and usually only) output line is the
-string \"true\", otherwise return nil."
- (magit-git-true "rev-parse" args))
-
-(defun magit-rev-verify (rev)
- (magit-rev-parse-safe "--verify" rev))
-
-(defun magit-rev-verify-commit (rev)
- "Return full hash for REV if it names an existing commit."
- (magit-rev-verify (concat rev "^{commit}")))
-
-(defun magit-rev-equal (a b)
- (magit-git-success "diff" "--quiet" a b))
-
-(defun magit-rev-eq (a b)
- (equal (magit-rev-verify a)
- (magit-rev-verify b)))
-
-(defun magit-rev-ancestor-p (a b)
- "Return non-nil if commit A is an ancestor of commit B."
- (magit-git-success "merge-base" "--is-ancestor" a b))
-
-(defun magit-rev-head-p (rev)
- (or (equal rev "HEAD")
- (and rev
- (not (string-match-p "\\.\\." rev))
- (equal (magit-rev-parse rev)
- (magit-rev-parse "HEAD")))))
-
-(defun magit-rev-name (rev &optional pattern)
- (magit-git-string "name-rev" "--name-only" "--no-undefined"
- (and pattern (concat "--refs=" pattern))
- rev))
-
-(defun magit-rev-branch (rev)
- (--when-let (magit-rev-name rev "refs/heads/*")
- (unless (string-match-p "~" it) it)))
-
-(defun magit-get-shortname (rev)
- (let ((fn (apply-partially 'magit-git-string "name-rev"
- "--name-only" "--no-undefined" rev)))
- (setq rev (or (funcall fn "--refs=refs/tags/*")
- (funcall fn "--refs=refs/heads/*")
- (funcall fn "--refs=refs/remotes/*" "--always")))
- (if (and (string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" rev)
- (magit-ref-fullname (match-string 1 rev)))
- (match-string 1 rev)
- rev)))
-
-(defun magit-name-branch (rev &optional lax)
- (or (magit-name-local-branch rev)
- (magit-name-remote-branch rev)
- (and lax (or (magit-name-local-branch rev t)
- (magit-name-remote-branch rev t)))))
-
-(defun magit-name-local-branch (rev &optional lax)
- (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
- "--refs=refs/heads/*" rev)
- (and (or lax (not (string-match-p "~" it))) it)))
-
-(defun magit-name-remote-branch (rev &optional lax)
- (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
- "--refs=refs/remotes/*" rev)
- (and (or lax (not (string-match-p "~" it)))
- (substring it 8))))
-
-(defun magit-name-tag (rev &optional lax)
- (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
- "--refs=refs/tags/*" rev)
- (and (or lax (not (string-match-p "~" it)))
- (substring it 5))))
-
-(defun magit-ref-fullname (name)
- (magit-rev-parse "--symbolic-full-name" name))
-
-(defun magit-ref-exists-p (ref)
- (magit-git-success "show-ref" "--verify" ref))
-
-(defun magit-headish ()
- "Return \"HEAD\" or if that doesn't exist the hash of the empty tree."
- (if (magit-no-commit-p)
- (magit-git-string "mktree")
- "HEAD"))
-
-(defun magit-branch-at-point ()
- (magit-section-case
- (branch (magit-section-value it))
- (commit (magit-name-branch (magit-section-value it)))))
-
-(defun magit-local-branch-at-point ()
- (magit-section-case
- (branch (let ((branch (magit-section-value it)))
- (when (member branch (magit-list-local-branch-names))
- branch)))
- (commit (magit-name-local-branch (magit-section-value it)))))
-
-(defun magit-remote-branch-at-point ()
- (magit-section-case
- (branch (let ((branch (magit-section-value it)))
- (when (member branch (magit-list-remote-branch-names))
- branch)))
- (commit (magit-name-remote-branch (magit-section-value it)))))
-
-(defun magit-commit-at-point ()
- (or (magit-section-when commit)
- (and (derived-mode-p 'magit-revision-mode)
- (car magit-refresh-args))))
-
-(defun magit-branch-or-commit-at-point ()
- (or (magit-section-case
- (branch (magit-section-value it))
- (commit (let ((rev (magit-section-value it)))
- (or (magit-get-shortname rev) rev))))
- (and (derived-mode-p 'magit-revision-mode)
- (car magit-refresh-args))))
-
-(defun magit-tag-at-point ()
- (magit-section-case
- (tag (magit-section-value it))
- (commit (magit-name-tag (magit-section-value it)))))
-
-(defun magit-stash-at-point ()
- (magit-section-when stash))
-
-(defun magit-remote-at-point ()
- (magit-section-case
- (remote (magit-section-value it))
- (branch (magit-section-parent-value it))))
-
-(defun magit-get-current-branch ()
- "Return the refname of the currently checked out branch.
-Return nil if no branch is currently checked out."
- (magit-git-string "symbolic-ref" "--short" "HEAD"))
-
-(defun magit-get-previous-branch ()
- "Return the refname of the previously checked out branch.
-Return nil if no branch can be found in the `HEAD' reflog
-which is different from the current branch and still exists."
- (let ((current (magit-get-current-branch))
- (i 1) prev)
- (while (and (setq prev (magit-rev-verify (format "@{-%i}" i)))
- (or (not (setq prev (magit-rev-branch prev)))
- (equal prev current)))
- (cl-incf i))
- prev))
-
-(cl-defun magit-get-upstream-ref
- (&optional (branch (magit-get-current-branch)))
- (when branch
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (when (and remote merge)
- (cond ((string-equal remote ".") merge)
- ((string-prefix-p "refs/heads/" merge)
- (concat "refs/remotes/" remote "/" (substring merge 11))))))))
-
-(cl-defun magit-get-upstream-branch
- (&optional (branch (magit-get-current-branch)))
- (when branch
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (when (and remote merge (string-prefix-p "refs/heads/" merge))
- (setq merge (substring merge 11))
- (if (string-equal remote ".")
- (propertize merge 'face 'magit-branch-local)
- (propertize (concat remote "/" merge) 'face 'magit-branch-remote))))))
-
-(defun magit-get-indirect-upstream-branch (branch &optional force)
- (let ((remote (magit-get "branch" branch "remote")))
- (and remote (not (equal remote "."))
- ;; The user has opted in...
- (or force (member branch magit-branch-prefer-remote-upstream))
- ;; and local BRANCH tracks a remote branch...
- (let ((upstream (magit-get-upstream-branch branch)))
- ;; whose upstream...
- (and upstream
- ;; has the same name as BRANCH and...
- (equal (substring upstream (1+ (length remote))) branch)
- ;; and can be fast-forwarded to BRANCH.
- (magit-rev-ancestor-p upstream branch)
- upstream)))))
-
-(cl-defun magit-get-upstream-remote
- (&optional (branch (magit-get-current-branch)))
- (when branch
- (magit-get "branch" branch "remote")))
-
-(cl-defun magit-get-push-remote
- (&optional (branch (magit-get-current-branch)))
- (or (and branch (magit-get "branch" branch "pushRemote"))
- (magit-get "remote.pushDefault")))
-
-(cl-defun magit-get-push-branch
- (&optional (branch (magit-get-current-branch)))
- (-when-let (remote (and branch (magit-get-push-remote branch)))
- (concat remote "/" branch)))
-
-(defun magit-get-@{push}-branch (&optional branch)
- (let ((ref (magit-rev-parse "--symbolic-full-name"
- (concat branch "@{push}"))))
- (when (and ref (string-prefix-p "refs/remotes/" ref))
- (substring ref 13))))
-
-(defun magit-get-remote (&optional branch)
- (when (or branch (setq branch (magit-get-current-branch)))
- (let ((remote (magit-get "branch" branch "remote")))
- (unless (equal remote ".")
- remote))))
-
-(defun magit-split-branch-name (branch)
- (cond ((member branch (magit-list-local-branch-names))
- (cons "." branch))
- ((string-match "/" branch)
- (let ((remote (substring branch 0 (match-beginning 0))))
- (if (save-match-data (member remote (magit-list-remotes)))
- (cons remote (substring branch (match-end 0)))
- (error "Invalid branch name %s" branch))))))
-
-(defun magit-get-current-tag (&optional rev with-distance)
- "Return the closest tag reachable from REV.
-
-If optional REV is nil then default to \"HEAD\".
-If optional WITH-DISTANCE is non-nil then return (TAG COMMITS),
-if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number
-of commits in \"HEAD\" but not in TAG and DIRTY is t if there are
-uncommitted changes, nil otherwise."
- (--when-let (magit-git-str "describe" "--long" "--tags"
- (and (eq with-distance 'dirty) "--dirty") rev)
- (save-match-data
- (string-match
- "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" it)
- (if with-distance
- `(,(match-string 1 it)
- ,(string-to-number (or (match-string 2 it) "0"))
- ,@(and (match-string 3 it) (list t)))
- (match-string 1 it)))))
-
-(defun magit-get-next-tag (&optional rev with-distance)
- "Return the closest tag from which REV is reachable.
-
-If optional REV is nil then default to \"HEAD\".
-If no such tag can be found or if the distance is 0 (in which
-case it is the current tag, not the next) return nil instead.
-If optional WITH-DISTANCE is non-nil then return (TAG COMMITS)
-where COMMITS is the number of commits in TAG but not in REV."
- (--when-let (magit-git-str "describe" "--contains" (or rev "HEAD"))
- (save-match-data
- (when (string-match "^[^^~]+" it)
- (setq it (match-string 0 it))
- (unless (equal it (magit-get-current-tag rev))
- (if with-distance
- (list it (car (magit-rev-diff-count it rev)))
- it))))))
-
-(defvar magit-list-refs-namespaces
- '("refs/heads" "refs/remotes" "refs/tags" "refs/pull"))
-
-(defun magit-list-refs (&rest args)
- (magit-git-lines "for-each-ref" "--format=%(refname)"
- (or args magit-list-refs-namespaces)))
-
-(defun magit-list-branches ()
- (magit-list-refs "refs/heads" "refs/remotes"))
-
-(defun magit-list-local-branches ()
- (magit-list-refs "refs/heads"))
-
-(defun magit-list-remote-branches (&optional remote)
- (magit-list-refs (concat "refs/remotes/" remote)))
-
-(defun magit-list-containing-branches (&optional commit)
- (--filter (not (string-match-p "\\`(HEAD" it))
- (--map (substring it 2)
- (magit-git-lines "branch" "--contains" commit))))
-
-(defun magit-list-merged-branches (&optional commit)
- (--filter (not (string-match-p "\\`(HEAD" it))
- (--map (substring it 2)
- (magit-git-lines "branch" "--merged" commit))))
-
-(defun magit-list-unmerged-branches (&optional commit)
- (--filter (not (string-match-p "\\`(HEAD" it))
- (--map (substring it 2)
- (magit-git-lines "branch" "--no-merged" commit))))
-
-(defun magit-list-unmerged-to-upstream-branches ()
- (--filter (-when-let (upstream (magit-get-upstream-branch it))
- (member it (magit-list-unmerged-branches upstream)))
- (magit-list-local-branch-names)))
-
-(defun magit-list-refnames (&rest args)
- (magit-git-lines "for-each-ref" "--format=%(refname:short)"
- (or args magit-list-refs-namespaces)))
-
-(defun magit-list-branch-names ()
- (magit-list-refnames "refs/heads" "refs/remotes"))
-
-(defun magit-list-local-branch-names ()
- (magit-list-refnames "refs/heads"))
-
-(defun magit-list-remote-branch-names (&optional remote relative)
- (if (and remote relative)
- (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote)))
- (--mapcat (when (string-match regexp it)
- (list (match-string 1 it)))
- (magit-list-remote-branches remote)))
- (magit-list-refnames (concat "refs/remotes/" remote))))
-
-(defun magit-format-refs (format &rest args)
- (let ((lines (magit-git-lines
- "for-each-ref" (concat "--format=" format)
- (or args (list "refs/heads" "refs/remotes" "refs/tags")))))
- (if (string-match-p "\f" format)
- (--map (split-string it "\f") lines)
- lines)))
-
-(defun magit-list-remotes ()
- (magit-git-lines "remote"))
-
-(defun magit-list-tags ()
- (magit-git-lines "tag"))
-
-(defun magit-list-notes-refnames ()
- (--map (substring it 6) (magit-list-refnames "refs/notes")))
-
-(defun magit-remote-list-tags (remote)
- (--map (substring it 51)
- (--filter (not (string-match-p "\\^{}$" it))
- (magit-git-lines "ls-remote" "--tags" remote))))
-
-(defun magit-remote-list-branches (remote)
- (--map (substring it 52)
- (--filter (not (string-match-p "\\^{}$" it))
- (magit-git-lines "ls-remote" "--heads" remote))))
-
-(defun magit-get-submodules ()
- (--mapcat (and (string-match "^160000 [0-9a-z]\\{40\\} 0\t\\(.+\\)$" it)
- (list (match-string 1 it)))
- (magit-git-items "ls-files" "-z" "--stage")))
-
-(defun magit-ref-p (rev)
- (or (car (member rev (magit-list-refs)))
- (car (member rev (magit-list-refnames)))))
-
-(defun magit-branch-p (rev)
- (or (car (member rev (magit-list-branches)))
- (car (member rev (magit-list-branch-names)))))
-
-(defun magit-local-branch-p (rev)
- (or (car (member rev (magit-list-local-branches)))
- (car (member rev (magit-list-local-branch-names)))))
-
-(defun magit-branch-set-face (branch)
- (propertize branch 'face (if (magit-local-branch-p branch)
- 'magit-branch-local
- 'magit-branch-remote)))
-
-(defun magit-tag-p (rev)
- (car (member rev (magit-list-tags))))
-
-(defun magit-remote-p (string)
- (car (member string (magit-list-remotes))))
-
-(defun magit-rev-diff-count (a b)
- "Return the commits in A but not B and vice versa.
-Return a list of two integers: (A>B B>A)."
- (mapcar 'string-to-number
- (split-string (magit-git-string "rev-list"
- "--count" "--left-right"
- (concat a "..." b))
- "\t")))
-
-(defun magit-abbrev-length ()
- (string-to-number (or (magit-get "core.abbrev") "7")))
-
-(defun magit-abbrev-arg (&optional arg)
- (format "--%s=%d" (or arg "abbrev") (magit-abbrev-length)))
-
-(defun magit-rev-abbrev (rev)
- (magit-rev-parse (magit-abbrev-arg "short") rev))
-
-(defun magit-commit-children (commit &optional args)
- (-map #'car
- (--filter (member commit (cdr it))
- (--map (split-string it " ")
- (magit-git-lines
- "log" "--format=%H %P"
- (or args (list "--branches" "--tags" "--remotes"))
- "--not" commit)))))
-
-(defun magit-commit-parents (commit)
- (--when-let (magit-git-string "rev-list" "-1" "--parents" commit)
- (cdr (split-string it))))
-
-(defun magit-assert-one-parent (commit command)
- (when (> (length (magit-commit-parents commit)) 1)
- (user-error "Cannot %s a merge commit" command)))
-
-(defun magit-patch-id (rev)
- (with-temp-buffer
- (magit-process-file
- shell-file-name nil '(t nil) nil shell-command-switch
- (let ((exec (shell-quote-argument magit-git-executable)))
- (format "%s diff-tree -u %s | %s patch-id" exec rev exec)))
- (car (split-string (buffer-string)))))
-
-(defun magit-rev-format (format &optional rev args)
- (let ((str (magit-git-string "show" "--no-patch"
- (concat "--format=" format) args
- (if rev (concat rev "^{commit}") "HEAD") "--")))
- (unless (string-equal str "")
- str)))
-
-(defun magit-rev-insert-format (format &optional rev args)
- (magit-git-insert "show" "--no-patch"
- (concat "--format=" format) args
- (if rev (concat rev "^{commit}") "HEAD") "--"))
-
-(defun magit-format-rev-summary (rev)
- (--when-let (magit-rev-format "%h %s" rev)
- (string-match " " it)
- (put-text-property 0 (match-beginning 0) 'face 'magit-hash it)
- it))
-
-(defun magit-format-ref-label (ref &optional head)
- (-let [(_re face fn)
- (--first (string-match (car it) ref) magit-ref-namespaces)]
- (if fn
- (funcall fn ref face)
- (propertize (or (match-string 1 ref) ref)
- 'face (if (equal ref head) 'magit-branch-current face)))))
-
-(defun magit-format-ref-labels (string)
- (save-match-data
- (let ((regexp "\\(, \\|tag: \\| -> \\|[()]\\)") head names)
- (if (and (derived-mode-p 'magit-log-mode)
- (member "--simplify-by-decoration" (cadr magit-refresh-args)))
- (let ((branches (magit-list-local-branch-names))
- (re (format "^%s/.+" (regexp-opt (magit-list-remotes)))))
- (setq names
- (--map (cond ((string-equal it "HEAD") it)
- ((string-prefix-p "refs/" it) it)
- ((member it branches) (concat "refs/heads/" it))
- ((string-match re it) (concat "refs/remotes/" it))
- (t (concat "refs/" it)))
- (split-string
- (replace-regexp-in-string "tag: " "refs/tags/" string)
- regexp t))))
- (setq names (split-string string regexp t)))
- (when (member "HEAD" names)
- (setq head (magit-git-string "symbolic-ref" "HEAD")
- names (cons (or head "@") (delete head (delete "HEAD" names)))))
- (mapconcat (lambda (it) (magit-format-ref-label it head)) names " "))))
-
-(defun magit-object-type (object)
- (magit-git-string "cat-file" "-t" object))
-
-(defmacro magit-with-blob (commit file &rest body)
- (declare (indent 2)
- (debug (form form body)))
- `(with-temp-buffer
- (let ((buffer-file-name ,file))
- (save-excursion
- (magit-git-insert "cat-file" "-p"
- (concat ,commit ":" buffer-file-name)))
- (decode-coding-inserted-region
- (point-min) (point-max) buffer-file-name t nil nil t)
- ,@body)))
-
-(defmacro magit-with-temp-index (tree arg &rest body)
- (declare (indent 2) (debug (form form body)))
- (let ((file (cl-gensym "file")))
- `(let ((,file (magit-convert-git-filename
- (magit-git-dir (make-temp-name "index.magit.")))))
- (setq ,file (or (file-remote-p ,file 'localname) ,file))
- (unwind-protect
- (progn (--when-let ,tree
- (or (magit-git-success "read-tree" ,arg it
- (concat "--index-output=" ,file))
- (error "Cannot read tree %s" it)))
- (if (file-remote-p default-directory)
- (let ((magit-tramp-process-environment
- (setenv-internal magit-tramp-process-environment
- "GIT_INDEX_FILE" ,file t)))
- ,@body)
- (let ((process-environment process-environment))
- (setenv "GIT_INDEX_FILE" ,file)
- ,@body)))
- (ignore-errors
- (delete-file (concat (file-remote-p default-directory) ,file)))))))
-
-(defun magit-commit-tree (message &optional tree &rest parents)
- (magit-git-string "commit-tree" "-m" message
- (--mapcat (list "-p" it) (delq nil parents))
- (or tree (magit-git-string "write-tree"))))
-
-(defun magit-commit-worktree (message &optional arg &rest other-parents)
- (magit-with-temp-index "HEAD" arg
- (and (magit-update-files (magit-modified-files))
- (apply #'magit-commit-tree message nil "HEAD" other-parents))))
-
-(defun magit-update-files (files)
- (magit-git-success "update-index" "--add" "--remove" "--" files))
-
-(defun magit-update-ref (ref message rev &optional stashish)
- (or (if (not (version< (magit-git-version) "2.6.0"))
- (magit-git-success "update-ref" "--create-reflog"
- "-m" message ref rev
- (or (magit-rev-verify ref) ""))
- ;; `--create-reflog' didn't exist before v2.6.0
- (let ((oldrev (magit-rev-verify ref))
- (logfile (magit-git-dir (concat "logs/" ref))))
- (unless (file-exists-p logfile)
- (when oldrev
- (magit-git-success "update-ref" "-d" ref oldrev))
- (make-directory (file-name-directory logfile) t)
- (with-temp-file logfile)
- (when (and oldrev (not stashish))
- (magit-git-success "update-ref" "-m" "enable reflog"
- ref oldrev ""))))
- (magit-git-success "update-ref" "-m" message ref rev
- (or (magit-rev-verify ref) "")))
- (error "Cannot update %s with %s" ref rev)))
-
-(defconst magit-range-re
- (concat "\\`\\([^ \t]*[^.]\\)?" ; revA
- "\\(\\.\\.\\.?\\)" ; range marker
- "\\([^.][^ \t]*\\)?\\'")) ; revB
-
-;;; Completion
-
-(defvar magit-revision-history nil)
-
-(defun magit-read-branch (prompt &optional default)
- (magit-completing-read prompt (magit-list-branch-names)
- nil t nil 'magit-revision-history
- (or (magit-branch-at-point)
- default (magit-get-current-branch))))
-
-(defun magit-read-branch-or-commit (prompt &optional secondary-default)
- (or (magit-completing-read prompt (cons "HEAD" (magit-list-refnames))
- nil nil nil 'magit-revision-history
- (or (magit-branch-or-commit-at-point)
- secondary-default
- (magit-get-current-branch)))
- (user-error "Nothing selected")))
-
-(defun magit-read-range-or-commit (prompt &optional secondary-default)
- (magit-read-range
- prompt
- (or (--when-let (magit-region-values 'commit 'branch)
- (deactivate-mark)
- (concat (car (last it)) ".." (car it)))
- (magit-branch-or-commit-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-range (prompt &optional default)
- (let* ((choose-completion-string-functions
- '(crm--choose-completion-string))
- (minibuffer-completion-table #'crm--collection-fn)
- (minibuffer-completion-confirm t)
- (crm-completion-table (magit-list-refnames))
- (crm-separator "\\.\\.\\.?")
- (input (read-from-minibuffer
- (concat prompt (and default (format " (%s)" default)) ": ")
- nil crm-local-completion-map
- nil 'magit-revision-history
- default)))
- (when (string-equal input "")
- (or (setq input default)
- (user-error "Nothing selected")))
- input))
-
-(defun magit-read-remote-branch
- (prompt &optional remote default local-branch require-match)
- (let ((choice (magit-completing-read
- prompt
- (nconc (and local-branch
- (if remote
- (concat remote "/" local-branch)
- (--map (concat it "/" local-branch)
- (magit-list-remotes))))
- (magit-list-remote-branch-names remote t))
- nil require-match nil 'magit-revision-history default)))
- (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice))
- choice
- (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice))))
-
-(defun magit-read-local-branch (prompt &optional secondary-default)
- (magit-completing-read prompt (magit-list-local-branch-names)
- nil t nil 'magit-revision-history
- (or (magit-local-branch-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-local-branch-or-commit (prompt)
- (let ((branches (magit-list-local-branch-names))
- (commit (magit-commit-at-point)))
- (or (magit-completing-read prompt
- (if commit (cons commit branches) branches)
- nil nil nil 'magit-revision-history
- (or (magit-local-branch-at-point) commit))
- (user-error "Nothing selected"))))
-
-(defun magit-read-local-branch-or-ref (prompt &optional secondary-default)
- (magit-completing-read prompt (nconc (magit-list-local-branch-names)
- (magit-list-refs "refs/"))
- nil t nil 'magit-revision-history
- (or (magit-local-branch-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-other-branch
- (prompt &optional exclude secondary-default no-require-match)
- (let* ((current (magit-get-current-branch))
- (atpoint (magit-branch-at-point))
- (exclude (or exclude current))
- (default (or (and (not (equal atpoint exclude)) atpoint)
- (and (not (equal current exclude)) current)
- secondary-default
- (magit-get-previous-branch))))
- (magit-completing-read prompt (delete exclude (magit-list-branch-names))
- nil (not no-require-match)
- nil 'magit-revision-history default)))
-
-(defun magit-read-other-branch-or-commit
- (prompt &optional exclude secondary-default)
- (let* ((current (magit-get-current-branch))
- (atpoint (magit-branch-or-commit-at-point))
- (exclude (or exclude current))
- (default (or (and (not (equal atpoint exclude)) atpoint)
- (and (not (equal current exclude)) current)
- secondary-default
- (magit-get-previous-branch))))
- (or (magit-completing-read prompt (delete exclude (magit-list-refnames))
- nil nil nil 'magit-revision-history default)
- (user-error "Nothing selected"))))
-
-(cl-defun magit-read-upstream-branch
- (&optional (branch (magit-get-current-branch)) prompt)
- (magit-completing-read
- (or prompt (format "Change upstream of %s to" branch))
- (nconc (--map (concat it "/" branch)
- (magit-list-remotes))
- (delete branch (magit-list-branch-names)))
- nil nil nil 'magit-revision-history
- (or (let ((r (magit-remote-branch-at-point))
- (l (magit-branch-at-point)))
- (when (and l (equal l branch))
- (setq l nil))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (let ((r (magit-branch-p "origin/master"))
- (l (and (not (equal branch "master"))
- (magit-branch-p "master"))))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (let ((previous (magit-get-previous-branch)))
- (and (not (equal previous branch)) previous)))))
-
-(defun magit-read-starting-point (prompt)
- (or (magit-completing-read
- (concat prompt " starting at")
- (cons "HEAD" (magit-list-refnames))
- nil nil nil 'magit-revision-history
- (or (let ((r (magit-remote-branch-at-point))
- (l (magit-local-branch-at-point)))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (magit-commit-at-point)
- (magit-stash-at-point)
- (magit-get-current-branch)))
- (user-error "Nothing selected")))
-
-(defun magit-read-tag (prompt &optional require-match)
- (magit-completing-read prompt (magit-list-tags) nil
- require-match nil 'magit-revision-history
- (magit-tag-at-point)))
-
-(defun magit-read-stash (prompt &optional use-at-point)
- (let ((atpoint (magit-stash-at-point)))
- (or (and use-at-point atpoint)
- (let ((stashes (magit-git-lines "stash" "list" "--format=%gd")))
- (magit-completing-read prompt stashes nil t nil nil
- (or atpoint (car stashes)))))))
-
-(defun magit-read-remote (prompt &optional default use-only)
- (let ((remotes (magit-list-remotes)))
- (if (and use-only (= (length remotes) 1))
- (car remotes)
- (magit-completing-read prompt remotes
- nil t nil nil
- (or default
- (magit-remote-at-point)
- (magit-get-remote))))))
-
-;;; Variables
-
-(defun magit-get (&rest keys)
- "Return the value of Git config entry specified by KEYS."
- (magit-git-str "config" (mapconcat 'identity keys ".")))
-
-(defun magit-get-all (&rest keys)
- "Return all values of the Git config entry specified by KEYS."
- (let ((magit-git-debug nil))
- (magit-git-lines "config" "--get-all" (mapconcat 'identity keys "."))))
-
-(defun magit-get-boolean (&rest keys)
- "Return the boolean value of Git config entry specified by KEYS."
- (magit-git-true "config" "--bool" (mapconcat 'identity keys ".")))
-
-(defun magit-set (val &rest keys)
- "Set Git config settings specified by KEYS to VAL."
- (if val
- (magit-git-string "config" (mapconcat 'identity keys ".") val)
- (magit-git-string "config" "--unset" (mapconcat 'identity keys "."))))
-
-;;; magit-git.el ends soon
-
-(define-obsolete-function-alias 'magit-get-tracked-ref
- 'magit-get-upstream-ref "Magit 2.4.0")
-(define-obsolete-function-alias 'magit-get-tracked-branch
- 'magit-get-upstream-branch "Magit 2.4.0")
-(define-obsolete-function-alias 'magit-get-tracked-remote
- 'magit-get-upstream-remote "Magit 2.4.0")
-
-(provide 'magit-git)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-git.el ends here
+++ /dev/null
-;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for looking at Git logs, including
-;; special logs like reflogs and cherry-logs, as well as for selecting
-;; a commit from a log.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-diff)
-
-(declare-function magit-blame-chunk-get 'magit-blame)
-(declare-function magit-blob-visit 'magit)
-(declare-function magit-find-file-noselect 'magit)
-(declare-function magit-insert-head-branch-header 'magit)
-(declare-function magit-insert-upstream-branch-header 'magit)
-(declare-function magit-read-file-from-rev 'magit)
-(declare-function magit-show-commit 'magit)
-(defvar magit-refs-indent-cherry-lines)
-(defvar magit-refs-show-commit-count)
-(defvar magit-status-sections-hook)
-
-(require 'ansi-color)
-(require 'crm)
-
-;;; Options
-;;;; Log Mode
-
-(defgroup magit-log nil
- "Inspect and manipulate Git history."
- :group 'magit-modes)
-
-(defcustom magit-log-mode-hook nil
- "Hook run after entering Magit-Log mode."
- :group 'magit-log
- :type 'hook)
-
-(defcustom magit-log-arguments '("-n256" "--graph" "--decorate")
- "The log arguments used in `magit-log-mode' buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L")
- "The log arguments that cause the `--graph' argument to be dropped."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type '(repeat (string :tag "Argument"))
- :options '("--follow" "--grep" "-G" "-S" "-L"))
-
-(defcustom magit-log-revision-headers-format "\
-%+b
-Author: %aN <%aE>
-Committer: %cN <%cE>"
- "Additional format string used with the `++header' argument."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type 'string)
-
-(defcustom magit-log-auto-more nil
- "Insert more log entries automatically when moving past the last entry.
-Only considered when moving past the last entry with
-`magit-goto-*-section' commands."
- :group 'magit-log
- :type 'boolean)
-
-(defcustom magit-log-show-margin t
- "Whether to initially show the margin in log buffers.
-
-When non-nil the author name and date are initially displayed in
-the margin of log buffers. The margin can be shown or hidden in
-the current buffer using the command `magit-toggle-margin'. In
-status buffers this option is ignored but it is possible to show
-the margin using the mentioned command."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type 'boolean)
-
-(defcustom magit-duration-spec
- `((?Y "year" "years" ,(round (* 60 60 24 365.2425)))
- (?M "month" "months" ,(round (* 60 60 24 30.436875)))
- (?w "week" "weeks" ,(* 60 60 24 7))
- (?d "day" "days" ,(* 60 60 24))
- (?h "hour" "hours" ,(* 60 60))
- (?m "minute" "minutes" 60)
- (?s "second" "seconds" 1))
- "Units used to display durations in a human format.
-The value is a list of time units, beginning with the longest.
-Each element has the form (CHAR UNIT UNITS SECONDS). UNIT is the
-time unit, UNITS is the plural of that unit. CHAR is a character
-abbreviation. And SECONDS is the number of seconds in one UNIT.
-Also see option `magit-log-margin-spec'."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type '(repeat (list (character :tag "Unit character")
- (string :tag "Unit singular string")
- (string :tag "Unit plural string")
- (integer :tag "Seconds in unit"))))
-
-(defcustom magit-log-margin-spec '(28 7 magit-duration-spec)
- "How to format the log margin.
-
-The log margin is used to display each commit's author followed
-by the commit's age. This option controls the total width of the
-margin and how time units are formatted, the value has the form:
-
- (WIDTH UNIT-WIDTH DURATION-SPEC)
-
-WIDTH specifies the total width of the log margin. UNIT-WIDTH is
-either the integer 1, in which case time units are displayed as a
-single characters, leaving more room for author names; or it has
-to be the width of the longest time unit string in DURATION-SPEC.
-DURATION-SPEC has to be a variable, its value controls which time
-units, in what language, are being used."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :set-after '(magit-duration-spec)
- :type '(list (integer :tag "Margin width")
- (choice :tag "Time unit style"
- (const :format "%t\n"
- :tag "abbreviate to single character" 1)
- (integer :format "%t\n"
- :tag "show full name" 7))
- (variable :tag "Duration spec variable")))
-
-(defcustom magit-log-show-refname-after-summary nil
- "Whether to show refnames after commit summaries.
-This is useful if you use really long branch names."
- :package-version '(magit . "2.2.0")
- :group 'magit-log
- :type 'boolean)
-
-(defface magit-log-graph
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for the graph part of the log output."
- :group 'magit-faces)
-
-(defface magit-log-author
- '((((class color) (background light)) :foreground "firebrick")
- (((class color) (background dark)) :foreground "tomato"))
- "Face for the author part of the log output."
- :group 'magit-faces)
-
-(defface magit-log-date
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for the date part of the log output."
- :group 'magit-faces)
-
-;;;; Select Mode
-
-(defcustom magit-log-select-arguments '("-n256" "--decorate")
- "The log arguments used in `magit-log-select-mode' buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-log-select-show-usage 'both
- "Whether to show usage information when selecting a commit from a log.
-The message can be shown in the `echo-area' or the `header-line', or in
-`both' places. If the value isn't one of these symbols, then it should
-be nil, in which case no usage information is shown."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type '(choice (const :tag "in echo-area" echo-area)
- (const :tag "in header-line" header-line)
- (const :tag "in both places" both)
- (const :tag "nowhere")))
-
-;;;; Cherry Mode
-
-(defcustom magit-cherry-sections-hook
- '(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
- :type 'hook)
-
-;;;; Reflog Mode
-
-(defcustom magit-reflog-arguments '("-n256")
- "The log arguments used in `magit-reflog-mode' buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-reflog-show-margin t
- "Whether to initially show the margin in reflog buffers.
-
-When non-nil the author name and date are initially displayed in
-the margin of reflog buffers. The margin can be shown or hidden
-in the current buffer using the command `magit-toggle-margin'."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type 'boolean)
-
-(defface magit-reflog-commit '((t :foreground "green"))
- "Face for commit commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-amend '((t :foreground "magenta"))
- "Face for amend commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-merge '((t :foreground "green"))
- "Face for merge, checkout and branch commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-checkout '((t :foreground "blue"))
- "Face for checkout commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-reset '((t :foreground "red"))
- "Face for reset commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-rebase '((t :foreground "magenta"))
- "Face for rebase commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-cherry-pick '((t :foreground "green"))
- "Face for cherry-pick commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-remote '((t :foreground "cyan"))
- "Face for pull and clone commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-other '((t :foreground "cyan"))
- "Face for other commands in reflogs."
- :group 'magit-faces)
-
-;;;; Log Sections
-
-(defcustom magit-log-section-commit-count 10
- "How many recent commits to show in certain log sections.
-How many recent commits `magit-insert-recent-commits' and
-`magit-insert-unpulled-from-upstream-or-recent' (provided
-the upstream isn't ahead of the current branch) show."
- :package-version '(magit . "2.1.0")
- :group 'magit-status
- :type 'number)
-
-(defcustom magit-log-section-arguments '("-n256" "--decorate")
- "The log arguments used in buffers that show other things besides logs."
- :package-version '(magit . "2.4.0")
- :group 'magit-log
- :group 'magit-status
- :type '(repeat (string :tag "Argument")))
-
-(define-obsolete-variable-alias 'magit-log-section-args
- 'magit-log-section-arguments "2.2.0")
-
-;;; Commands
-
-(defvar magit-log-popup
- '(:variable magit-log-arguments
- :man-page "git-log"
- :switches ((?g "Show graph" "--graph")
- (?c "Show graph in color" "--color")
- (?d "Show refnames" "--decorate")
- (?S "Show signatures" "--show-signature")
- (?u "Show diffs" "--patch")
- (?s "Show diffstats" "--stat")
- (?h "Show header" "++header")
- (?D "Simplify by decoration" "--simplify-by-decoration")
- (?f "Follow renames when showing single-file log" "--follow"))
- :options ((?n "Limit number of commits" "-n")
- (?f "Limit to files" "-- " magit-read-files)
- (?a "Limit to author" "--author=")
- (?o "Order commits by" "++order=" magit-log-select-order)
- (?g "Search messages" "--grep=")
- (?G "Search changes" "-G")
- (?S "Search occurences" "-S")
- (?L "Trace line evolution" "-L" magit-read-file-trace))
- :actions ((?l "Log current" magit-log-current)
- (?L "Log local branches" magit-log-branches)
- (?r "Reflog current" magit-reflog-current)
- (?o "Log other" magit-log)
- (?b "Log all branches" magit-log-all-branches)
- (?O "Reflog other" magit-reflog)
- (?h "Log HEAD" magit-log-head)
- (?a "Log all references" magit-log-all)
- (?H "Reflog HEAD" magit-reflog-head))
- :default-action magit-log-current
- :max-action-columns 3))
-
-(defvar magit-log-mode-refresh-popup
- '(:variable magit-log-arguments
- :man-page "git-log"
- :switches ((?g "Show graph" "--graph")
- (?c "Show graph in color" "--color")
- (?d "Show refnames" "--decorate")
- (?S "Show signatures" "--show-signature")
- (?u "Show diffs" "--patch")
- (?s "Show diffstats" "--stat")
- (?D "Simplify by decoration" "--simplify-by-decoration")
- (?f "Follow renames when showing single-file log" "--follow"))
- :options ((?n "Limit number of commits" "-n")
- (?f "Limit to files" "-- " magit-read-files)
- (?a "Limit to author" "--author=")
- (?o "Order commits by" "++order=" magit-log-select-order)
- (?g "Search messages" "--grep=")
- (?G "Search changes" "-G")
- (?S "Search occurences" "-S")
- (?L "Trace line evolution" "-L" magit-read-file-trace))
- :actions ((?g "Refresh" magit-log-refresh)
- (?t "Toggle margin" magit-toggle-margin)
- (?s "Set defaults" magit-log-set-default-arguments) nil
- (?w "Save defaults" magit-log-save-default-arguments))
- :max-action-columns 2))
-
-(defvar magit-reflog-mode-refresh-popup
- '(:variable magit-reflog-arguments
- :man-page "git-reflog"
- :options ((?n "Limit number of commits" "-n"))))
-
-(defvar magit-log-refresh-popup
- '(:variable magit-log-arguments
- :man-page "git-log"
- :switches ((?g "Show graph" "--graph")
- (?c "Show graph in color" "--color")
- (?d "Show refnames" "--decorate"))
- :options ((?n "Limit number of commits" "-n")
- (?o "Order commits by" "++order=" magit-log-select-order))
- :actions ((?g "Refresh" magit-log-refresh)
- (?t "Toggle margin" magit-toggle-margin)
- (?s "Set defaults" magit-log-set-default-arguments) nil
- (?w "Save defaults" magit-log-save-default-arguments))
- :max-action-columns 2))
-
-(magit-define-popup-keys-deferred 'magit-log-popup)
-(magit-define-popup-keys-deferred 'magit-log-mode-refresh-popup)
-(magit-define-popup-keys-deferred 'magit-log-refresh-popup)
-
-(defun magit-read-file-trace (&rest _ignored)
- (let ((file (magit-read-file-from-rev "HEAD" "File"))
- (trace (magit-read-string "Trace")))
- (if (string-match
- "^\\(/.+/\\|:[^:]+\\|[0-9]+,[-+]?[0-9]+\\)\\(:\\)?$" trace)
- (concat trace (or (match-string 2 trace) ":") file)
- (user-error "Trace is invalid, see man git-log"))))
-
-(defun magit-log-select-order (&rest _ignored)
- (magit-read-char-case "Order commits by " t
- (?t "[t]opography" "topo")
- (?a "[a]uthor date" "author-date")
- (?c "[c]ommitter date" "date")))
-
-(defun magit-log-arguments (&optional refresh)
- (cond ((memq magit-current-popup
- '(magit-log-popup magit-log-refresh-popup))
- (magit-popup-export-file-args magit-current-popup-args))
- ((derived-mode-p 'magit-log-mode)
- (list (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (refresh
- (list magit-log-section-arguments nil))
- (t
- (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
- (with-current-buffer buffer
- (list (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (list (default-value 'magit-log-arguments) nil)))))
-
-(defun magit-log-popup (arg)
- "Popup console for log commands."
- (interactive "P")
- (let ((magit-log-refresh-popup
- (pcase major-mode
- (`magit-log-mode magit-log-mode-refresh-popup)
- (_ magit-log-refresh-popup)))
- (magit-log-arguments
- (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
- (with-current-buffer buffer
- (magit-popup-import-file-args (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (default-value 'magit-log-arguments))))
- (magit-invoke-popup 'magit-log-popup nil arg)))
-
-(defun magit-log-refresh-popup (arg)
- "Popup console for changing log arguments in the current buffer."
- (interactive "P")
- (magit-log-refresh-assert)
- (let ((magit-log-refresh-popup
- (cond ((derived-mode-p 'magit-log-select-mode)
- magit-log-refresh-popup)
- ((derived-mode-p 'magit-log-mode)
- (let ((def (copy-sequence magit-log-refresh-popup)))
- (plist-put def :switches (plist-get magit-log-popup :switches))
- (plist-put def :options (plist-get magit-log-popup :options))
- def))
- (t
- magit-log-refresh-popup)))
- (magit-log-arguments
- (cond ((derived-mode-p 'magit-log-select-mode)
- (cadr magit-refresh-args))
- ((derived-mode-p 'magit-log-mode)
- (magit-popup-import-file-args (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (t
- magit-log-section-arguments))))
- (magit-invoke-popup 'magit-log-refresh-popup nil arg)))
-
-(defun magit-log-refresh (args files)
- "Set the local log arguments for the current buffer."
- (interactive (magit-log-arguments t))
- (magit-log-refresh-assert)
- (cond ((derived-mode-p 'magit-log-select-mode)
- (setcar (cdr magit-refresh-args) args))
- ((derived-mode-p 'magit-log-mode)
- (setcdr magit-refresh-args (list args files)))
- (t
- (setq-local magit-log-section-arguments args)))
- (magit-refresh))
-
-(defun magit-log-set-default-arguments (args files)
- "Set the global log arguments for the current buffer."
- (interactive (magit-log-arguments t))
- (magit-log-refresh-assert)
- (cond ((derived-mode-p 'magit-log-select-mode)
- (customize-set-variable 'magit-log-select-arguments args)
- (setcar (cdr magit-refresh-args) args))
- ((derived-mode-p 'magit-log-mode)
- (customize-set-variable 'magit-log-arguments args)
- (setcdr magit-refresh-args (list args files)))
- (t
- (customize-set-variable 'magit-log-section-arguments args)
- (kill-local-variable 'magit-log-section-arguments)))
- (magit-refresh))
-
-(defun magit-log-save-default-arguments (args files)
- "Set and save the global log arguments for the current buffer."
- (interactive (magit-log-arguments t))
- (magit-log-refresh-assert)
- (cond ((derived-mode-p 'magit-log-select-mode)
- (customize-save-variable 'magit-log-select-arguments args)
- (setcar (cdr magit-refresh-args) args))
- ((derived-mode-p 'magit-log-mode)
- (customize-save-variable 'magit-log-arguments args)
- (setcdr magit-refresh-args (list args files)))
- (t
- (customize-save-variable 'magit-log-section-arguments args)
- (kill-local-variable 'magit-log-section-arguments)))
- (magit-refresh))
-
-(defun magit-log-refresh-assert ()
- (cond ((derived-mode-p 'magit-reflog-mode)
- (user-error "Cannot change log arguments in reflog buffers"))
- ((derived-mode-p 'magit-cherry-mode)
- (user-error "Cannot change log arguments in cherry buffers"))))
-
-(defvar magit-log-read-revs-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map crm-local-completion-map)
- (define-key map "\s" 'self-insert-command)
- map))
-
-(defun magit-log-read-revs (&optional use-current)
- (or (and use-current (--when-let (magit-get-current-branch) (list it)))
- (let* ((choose-completion-string-functions
- '(crm--choose-completion-string))
- (minibuffer-completion-table #'crm--collection-fn)
- (minibuffer-completion-confirm t)
- (crm-completion-table
- `(,@(and (file-exists-p (magit-git-dir "FETCH_HEAD"))
- (list "FETCH_HEAD"))
- ,@(magit-list-branch-names)))
- (crm-separator "\\(\\.\\.\\.?\\|[, ]\\)")
- (default (or (magit-branch-or-commit-at-point)
- (unless use-current
- (magit-get-previous-branch))))
- (input (read-from-minibuffer
- (format "Log rev,s%s: "
- (if default (format " (%s)" default) ""))
- nil magit-log-read-revs-map
- nil 'magit-revision-history default)))
- (when (string-equal input "")
- (or (setq input default)
- (user-error "Nothing selected")))
- (split-string input "[, ]" t))))
-
-;;;###autoload
-(defun magit-log-current (revs &optional args files)
- "Show log for the current branch.
-When `HEAD' is detached or with a prefix argument show log for
-one or more revs read from the minibuffer."
- (interactive (cons (magit-log-read-revs t)
- (magit-log-arguments)))
- (magit-log revs args files))
-
-;;;###autoload
-(defun magit-log (revs &optional args files)
- "Show log for one or more revs read from the minibuffer.
-The user can input any revision or revisions separated by a
-space, or even ranges, but only branches and tags, and a
-representation of the commit at point, are available as
-completion candidates."
- (interactive (cons (magit-log-read-revs)
- (magit-log-arguments)))
- (require 'magit)
- (magit-mode-setup #'magit-log-mode revs args files)
- (magit-log-goto-same-commit))
-
-;;;###autoload
-(defun magit-log-head (&optional args files)
- "Show log for `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (list "HEAD") args files))
-
-;;;###autoload
-(defun magit-log-branches (&optional args files)
- "Show log for all local branches and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (if (magit-get-current-branch)
- (list "--branches")
- (list "HEAD" "--branches"))
- args files))
-
-;;;###autoload
-(defun magit-log-all-branches (&optional args files)
- "Show log for all local and remote branches and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (if (magit-get-current-branch)
- (list "--branches" "--remotes")
- (list "HEAD" "--branches" "--remotes"))
- args files))
-
-;;;###autoload
-(defun magit-log-all (&optional args files)
- "Show log for all references and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (if (magit-get-current-branch)
- (list "--all")
- (list "HEAD" "--all"))
- args files))
-
-;;;###autoload
-(defun magit-log-buffer-file (&optional follow beg end)
- "Show log for the blob or file visited in the current buffer.
-With a prefix argument or when `--follow' is part of
-`magit-log-arguments', then follow renames."
- (interactive (if (region-active-p)
- (list current-prefix-arg
- (1- (line-number-at-pos (region-beginning)))
- (1- (line-number-at-pos (region-end))))
- (list current-prefix-arg)))
- (-if-let (file (magit-file-relative-name))
- (magit-mode-setup #'magit-log-mode
- (list (or magit-buffer-refname
- (magit-get-current-branch) "HEAD"))
- (let ((args (car (magit-log-arguments))))
- (when (and follow (not (member "--follow" args)))
- (push "--follow" args))
- (when (and beg end)
- (setq args (cons (format "-L%s,%s:%s" beg end file)
- (cl-delete "-L" args :test
- 'string-prefix-p)))
- (setq file nil))
- args)
- (and file (list file)))
- (user-error "Buffer isn't visiting a file"))
- (magit-log-goto-same-commit))
-
-;;;###autoload
-(defun magit-reflog-current ()
- "Display the reflog of the current branch."
- (interactive)
- (magit-reflog (magit-get-current-branch)))
-
-;;;###autoload
-(defun magit-reflog (ref)
- "Display the reflog of a branch."
- (interactive (list (magit-read-local-branch-or-ref "Show reflog for")))
- (magit-mode-setup #'magit-reflog-mode ref magit-reflog-arguments))
-
-;;;###autoload
-(defun magit-reflog-head ()
- "Display the `HEAD' reflog."
- (interactive)
- (magit-reflog "HEAD"))
-
-(defun magit-log-toggle-commit-limit ()
- "Toggle the number of commits the current log buffer is limited to.
-If the number of commits is currently limited, then remove that
-limit. Otherwise set it to 256."
- (interactive)
- (magit-log-set-commit-limit (lambda (&rest _) nil)))
-
-(defun magit-log-double-commit-limit ()
- "Double the number of commits the current log buffer is limited to."
- (interactive)
- (magit-log-set-commit-limit '*))
-
-(defun magit-log-half-commit-limit ()
- "Half the number of commits the current log buffer is limited to."
- (interactive)
- (magit-log-set-commit-limit '/))
-
-(defun magit-log-set-commit-limit (fn)
- (let* ((val (car (magit-log-arguments t)))
- (arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val))
- (num (and arg (string-to-number (match-string 1 arg))))
- (num (if num (funcall fn num 2) 256)))
- (setq val (delete arg val))
- (setcar (cdr magit-refresh-args)
- (if (and num (> num 0))
- (cons (format "-n%i" num) val)
- val)))
- (magit-refresh))
-
-(defun magit-log-get-commit-limit ()
- (--when-let (--first (string-match "^-n\\([0-9]+\\)?$" it)
- (car (magit-log-arguments t)))
- (string-to-number (match-string 1 it))))
-
-(defun magit-log-bury-buffer (&optional arg)
- "Bury the current buffer or the revision buffer in the same frame.
-Like `magit-mode-bury-buffer' (which see) but with a negative
-prefix argument instead bury the revision buffer, provided it
-is displayed in the current frame."
- (interactive "p")
- (if (< arg 0)
- (let* ((buf (magit-mode-get-buffer 'magit-revision-mode))
- (win (and buf (get-buffer-window buf (selected-frame)))))
- (if win
- (with-selected-window win
- (with-current-buffer buf
- (magit-mode-bury-buffer (> (abs arg) 1))))
- (user-error "No revision buffer in this frame")))
- (magit-mode-bury-buffer (> arg 1))))
-
-;;; Log Mode
-
-(defvar magit-log-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-c\C-b" 'magit-go-backward)
- (define-key map "\C-c\C-f" 'magit-go-forward)
- (define-key map "=" 'magit-log-toggle-commit-limit)
- (define-key map "+" 'magit-log-double-commit-limit)
- (define-key map "-" 'magit-log-half-commit-limit)
- (define-key map "q" 'magit-log-bury-buffer)
- map)
- "Keymap for `magit-log-mode'.")
-
-(define-derived-mode magit-log-mode magit-mode "Magit Log"
- "Mode for looking at Git log.
-
-This mode is documented in info node `(magit)Log Buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-branch-popup] to see available branch commands.
-Type \\[magit-merge-popup] to merge the branch or commit at point.
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-Type \\[magit-reset] to reset HEAD to the commit at point.
-
-\\{magit-log-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(defvar magit-log-disable-graph-hack-args
- '("-G" "--grep" "--author")
- "Arguments which disable the graph speedup hack.")
-
-(defun magit-log-refresh-buffer (revs args files)
- (setq header-line-format
- (propertize
- (concat " Commits in " (mapconcat 'identity revs " ")
- (and files (concat " touching "
- (mapconcat 'identity files " "))))
- 'face 'magit-header-line))
- (unless (= (length files) 1)
- (setq args (remove "--follow" args)))
- (when (--any-p (string-match-p
- (concat "^" (regexp-opt magit-log-remove-graph-args)) it)
- args)
- (setq args (remove "--graph" args)))
- (unless (member "--graph" args)
- (setq args (remove "--color" args)))
- (-when-let* ((limit (magit-log-get-commit-limit))
- (limit (* 2 limit)) ; increase odds for complete graph
- (count (and (= (length revs) 1)
- (> limit 1024) ; otherwise it's fast enough
- (setq revs (car revs))
- (not (string-match-p "\\.\\." revs))
- (not (member revs '("--all" "--branches")))
- (-none-p (lambda (arg)
- (--any-p (string-prefix-p it arg)
- magit-log-disable-graph-hack-args))
- args)
- (magit-git-string "rev-list" "--count"
- "--first-parent" args revs))))
- (setq revs (if (< (string-to-number count) limit)
- revs
- (format "%s~%s..%s" revs limit revs))))
- (magit-insert-section (logbuf)
- (magit-insert-log revs args files)))
-
-(defun magit-insert-log (revs &optional args files)
- "Insert a log section.
-Do not add this to a hook variable."
- (magit-git-wash (apply-partially #'magit-log-wash-log 'log)
- "log"
- (format "--format=%%h%s %s[%%aN][%%at]%%s%s"
- (if (member "--decorate" args) "%d" "")
- (if (member "--show-signature" args)
- (progn (setq args (remove "--show-signature" args)) "%G?")
- "")
- (if (member "++header" args)
- (if (member "--graph" (setq args (remove "++header" args)))
- (concat "\n" magit-log-revision-headers-format "\n")
- (concat "\n\1e" magit-log-revision-headers-format "\1e\n"))
- ""))
- (progn
- (--when-let (--first (string-match "^\\+\\+order=\\(.+\\)$" it) args)
- (setq args (cons (format "--%s-order" (match-string 1 it))
- (remove it args))))
- (if (member "--decorate" args)
- (cons "--decorate=full" (remove "--decorate" args))
- args))
- "--use-mailmap" "--no-prefix" revs "--" files))
-
-(defvar magit-commit-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-show-commit)
- (define-key map "a" 'magit-cherry-apply)
- map)
- "Keymap for `commit' sections.")
-
-(defvar magit-module-commit-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-show-commit)
- map)
- "Keymap for `module-commit' sections.")
-
-(defconst magit-log-heading-re
- (concat "^"
- "\\(?4:[-_/|\\*o. ]*\\)" ; graph
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs
- "\\(?7:[BGUN]\\)?" ; gpg
- "\\[\\(?5:[^]]*\\)\\]" ; author
- "\\[\\(?6:[^]]*\\)\\]" ; date
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-cherry-re
- (concat "^"
- "\\(?8:[-+]\\) " ; cherry
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-module-re
- (concat "^"
- "\\(?:\\(?11:[<>]\\) \\)?" ; side
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-bisect-vis-re
- (concat "^"
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-bisect-log-re
- (concat "^# "
- "\\(?3:bad:\\|skip:\\|good:\\) " ; "refs"
- "\\[\\(?1:[^]]+\\)\\] " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-reflog-re
- (concat "^"
- "\\(?1:[^ ]+\\) " ; sha1
- "\\(?:\\(?:[^@]+@{\\(?6:[^}]+\\)} " ; date
- "\\(?10:merge \\|autosave \\|restart \\|[^:]+: \\)?" ; refsub
- "\\(?2:.*\\)?\\)\\| \\)$")) ; msg
-
-(defconst magit-reflog-subject-re
- (concat "\\(?1:[^ ]+\\) ?" ; command
- "\\(?2:\\(?: ?-[^ ]+\\)+\\)?" ; option
- "\\(?: ?(\\(?3:[^)]+\\))\\)?")) ; type
-
-(defconst magit-log-stash-re
- (concat "^"
- "\\(?1:[^ ]+\\)" ; "sha1"
- "\\(?5: \\)" ; "author"
- "\\(?6:[^ ]+\\) " ; date
- "\\(?2:.*\\)$")) ; msg
-
-(defvar magit-log-count nil)
-
-(defun magit-log-wash-log (style args)
- (setq args (-flatten args))
- (when (and (member "--graph" args)
- (member "--color" args))
- (let ((ansi-color-apply-face-function
- (lambda (beg end face)
- (put-text-property beg end 'font-lock-face
- (or face 'magit-log-graph)))))
- (ansi-color-apply-on-region (point-min) (point-max))))
- (when (eq style 'cherry)
- (reverse-region (point-min) (point-max)))
- (let ((magit-log-count 0)
- (abbrev (magit-abbrev-length)))
- (magit-wash-sequence (apply-partially 'magit-log-wash-rev style abbrev))
- (if (derived-mode-p 'magit-log-mode)
- (when (eq magit-log-count (magit-log-get-commit-limit))
- (magit-insert-section (longer)
- (insert-text-button
- (substitute-command-keys
- (format "Type \\<%s>\\[%s] to show more history"
- 'magit-log-mode-map
- 'magit-log-double-commit-limit))
- 'action (lambda (_button)
- (magit-log-double-commit-limit))
- 'follow-link t
- 'mouse-face 'magit-section-highlight)))
- (unless (equal (car args) "cherry")
- (insert ?\n)))))
-
-(defun magit-log-wash-rev (style abbrev)
- (when (derived-mode-p 'magit-log-mode)
- (cl-incf magit-log-count))
- (looking-at (pcase style
- (`log magit-log-heading-re)
- (`cherry magit-log-cherry-re)
- (`module magit-log-module-re)
- (`reflog magit-log-reflog-re)
- (`stash magit-log-stash-re)
- (`bisect-vis magit-log-bisect-vis-re)
- (`bisect-log magit-log-bisect-log-re)))
- (magit-bind-match-strings
- (hash msg refs graph author date gpg cherry _ refsub side) nil
- (let ((align (not (member "--stat" (cadr magit-refresh-args)))))
- (magit-delete-line)
- (magit-insert-section section (commit hash)
- (pcase style
- (`stash (setf (magit-section-type section) 'stash))
- (`module (setf (magit-section-type section) 'module-commit))
- (`bisect-log (setq hash (magit-rev-parse "--short" hash))))
- (when cherry
- (when (and (derived-mode-p 'magit-refs-mode)
- magit-refs-show-commit-count)
- (insert (make-string magit-refs-indent-cherry-lines ?\s)))
- (insert (propertize cherry 'face (if (string= cherry "-")
- 'magit-cherry-equivalent
- 'magit-cherry-unmatched)))
- (insert ?\s))
- (when side
- (insert (propertize side 'face (if (string= side "<")
- 'magit-diff-removed
- 'magit-diff-added)))
- (insert ?\s))
- (when align
- (insert (propertize hash 'face 'magit-hash) ?\s))
- (when graph
- (insert graph))
- (unless align
- (insert (propertize hash 'face 'magit-hash) ?\s))
- (when (and refs (not magit-log-show-refname-after-summary))
- (insert (magit-format-ref-labels refs) ?\s))
- (when refsub
- (insert (format "%-2s " (1- magit-log-count)))
- (insert (magit-reflog-format-subject
- (substring refsub 0 (if (string-match-p ":" refsub) -2 -1)))))
- (when msg
- (insert (propertize msg 'face
- (pcase (and gpg (aref gpg 0))
- (?G 'magit-signature-good)
- (?B 'magit-signature-bad)
- (?U 'magit-signature-untrusted)))))
- (when (and refs magit-log-show-refname-after-summary)
- (insert ?\s)
- (insert (magit-format-ref-labels refs)))
- (insert ?\n)
- (when (memq style '(log reflog stash))
- (goto-char (line-beginning-position))
- (when (and refsub
- (string-match "\\`\\([^ ]\\) \\+\\(..\\)\\(..\\)" date))
- (setq date (+ (string-to-number (match-string 1 date))
- (* (string-to-number (match-string 2 date)) 60 60)
- (* (string-to-number (match-string 3 date)) 60))))
- (save-excursion
- (backward-char)
- (magit-format-log-margin author date)))
- (when (and (eq style 'log)
- (not (or (eobp) (looking-at magit-log-heading-re))))
- (when (looking-at "\1e")
- (magit-insert-heading)
- (delete-char 1)
- (magit-insert-section (commit-header)
- (forward-line)
- (magit-insert-heading)
- (re-search-forward "\1e")
- (backward-delete-char 1)
- (forward-char)
- (insert ?\n))
- (delete-char 1))
- (if (looking-at "^\\(---\\|\n\s\\|\ndiff\\)")
- (let ((limit (save-excursion
- (and (re-search-forward magit-log-heading-re nil t)
- (match-beginning 0)))))
- (unless (magit-section-content magit-insert-section--current)
- (magit-insert-heading))
- (delete-char (if (looking-at "\n") 1 4))
- (magit-diff-wash-diffs (list "--stat") limit))
- (when align
- (setq align (make-string (1+ abbrev) ? )))
- (when (and (not (eobp)) (not (looking-at magit-log-heading-re)))
- (when align
- (setq align (make-string (1+ abbrev) ? )))
- (while (and (not (eobp)) (not (looking-at magit-log-heading-re)))
- (when align
- (save-excursion (insert align)))
- (magit-format-log-margin)
- (forward-line))
- ;; When `--format' is used and its value isn't one of the
- ;; predefined formats, then `git-log' does not insert a
- ;; separator line.
- (save-excursion
- (forward-line -1)
- (looking-at "[-_/|\\*o. ]*"))
- (setq graph (match-string 0))
- (unless (string-match-p "[/\\]" graph)
- (insert graph ?\n))))))))
- t)
-
-(defun magit-format-log-margin (&optional author date)
- (-let [(width unit-width duration-spec) magit-log-margin-spec]
- (when (and date (not author))
- (setq width (+ (if (= unit-width 1) 1 (1+ unit-width))
- (if (derived-mode-p 'magit-log-mode) 1 0))))
- (if date
- (magit-make-margin-overlay
- (and author
- (concat (propertize (truncate-string-to-width
- (or author "")
- (- width 1 3 ; gap, digits
- (if (= unit-width 1) 1 (1+ unit-width))
- (if (derived-mode-p 'magit-log-mode) 1 0))
- nil ?\s (make-string 1 magit-ellipsis))
- 'face 'magit-log-author)
- " "))
- (propertize (magit-format-duration
- (abs (truncate (- (float-time)
- (string-to-number date))))
- (symbol-value duration-spec)
- unit-width)
- 'face 'magit-log-date)
- (and (derived-mode-p 'magit-log-mode)
- (propertize " " 'face 'fringe)))
- (magit-make-margin-overlay
- (propertize (make-string (1- width) ?\s) 'face 'default)
- (propertize " " 'face 'fringe)))))
-
-(defun magit-format-duration (duration spec &optional width)
- (-let [(char unit units weight) (car spec)]
- (let ((cnt (round (/ duration weight 1.0))))
- (if (or (not (cdr spec))
- (>= (/ duration weight) 1))
- (if (eq width 1)
- (format "%3i%c" cnt char)
- (format (if width (format "%%3i %%-%is" width) "%i %s")
- cnt (if (= cnt 1) unit units)))
- (magit-format-duration duration (cdr spec) width)))))
-
-(defun magit-log-maybe-show-more-commits (section)
- "Automatically insert more commit sections in a log.
-Only do so if `point' is on the \"show more\" section,
-and `magit-log-auto-more' is non-nil."
- (when (and (eq (magit-section-type section) 'longer)
- magit-log-auto-more)
- (magit-log-double-commit-limit)
- (forward-line -1)
- (magit-section-forward)))
-
-(defvar magit--update-revision-buffer nil)
-
-(defun magit-log-maybe-update-revision-buffer (&optional _)
- "When moving in the log buffer, update the revision buffer.
-If there is no revision buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-log-mode)
- (magit-log-maybe-update-revision-buffer-1)))
-
-(defun magit-log-maybe-update-revision-buffer-1 ()
- (unless magit--update-revision-buffer
- (-when-let* ((commit (magit-section-when 'commit))
- (buffer (magit-mode-get-buffer 'magit-revision-mode nil t)))
- (setq magit--update-revision-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (-let [(rev buf) magit--update-revision-buffer]
- (setq magit--update-revision-buffer nil)
- (when (buffer-live-p buf)
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-show-commit rev (magit-diff-arguments)))))
- (setq magit--update-revision-buffer nil))))))
-
-(defvar magit--update-blob-buffer nil)
-
-(defun magit-log-maybe-update-blob-buffer (&optional _)
- "When moving in the log buffer, update the blob buffer.
-If there is no blob buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-log-mode)
- (magit-log-maybe-update-blob-buffer-1)))
-
-(defun magit-log-maybe-update-blob-buffer-1 ()
- (unless magit--update-revision-buffer
- (-when-let* ((commit (magit-section-when 'commit))
- (buffer (--first (with-current-buffer it magit-buffer-revision)
- (-map #'window-buffer (window-list)))))
- (setq magit--update-blob-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (-let [(rev buf) magit--update-blob-buffer]
- (setq magit--update-blob-buffer nil)
- (when (buffer-live-p buf)
- (save-excursion
- (with-selected-window (get-buffer-window buf)
- (with-current-buffer buf
- (magit-blob-visit (list (magit-rev-parse rev)
- (magit-file-relative-name
- magit-buffer-file-name))
- (line-number-at-pos))))))))))))
-
-(defun magit-log-goto-same-commit ()
- (-when-let* ((prev magit-previous-section)
- (rev (cond ((magit-section-match 'commit prev)
- (magit-section-value prev))
- ((magit-section-match 'branch prev)
- (magit-rev-format
- "%h" (magit-section-value prev)))))
- (same (--first (equal (magit-section-value it) rev)
- (magit-section-children magit-root-section))))
- (goto-char (magit-section-start same))))
-
-;;; Select Mode
-
-(defvar magit-log-select-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-log-mode-map)
- (define-key map "\C-c\C-b" 'undefined)
- (define-key map "\C-c\C-f" 'undefined)
- (define-key map "." 'magit-log-select-pick)
- (define-key map "e" 'magit-log-select-pick)
- (define-key map "\C-c\C-c" 'magit-log-select-pick)
- (define-key map "q" 'magit-log-select-quit)
- (define-key map "\C-c\C-k" 'magit-log-select-quit)
- map)
- "Keymap for `magit-log-select-mode'.")
-
-(put 'magit-log-select-pick :advertised-binding [?\C-c ?\C-c])
-(put 'magit-log-select-quit :advertised-binding [?\C-c ?\C-k])
-
-(define-derived-mode magit-log-select-mode magit-log-mode "Magit Select"
- "Mode for selecting a commit from history.
-
-This mode is documented in info node `(magit)Select from log'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-\\<magit-log-select-mode-map>\
-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))
-
-(defun magit-log-select-refresh-buffer (rev args)
- (magit-insert-section (logbuf)
- (magit-insert-log rev args)))
-
-(defvar-local magit-log-select-pick-function nil)
-(defvar-local magit-log-select-quit-function nil)
-
-(defun magit-log-select (pick &optional msg quit branch)
- (declare (indent defun))
- (magit-mode-setup #'magit-log-select-mode
- (or branch (magit-get-current-branch) "HEAD")
- magit-log-select-arguments)
- (magit-log-goto-same-commit)
- (setq magit-log-select-pick-function pick)
- (setq magit-log-select-quit-function quit)
- (when magit-log-select-show-usage
- (setq msg (substitute-command-keys
- (format-spec
- (if msg
- (if (string-suffix-p "," msg)
- (concat msg " or %q to abort")
- msg)
- "Type %p to select commit at point, or %q to abort")
- '((?p . "\\[magit-log-select-pick]")
- (?q . "\\[magit-log-select-quit]")))))
- (when (memq magit-log-select-show-usage '(both header-line))
- (setq header-line-format (propertize (concat " " msg) 'face 'bold)))
- (when (memq magit-log-select-show-usage '(both echo-area))
- (message "%s" msg))))
-
-(defun magit-log-select-pick ()
- "Select the commit at point and act on it.
-Call `magit-log-select-pick-function' with the selected
-commit as argument."
- (interactive)
- (let ((fun magit-log-select-pick-function)
- (rev (magit-commit-at-point)))
- (kill-buffer (current-buffer))
- (funcall fun rev)))
-
-(defun magit-log-select-quit ()
- "Abort selecting a commit, don't act on any commit."
- (interactive)
- (kill-buffer (current-buffer))
- (when magit-log-select-quit-function
- (funcall magit-log-select-quit-function)))
-
-;;; Cherry Mode
-
-(defvar magit-cherry-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "q" 'magit-log-bury-buffer)
- (define-key map "L" 'magit-toggle-margin)
- map)
- "Keymap for `magit-cherry-mode'.")
-
-(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry"
- "Mode for looking at commits not merged upstream.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-
-\\{magit-cherry-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-;;;###autoload
-(defun magit-cherry (head upstream)
- "Show commits in a branch that are not merged in the upstream branch."
- (interactive
- (let ((head (magit-read-branch "Cherry head")))
- (list head (magit-read-other-branch "Cherry upstream" head
- (magit-get-upstream-branch head)))))
- (magit-mode-setup #'magit-cherry-mode upstream head))
-
-(defun magit-cherry-refresh-buffer (_upstream _head)
- (magit-insert-section (cherry)
- (run-hooks 'magit-cherry-sections-hook)))
-
-(defun magit-insert-cherry-headers ()
- "Insert headers appropriate for `magit-cherry-mode' buffers."
- (magit-insert-head-branch-header (nth 1 magit-refresh-args))
- (magit-insert-upstream-branch-header (nth 1 magit-refresh-args)
- (nth 0 magit-refresh-args)
- "Upstream: ")
- (insert ?\n))
-
-(defun magit-insert-cherry-commits ()
- "Insert commit sections into a `magit-cherry-mode' buffer."
- (magit-insert-section (cherries)
- (magit-insert-heading "Cherry commits:")
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" "--abbrev" magit-refresh-args)))
-
-;;; Reflog Mode
-
-(defvar magit-reflog-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-log-mode-map)
- (define-key map "L" 'magit-toggle-margin)
- map)
- "Keymap for `magit-reflog-mode'.")
-
-(define-derived-mode magit-reflog-mode magit-log-mode "Magit Reflog"
- "Mode for looking at Git reflog.
-
-This mode is documented in info node `(magit)Reflog'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-Type \\[magit-reset] to reset HEAD to the commit at point.
-
-\\{magit-reflog-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-reflog-refresh-buffer (ref args)
- (setq header-line-format
- (propertize (concat " Reflog for " ref) 'face 'magit-header-line))
- (magit-insert-section (reflogbuf)
- (magit-git-wash (apply-partially 'magit-log-wash-log 'reflog)
- "reflog" "show" "--format=%h %gd %gs" "--date=raw" args ref)))
-
-(defvar magit-reflog-labels
- '(("commit" . magit-reflog-commit)
- ("amend" . magit-reflog-amend)
- ("merge" . magit-reflog-merge)
- ("checkout" . magit-reflog-checkout)
- ("branch" . magit-reflog-checkout)
- ("reset" . magit-reflog-reset)
- ("rebase" . magit-reflog-rebase)
- ("cherry-pick" . magit-reflog-cherry-pick)
- ("initial" . magit-reflog-commit)
- ("pull" . magit-reflog-remote)
- ("clone" . magit-reflog-remote)
- ("autosave" . magit-reflog-commit)
- ("restart" . magit-reflog-reset)))
-
-(defun magit-reflog-format-subject (subject)
- (let* ((match (string-match magit-reflog-subject-re subject))
- (command (and match (match-string 1 subject)))
- (option (and match (match-string 2 subject)))
- (type (and match (match-string 3 subject)))
- (label (if (string= command "commit")
- (or type command)
- command))
- (text (if (string= command "commit")
- label
- (mapconcat #'identity
- (delq nil (list command option type))
- " "))))
- (format "%-16s "
- (propertize text 'face
- (or (cdr (assoc label magit-reflog-labels))
- 'magit-reflog-other)))))
-
-;;; Log Sections
-;;;; Standard Log Sections
-
-(defvar magit-unpulled-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
- map)
- "Keymap for `unpulled' sections.")
-
-(magit-define-section-jumper magit-jump-to-unpulled-from-upstream
- "Unpulled from @{upstream}" unpulled "..@{upstream}")
-
-(defun magit-insert-unpulled-from-upstream ()
- "Insert commits that haven't been pulled from the upstream yet."
- (when (magit-git-success "rev-parse" "@{upstream}")
- (magit-insert-section (unpulled "..@{upstream}")
- (magit-insert-heading
- (format (propertize "Unpulled from %s:" 'face 'magit-section-heading)
- (magit-get-upstream-branch)))
- (magit-insert-log "..@{upstream}" magit-log-section-arguments)
- (magit-section-cache-visibility))))
-
-(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote
- "Unpulled from <push-remote>" unpulled
- (concat ".." (magit-get-push-branch)))
-
-(defun magit-insert-unpulled-from-pushremote ()
- "Insert commits that haven't been pulled from the push-remote yet."
- (--when-let (magit-get-push-branch)
- (unless (and (equal (magit-rev-name it)
- (magit-rev-name "@{upstream}"))
- (or (memq 'magit-insert-unpulled-from-upstream
- magit-status-sections-hook)
- (memq 'magit-insert-unpulled-from-upstream-or-recent
- magit-status-sections-hook)))
- (magit-insert-section (unpulled (concat ".." it))
- (magit-insert-heading
- (format (propertize "Unpulled from %s:" 'face 'magit-section-heading)
- (propertize it 'face 'magit-branch-remote)))
- (magit-insert-log (concat ".." it) magit-log-section-arguments)
- (magit-section-cache-visibility)))))
-
-(defvar magit-unpushed-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
- map)
- "Keymap for `unpushed' sections.")
-
-(magit-define-section-jumper magit-jump-to-unpushed-to-upstream
- "Unpushed to @{upstream}" unpushed "@{upstream}..")
-
-(defun magit-insert-unpushed-to-upstream ()
- "Insert commits that haven't been pushed to the upstream yet."
- (when (magit-git-success "rev-parse" "@{upstream}")
- (magit-insert-section (unpushed "@{upstream}..")
- (magit-insert-heading
- (format (propertize "Unmerged into %s:" 'face 'magit-section-heading)
- (magit-get-upstream-branch)))
- (magit-insert-log "@{upstream}.." magit-log-section-arguments)
- (magit-section-cache-visibility))))
-
-(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote
- "Unpushed to <push-remote>" unpushed
- (concat (magit-get-push-branch) ".."))
-
-(defun magit-insert-unpushed-to-pushremote ()
- "Insert commits that haven't been pushed to the push-remote yet."
- (--when-let (magit-get-push-branch)
- (unless (and (equal (magit-rev-name it)
- (magit-rev-name "@{upstream}"))
- (memq 'magit-insert-unpushed-to-upstream
- magit-status-sections-hook))
- (magit-insert-section (unpushed (concat it ".."))
- (magit-insert-heading
- (format (propertize "Unpushed to %s:" 'face 'magit-section-heading)
- (propertize it 'face 'magit-branch-remote)))
- (magit-insert-log (concat it "..") magit-log-section-arguments)
- (magit-section-cache-visibility)))))
-
-(defun magit-insert-recent-commits (&optional collapse)
- "Insert section showing recent commits.
-Show the last `magit-log-section-commit-count' commits."
- (let* ((start (format "HEAD~%s" magit-log-section-commit-count))
- (range (and (magit-rev-verify start)
- (concat start "..HEAD"))))
- (magit-insert-section (recent range collapse)
- (magit-insert-heading "Recent commits:")
- (magit-insert-log range
- (cons (format "-%d" magit-log-section-commit-count)
- magit-log-section-arguments)))))
-
-(defun magit-insert-unpulled-from-upstream-or-recent ()
- "Insert section showing unpulled or recent commits.
-If an upstream is configured for the current branch and it is
-ahead of the current branch, then show the commits that have
-not yet been pulled into the current branch. If no upstream is
-configured or if the upstream is not ahead of the current branch,
-then show the last `magit-log-section-commit-count' commits."
- (if (equal (magit-rev-parse "HEAD")
- (magit-rev-parse "@{upstream}"))
- (magit-insert-recent-commits t)
- (magit-insert-unpulled-from-upstream)))
-
-;;;; Auxiliary Log Sections
-
-(defun magit-insert-unpulled-cherries ()
- "Insert section showing unpulled commits.
-Like `magit-insert-unpulled-to-upstream' but prefix each commit
-which has not been applied yet (i.e. a commit with a patch-id
-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-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" (magit-abbrev-arg)
- (magit-get-current-branch) "@{upstream}"))))
-
-(defun magit-insert-unpushed-cherries ()
- "Insert section showing unpushed commits.
-Like `magit-insert-unpushed-to-upstream' but prefix each commit
-which has not been applied to upstream yet (i.e. a commit with
-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-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" (magit-abbrev-arg) "@{upstream}"))))
-
-;;; Buffer Margins
-
-(defvar-local magit-set-buffer-margin-refresh nil)
-
-(defvar-local magit-show-margin nil)
-(put 'magit-show-margin 'permanent-local t)
-
-(defun magit-toggle-margin ()
- "Show or hide the Magit margin."
- (interactive)
- (unless (derived-mode-p 'magit-log-mode 'magit-status-mode 'magit-refs-mode)
- (user-error "Buffer doesn't contain any logs"))
- (magit-set-buffer-margin (not (cdr (window-margins)))))
-
-(defun magit-maybe-show-margin ()
- "Maybe show the margin, depending on the major-mode and an option.
-Supported modes are `magit-log-mode' and `magit-reflog-mode',
-and the respective options are `magit-log-show-margin' and
-`magit-reflog-show-margin'."
- (if (local-variable-p 'magit-show-margin)
- (magit-set-buffer-margin magit-show-margin)
- (pcase major-mode
- (`magit-log-mode (magit-set-buffer-margin magit-log-show-margin))
- (`magit-reflog-mode (magit-set-buffer-margin magit-reflog-show-margin)))))
-
-(defun magit-set-buffer-margin (enable)
- (let ((width (cond ((not enable) nil)
- ((derived-mode-p 'magit-reflog-mode)
- (+ (cadr magit-log-margin-spec) 5))
- (t (car magit-log-margin-spec)))))
- (setq magit-show-margin width)
- (when (and enable magit-set-buffer-margin-refresh)
- (magit-refresh))
- (-when-let (window (get-buffer-window))
- (with-selected-window window
- (set-window-margins nil (car (window-margins)) width)
- (if enable
- (add-hook 'window-configuration-change-hook
- 'magit-set-buffer-margin-1 nil t)
- (remove-hook 'window-configuration-change-hook
- 'magit-set-buffer-margin-1 t))))))
-
-(defun magit-set-buffer-margin-1 ()
- (-when-let (window (get-buffer-window))
- (with-selected-window window
- (set-window-margins nil (car (window-margins)) magit-show-margin))))
-
-(defun magit-make-margin-overlay (&rest strings)
- ;; Don't put the overlay on the complete line to work around #1880.
- (let ((o (make-overlay (1+ (line-beginning-position))
- (line-end-position)
- nil t)))
- (overlay-put o 'evaporate t)
- (overlay-put o 'before-string
- (propertize "o" 'display
- (list '(margin right-margin)
- (apply #'concat strings))))))
-
-;;; magit-log.el ends soon
-
-(define-obsolete-function-alias 'magit-insert-unpulled-or-recent-commits
- 'magit-insert-unpulled-from-upstream-or-recent "Magit 2.4.0")
-
-(provide 'magit-log)
-;; Local Variables:
-;; coding: utf-8
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-log.el ends here
+++ /dev/null
-;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements the abstract major-mode `magit-mode' from
-;; which almost all other Magit major-modes derive. The code in here
-;; is mostly concerned with creating and refreshing Magit buffers.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-section)
-(require 'magit-git)
-
-;; For `magit-xref-insert-buttons' from `magit'
-(defvar magit-diff-show-xref-buttons)
-(defvar magit-revision-show-xref-buttons)
-;; For `magit-refresh' and `magit-refresh-all'
-(declare-function magit-auto-revert-buffers 'magit-autorevert)
-
-(require 'format-spec)
-(require 'help-mode)
-
-;;; Options
-
-(defcustom magit-mode-hook
- '(magit-load-config-extensions
- magit-xref-setup)
- "Hook run when entering a mode derived from Magit mode."
- :group 'magit-modes
- :type 'hook
- :options '(magit-load-config-extensions
- magit-xref-setup
- bug-reference-mode))
-
-(defcustom magit-mode-setup-hook
- '(magit-maybe-save-repository-buffers
- magit-maybe-show-margin)
- "Hook run by `magit-mode-setup'."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-maybe-save-repository-buffers
- magit-maybe-show-margin))
-
-(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers)
- "Hook run before refreshing in `magit-refresh'.
-
-This hook, or `magit-post-refresh-hook', should be used
-for functions that are not tied to a particular buffer.
-
-To run a function with a particular buffer current, use
-`magit-refresh-buffer-hook' and use `derived-mode-p'
-inside your function."
- :package-version '(magit . "2.4.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-maybe-save-repository-buffers))
-
-(defcustom magit-post-refresh-hook nil
- "Hook run after refreshing in `magit-refresh'.
-
-This hook, or `magit-pre-refresh-hook', should be used
-for functions that are not tied to a particular buffer.
-
-To run a function with a particular buffer current, use
-`magit-refresh-buffer-hook' and use `derived-mode-p'
-inside your function."
- :package-version '(magit . "2.4.0")
- :group 'magit-modes
- :type 'hook)
-
-(defcustom magit-display-buffer-function 'magit-display-buffer-traditional
- "The function used display a Magit buffer.
-
-All Magit buffers (buffers whose major-modes derive from
-`magit-mode') are displayed using `magit-display-buffer',
-which in turn uses the function specified here."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type '(radio (function-item magit-display-buffer-traditional)
- (function-item display-buffer)
- (function :tag "Function")))
-
-(unless (find-lisp-object-file-name 'magit-pre-display-buffer-hook 'defvar)
- (add-hook 'magit-pre-display-buffer-hook 'magit-save-window-configuration))
-(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration)
- "Hook run by `magit-display-buffer' before displaying the buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-save-window-configuration))
-
-(unless (find-lisp-object-file-name 'magit-post-display-buffer-hook 'defvar)
- (add-hook 'magit-post-display-buffer-hook 'magit-maybe-set-dedicated))
-(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated)
- "Hook run by `magit-display-buffer' after displaying the buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'hook
- :options '(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-modes
- :type '(radio (function-item magit-generate-buffer-name-default-function)
- (function :tag "Function")))
-
-(defcustom magit-buffer-name-format "*%M%v: %t"
- "The format string used to name Magit buffers.
-
-The following %-sequences are supported:
-
-`%m' The name of the major-mode, but with the `-mode' suffix
- removed.
-
-`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'.
-
-`%v' The value the buffer is locked to, in parentheses, or an empty
- string if the buffer is not locked to a value.
-
-`%V' Like \"%v\", but the string is prefixed with a space, unless it
- is an empty string.
-
-`%t' The top-level directory of the working tree of the
- repository, or if `magit-uniquify-buffer-names' is non-nil
- an abbreviation of that.
-
-The value should always contain either \"%m\" or \"%M\" as well as
-\"%t\". If `magit-uniquify-buffer-names' is non-nil, then the
-value must end with \"%t\".
-
-This is used by `magit-generate-buffer-name-default-function'.
-If another `magit-generate-buffer-name-function' is used, then
-it may not respect this option, or on the contrary it may
-support additional %-sequences."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'string)
-
-(defcustom magit-uniquify-buffer-names t
- "Whether to uniquify the names of Magit buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'boolean)
-
-(defcustom magit-bury-buffer-function 'magit-restore-window-configuration
- "The function used to bury or kill the current Magit buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type '(radio (function-item quit-window)
- (function-item magit-mode-quit-window)
- (function-item magit-restore-window-configuration)
- (function :tag "Function")))
-
-(defcustom magit-region-highlight-hook
- '(magit-section-update-region magit-diff-update-hunk-region)
- "Functions used to highlight the region.
-Each function is run with the current section as only argument
-until one of them returns non-nil. When multiple sections are
-selected, then this hook does not run and the region is not
-displayed. Otherwise fall back to regular region highlighting."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-section-update-region magit-diff-update-hunk-region))
-
-(defcustom magit-refresh-verbose nil
- "Whether to revert Magit buffers verbosely."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'boolean)
-
-(defcustom magit-refresh-buffer-hook nil
- "Normal hook for `magit-refresh-buffer' to run after refreshing."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'hook)
-
-(defcustom magit-refresh-status-buffer t
- "Whether the status buffer is refreshed after running git.
-
-When this is non-nil, then the status buffer is automatically
-refreshed after running git for side-effects, in addition to the
-current Magit buffer, which is always refreshed automatically.
-
-Only set this to nil after exhausting all other options to
-improve performance."
- :package-version '(magit . "2.4.0")
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-save-repository-buffers t
- "Whether to save file-visiting buffers when appropriate.
-
-If this is non-nil then all modified file-visiting buffers
-belonging to the current repository may be saved before running
-commands, before creating new Magit buffers, and before
-explicitly refreshing such buffers. If this is `dontask' then
-this is done without user intervention, if it is t then the user
-has to confirm each save. `dontask' is the recommended setting."
- :group 'magit
- :type '(choice (const :tag "Never" nil)
- (const :tag "Ask" t)
- (const :tag "Save without asking" dontask)))
-
-(defcustom magit-keep-region-overlay nil
- "Whether to keep the region overlay when there is a valid selection.
-
-By default Magit removes the regular region overlay if, and only
-if, that region constitutes a valid selection as understood by
-Magit commands. Otherwise it does not remove that overlay, and
-the region looks like it would in other buffers.
-
-There are two types of such valid selections: hunk-internal
-regions and regions that select two or more sibling sections.
-In such cases Magit removes the region overlay and instead
-highlights a slightly larger range. All text (for hunk-internal
-regions) or the headings of all sections (for sibling selections)
-that are inside that range (not just inside the region) are acted
-on by commands such as the staging command. This buffer range
-begins at the beginning of the line on which the region begins
-and ends at the end of the line on which the region ends.
-
-Because Magit acts on this larger range and not the region, it is
-actually quite important to visualize that larger range. If we
-don't do that, then one might think that these commands act on
-the region instead. If you want to *also* visualize the region,
-then set this option to t. But please note that when the region
-does *not* constitute a valid selection, then the region is
-*always* visualized as usual, and that it is usually under such
-circumstances that you want to use a non-magit command to act on
-the region.
-
-Besides keeping the region overlay, setting this option to t also
-causes all face properties, except for `:foreground', to be
-ignored for the faces used to highlight headings of selected
-sections. This avoids the worst conflicts that result from
-displaying the region and the selection overlays at the same
-time. We are not interested in dealing with other conflicts.
-In fact we *already* provide a way to avoid all of these
-conflicts: *not* changing the value of this option.
-
-It should be clear by now that we consider it a mistake to set
-this to display the region when the Magit selection is also
-visualized, but since it has been requested a few times and
-because it doesn't cost much to offer this option we do so.
-However that might change. If the existence of this option
-starts complicating other things, then it will be removed."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'boolean)
-
-;;; Magit Mode
-
-(defvar magit-mode-map
- (let ((map (make-keymap)))
- (suppress-keymap map t)
- (define-key map "\t" 'magit-section-toggle)
- (define-key map [C-tab] 'magit-section-cycle)
- (define-key map [M-tab] 'magit-section-cycle-diffs)
- (define-key map [s-tab] 'magit-section-cycle-global)
- (define-key map [backtab] 'magit-section-cycle-global)
- (define-key map "^" 'magit-section-up)
- (define-key map "n" 'magit-section-forward)
- (define-key map "p" 'magit-section-backward)
- (define-key map "\M-n" 'magit-section-forward-sibling)
- (define-key map "\M-p" 'magit-section-backward-sibling)
- (define-key map "+" 'magit-diff-more-context)
- (define-key map "-" 'magit-diff-less-context)
- (define-key map "0" 'magit-diff-default-context)
- (define-key map "1" 'magit-section-show-level-1)
- (define-key map "2" 'magit-section-show-level-2)
- (define-key map "3" 'magit-section-show-level-3)
- (define-key map "4" 'magit-section-show-level-4)
- (define-key map "\M-1" 'magit-section-show-level-1-all)
- (define-key map "\M-2" 'magit-section-show-level-2-all)
- (define-key map "\M-3" 'magit-section-show-level-3-all)
- (define-key map "\M-4" 'magit-section-show-level-4-all)
- (define-key map "g" 'magit-refresh)
- (define-key map "G" 'magit-refresh-all)
- (define-key map "q" 'magit-mode-bury-buffer)
- (define-key map "$" 'magit-process-buffer)
- (define-key map "a" 'magit-cherry-apply)
- (define-key map "A" 'magit-cherry-pick-popup)
- (define-key map "b" 'magit-branch-popup)
- (define-key map "B" 'magit-bisect-popup)
- (define-key map "c" 'magit-commit-popup)
- (define-key map "d" 'magit-diff-popup)
- (define-key map "D" 'magit-diff-refresh-popup)
- (define-key map "h" 'magit-dispatch-popup)
- (define-key map "?" 'magit-dispatch-popup)
- (define-key map "\C-c\C-c" 'magit-dispatch-popup)
- (define-key map "\C-c\C-e" 'magit-dispatch-popup)
- (define-key map "e" 'magit-ediff-dwim)
- (define-key map "E" 'magit-ediff-popup)
- (define-key map "f" 'magit-fetch-popup)
- (define-key map "F" 'magit-pull-popup)
- (define-key map "i" 'magit-gitignore)
- (define-key map "I" 'magit-gitignore-locally)
- (define-key map "k" 'magit-delete-thing)
- (define-key map "K" 'magit-file-untrack)
- (define-key map "l" 'magit-log-popup)
- (define-key map "L" 'magit-log-refresh-popup)
- (define-key map "m" 'magit-merge-popup)
- (define-key map "M" 'magit-remote-popup)
- (define-key map "o" 'magit-submodule-popup)
- (define-key map "P" 'magit-push-popup)
- (define-key map "r" 'magit-rebase-popup)
- (define-key map "R" 'magit-file-rename)
- (define-key map "t" 'magit-tag-popup)
- (define-key map "T" 'magit-notes-popup)
- (define-key map "\r" 'magit-visit-thing)
- (define-key map [C-return] 'magit-visit-thing)
- (define-key map [M-return] 'magit-dired-jump)
- (define-key map "\s" 'magit-diff-show-or-scroll-up)
- (define-key map "\d" 'magit-diff-show-or-scroll-down)
- (define-key map "s" 'magit-stage-file)
- (define-key map "S" 'magit-stage-modified)
- (define-key map "u" 'magit-unstage-file)
- (define-key map "U" 'magit-unstage-all)
- (define-key map "v" 'magit-revert-no-commit)
- (define-key map "V" 'magit-revert-popup)
- (define-key map "w" 'magit-am-popup)
- (define-key map "W" 'magit-patch-popup)
- (define-key map "x" 'magit-reset)
- (define-key map "y" 'magit-show-refs-popup)
- (define-key map "Y" 'magit-cherry)
- (define-key map "z" 'magit-stash-popup)
- (define-key map "Z" 'magit-stash-popup)
- (define-key map ":" 'magit-git-command)
- (define-key map "!" 'magit-run-popup)
- (define-key map "\C-xa" 'magit-add-change-log-entry)
- (define-key map "\C-x4a" 'magit-add-change-log-entry-other-window)
- (define-key map "\C-w" 'magit-copy-section-value)
- (define-key map "\M-w" 'magit-copy-buffer-revision)
- (define-key map [remap evil-previous-line] 'evil-previous-visual-line)
- (define-key map [remap evil-next-line] 'evil-next-visual-line)
- map)
- "Parent keymap for all keymaps of modes derived from `magit-mode'.")
-
-(defun magit-delete-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which deletes the thing at point."
- (interactive)
- (user-error "There is no thing at point that could be deleted"))
-
-(defun magit-visit-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which visits the thing at point."
- (interactive)
- (user-error "There is no thing at point that could be visited"))
-
-(easy-menu-define magit-mode-menu magit-mode-map
- "Magit menu"
- '("Magit"
- ["Refresh" magit-refresh t]
- ["Refresh all" magit-refresh-all t]
- "---"
- ["Stage" magit-stage t]
- ["Stage modified" magit-stage-modified t]
- ["Unstage" magit-unstage t]
- ["Reset index" magit-reset-index t]
- ["Commit" magit-commit-popup t]
- ["Add log entry" magit-commit-add-log t]
- ["Tag" magit-tag t]
- "---"
- ["Diff working tree" magit-diff-working-tree t]
- ["Diff" magit-diff t]
- ("Log"
- ["Log" magit-log t]
- ["Reflog" magit-reflog t]
- ["Extended..." magit-log-popup t])
- "---"
- ["Cherry pick" magit-cherry-pick t]
- ["Revert commit" magit-revert-popup t]
- "---"
- ["Ignore" magit-gitignore t]
- ["Ignore locally" magit-gitignore-locally t]
- ["Discard" magit-discard t]
- ["Reset head" magit-reset-head t]
- ["Stash" magit-stash t]
- ["Snapshot" magit-snapshot t]
- "---"
- ["Branch..." magit-checkout t]
- ["Merge" magit-merge t]
- ["Ediff resolve" magit-ediff-resolve t]
- ["Rebase..." magit-rebase-popup t]
- "---"
- ["Push" magit-push t]
- ["Pull" magit-pull t]
- ["Remote update" magit-fetch-all t]
- ("Submodule"
- ["Submodule update" magit-submodule-update t]
- ["Submodule update and init" magit-submodule-setup t]
- ["Submodule init" magit-submodule-init t]
- ["Submodule sync" magit-submodule-sync t])
- "---"
- ("Extensions")
- "---"
- ["Display Git output" magit-process-buffer t]
- ["Quit Magit" magit-mode-bury-buffer t]))
-
-(defun magit-load-config-extensions ()
- "Load Magit extensions that are defined at the Git config layer."
- (dolist (ext (magit-get-all "magit.extension"))
- (let ((sym (intern (format "magit-%s-mode" ext))))
- (when (fboundp sym)
- (funcall sym 1)))))
-
-(define-derived-mode magit-mode special-mode "Magit"
- "Parent major mode from which Magit major modes inherit.
-
-Magit is documented in info node `(magit)'."
- :group 'magit-modes
- (buffer-disable-undo)
- (setq truncate-lines t)
- (setq buffer-read-only t)
- (setq-local line-move-visual t) ; see #1771
- (setq show-trailing-whitespace nil)
- (setq list-buffers-directory default-directory)
- (hack-dir-local-variables-non-file-buffer)
- (make-local-variable 'text-property-default-nonsticky)
- (push (cons 'keymap t) text-property-default-nonsticky)
- (add-hook 'post-command-hook #'magit-section-update-highlight t t)
- (setq-local redisplay-highlight-region-function 'magit-highlight-region)
- (setq-local redisplay-unhighlight-region-function 'magit-unhighlight-region)
- (when (fboundp 'linum-mode)
- (linum-mode -1)))
-
-(defvar-local magit-region-overlays nil)
-
-(defun magit-highlight-region (start end window rol)
- (mapc #'delete-overlay magit-region-overlays)
- (if (and (run-hook-with-args-until-success 'magit-region-highlight-hook
- (magit-current-section))
- (not magit-keep-region-overlay))
- (funcall (default-value 'redisplay-unhighlight-region-function) rol)
- (funcall (default-value 'redisplay-highlight-region-function)
- start end window rol)))
-
-(defun magit-unhighlight-region (rol)
- (setq magit-section-highlighted-section nil)
- (mapc #'delete-overlay magit-region-overlays)
- (funcall (default-value 'redisplay-unhighlight-region-function) rol))
-
-(defvar-local magit-refresh-args nil
- "The arguments used to refresh the current buffer.")
-(put 'magit-refresh-args 'permanent-local t)
-
-(defvar-local magit-previous-section nil)
-(put 'magit-previous-section 'permanent-local t)
-
-(defun magit-mode-setup (mode &rest args)
- "Setup up a MODE buffer using ARGS to generate its content."
- (let ((buffer (magit-mode-get-buffer mode t))
- (section (magit-current-section)))
- (with-current-buffer buffer
- (setq magit-previous-section section)
- (setq magit-refresh-args args)
- (funcall mode))
- (magit-display-buffer buffer)
- (with-current-buffer buffer
- (run-hooks 'magit-mode-setup-hook)
- (magit-refresh-buffer))))
-
-(defvar magit-display-buffer-noselect nil
- "If non-nil, then `magit-display-buffer' doesn't call `select-window'.")
-
-(defun magit-display-buffer (buffer)
- "Display BUFFER in some window and maybe select it.
-
-Display the buffer using `magit-display-buffer-function' and
-then, unless `magit-display-buffer-noselect' is non-nil, select
-the window which was used to display the buffer.
-
-Also run the hooks `magit-pre-display-buffer-hook'
-and `magit-post-display-buffer-hook'."
- (with-current-buffer buffer
- (run-hooks 'magit-pre-display-buffer-hook))
- (let ((window (funcall magit-display-buffer-function buffer)))
- (unless magit-display-buffer-noselect
- (select-window window)))
- (with-current-buffer buffer
- (run-hooks 'magit-post-display-buffer-hook)))
-
-(defun magit-display-buffer-traditional (buffer)
- "Display BUFFER the way this has traditionally been done."
- (display-buffer
- buffer (if (and (derived-mode-p 'magit-mode)
- (not (memq (with-current-buffer buffer major-mode)
- '(magit-process-mode
- magit-revision-mode
- magit-diff-mode
- magit-stash-mode
- magit-status-mode))))
- '(display-buffer-same-window)
- nil))) ; display in another window
-
-(defun magit-maybe-set-dedicated ()
- "Mark the selected window as dedicated if appropriate.
-
-If a new window was created to display the buffer, then remember
-that fact. That information is used by `magit-mode-quit-window',
-to determine whether the window should be deleted when its last
-Magit buffer is buried."
- (let ((window (get-buffer-window (current-buffer))))
- (when (and (window-live-p window)
- (not (window-prev-buffers window)))
- (set-window-parameter window 'magit-dedicated t))))
-
-(defvar-local magit--default-directory nil
- "Value of `default-directory' when buffer is generated.
-This exists to prevent a let-bound `default-directory' from
-tricking `magit-mode-get-buffer' or `magit-mode-get-buffers' into
-thinking a buffer belongs to a repo that it doesn't.")
-(put 'magit--default-directory 'permanent-local 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))))
-
-(defvar-local magit-buffer-locked-p nil)
-(put 'magit-buffer-locked-p 'permanent-local t)
-
-(defun magit-mode-get-buffer (mode &optional create frame)
- (-if-let (topdir (magit-toplevel))
- (or (--first (with-current-buffer it
- (and (eq major-mode mode)
- (equal magit--default-directory topdir)
- (not magit-buffer-locked-p)))
- (if frame
- (-map #'window-buffer
- (window-list (unless (eq frame t) frame)))
- (buffer-list)))
- (and create
- (let ((default-directory topdir))
- (magit-generate-new-buffer mode))))
- (user-error "Not inside a Git repository")))
-
-(defun magit-generate-new-buffer (mode)
- (let* ((name (funcall magit-generate-buffer-name-function mode))
- (buffer (generate-new-buffer name)))
- (with-current-buffer buffer
- (setq magit--default-directory default-directory))
- (when magit-uniquify-buffer-names
- (add-to-list 'uniquify-list-buffers-directory-modes mode)
- (with-current-buffer buffer
- (setq list-buffers-directory default-directory))
- (let ((uniquify-buffer-name-style
- (if (memq uniquify-buffer-name-style '(nil forward))
- 'post-forward-angle-brackets
- uniquify-buffer-name-style)))
- (uniquify-rationalize-file-buffer-names
- name (file-name-directory (directory-file-name default-directory))
- buffer)))
- buffer))
-
-(defun magit-generate-buffer-name-default-function (mode &optional value)
- (let ((m (substring (symbol-name mode) 0 -5))
- (v (and value (format "%s" (if (listp value) value (list value))))))
- (format-spec
- magit-buffer-name-format
- `((?m . ,m)
- (?M . ,(if (eq mode 'magit-status-mode) "magit" m))
- (?v . ,(or v ""))
- (?V . ,(if v (concat " " v) ""))
- (?t . ,(if magit-uniquify-buffer-names
- (file-name-nondirectory
- (directory-file-name default-directory))
- default-directory))))))
-
-(defun magit-toggle-buffer-lock ()
- "Lock the current buffer to its value or unlock it.
-
-Locking a buffer to its value, prevents it from being reused to
-display another value. The name of a locked buffer contains its
-value, which allows telling it apart from other locked buffers
-and the unlocked buffer.
-
-Not all Magit buffers can be locked to their values, for example
-it wouldn't make sense to lock a status buffer.
-
-There can only be a single unlocked buffer using a certain
-major-mode per repository. So when a buffer is being unlocked
-and another unlocked buffer already exists for that mode and
-repository, then the former buffer is instead deleted and the
-latter is displayed in its place."
- (interactive)
- (if magit-buffer-locked-p
- (-if-let (unlocked (magit-mode-get-buffer major-mode))
- (let ((locked (current-buffer)))
- (set-buffer unlocked)
- (kill-buffer locked))
- (setq magit-buffer-locked-p nil)
- (rename-buffer (funcall magit-generate-buffer-name-function
- major-mode)))
- (setq magit-buffer-locked-p
- (cond ((memq major-mode '(magit-cherry-mode
- magit-log-mode
- magit-reflog-mode
- magit-refs-mode
- magit-revision-mode
- magit-stash-mode
- magit-stashes-mode))
- (car magit-refresh-args))
- ((eq major-mode 'magit-diff-mode)
- (let ((rev (nth 0 magit-refresh-args))
- (args (nth 1 magit-refresh-args)))
- (cond
- ((member "--no-index" args)
- (nth 3 magit-refresh-args))
- (rev (if args (cons rev args) rev))
- (t (if (member "--cached" args) "staged" "unstaged")))))))
- (if magit-buffer-locked-p
- (rename-buffer (funcall magit-generate-buffer-name-function
- major-mode magit-buffer-locked-p))
- (user-error "Buffer has no value it could be locked to"))))
-
-(defun magit-mode-bury-buffer (&optional kill-buffer)
- "Bury the current buffer.
-With a prefix argument, kill the buffer instead.
-This is done using `magit-bury-buffer-function'."
- (interactive "P")
- (funcall magit-bury-buffer-function kill-buffer))
-
-(defun magit-mode-quit-window (kill-buffer)
- "Quit the selected window and bury its buffer.
-
-This behaves similar to `quit-window', but when the window
-was originally created to display a Magit buffer and the
-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)))
- (quit-window kill-buffer)
- (let ((window (selected-window)))
- (quit-window kill-buffer)
- (when (window-live-p window)
- (delete-window window)))))
-
-;;; Refresh Magit Buffers
-
-(defvar inhibit-magit-refresh nil)
-
-(defun magit-refresh ()
- "Refresh some buffers belonging to the current repository.
-
-Refresh the current buffer if its major mode derives from
-`magit-mode', and refresh the corresponding status buffer.
-
-Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
- (interactive)
- (unless inhibit-magit-refresh
- (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
- (when (derived-mode-p 'magit-mode)
- (magit-refresh-buffer))
- (--when-let (and magit-refresh-status-buffer
- (not (derived-mode-p 'magit-status-mode))
- (magit-mode-get-buffer 'magit-status-mode))
- (with-current-buffer it
- (magit-refresh-buffer)))
- (magit-auto-revert-buffers)
- (magit-run-hook-with-benchmark 'magit-post-refresh-hook)))
-
-(defun magit-refresh-all ()
- "Refresh all buffers belonging to the current repository.
-
-Refresh all Magit buffers belonging to the current repository,
-and revert buffers that visit files located inside the current
-repository.
-
-Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
- (interactive)
- (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
- (dolist (buffer (magit-mode-get-buffers))
- (with-current-buffer buffer (magit-refresh-buffer)))
- (magit-auto-revert-buffers)
- (magit-run-hook-with-benchmark 'magit-post-refresh-hook))
-
-(defvar-local magit-refresh-start-time nil)
-
-(defun magit-refresh-buffer ()
- "Refresh the current Magit buffer."
- (setq magit-refresh-start-time (current-time))
- (let ((refresh (intern (format "%s-refresh-buffer"
- (substring (symbol-name major-mode) 0 -5)))))
- (when (functionp refresh)
- (when magit-refresh-verbose
- (message "Refreshing buffer `%s'..." (buffer-name)))
- (let* ((buffer (current-buffer))
- (windows
- (--mapcat (with-selected-window it
- (with-current-buffer buffer
- (-when-let (section (magit-current-section))
- (list
- (nconc (list it section)
- (magit-refresh-get-relative-position))))))
- (or (get-buffer-window-list buffer nil t)
- (list (selected-window))))))
- (deactivate-mark)
- (setq magit-section-highlight-overlays nil
- magit-section-highlighted-section nil
- magit-section-highlighted-sections nil
- magit-section-unhighlight-sections nil)
- (let ((inhibit-read-only t))
- (erase-buffer)
- (save-excursion
- (apply refresh magit-refresh-args)))
- (dolist (window windows)
- (with-selected-window (car window)
- (with-current-buffer buffer
- (apply #'magit-section-goto-successor (cdr window)))))
- (run-hooks 'magit-refresh-buffer-hook)
- (magit-section-update-highlight)
- (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)))))))
-
-(defun magit-refresh-get-relative-position ()
- (-when-let (section (magit-current-section))
- (let ((start (magit-section-start section)))
- (list (count-lines start (point))
- (- (point) (line-beginning-position))
- (and (eq (magit-section-type section) 'hunk)
- (region-active-p)
- (progn (goto-char (line-beginning-position))
- (when (looking-at "^[-+]") (forward-line))
- (while (looking-at "^[ @]") (forward-line))
- (let ((beg (point)))
- (cond ((looking-at "^[-+]")
- (forward-line)
- (while (looking-at "^[-+]") (forward-line))
- (while (looking-at "^ ") (forward-line))
- (forward-line -1)
- (regexp-quote (buffer-substring-no-properties
- beg (line-end-position))))
- (t t)))))))))
-
-;;; Save File-Visiting Buffers
-
-(defvar disable-magit-save-buffers nil)
-
-(defun magit-pre-command-hook ()
- (setq disable-magit-save-buffers nil))
-(add-hook 'pre-command-hook #'magit-pre-command-hook)
-
-(defvar magit-after-save-refresh-buffers nil)
-
-(defun magit-after-save-refresh-buffers ()
- (dolist (buffer magit-after-save-refresh-buffers)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (magit-refresh-buffer))))
- (setq magit-after-save-refresh-buffers nil)
- (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers))
-
-(defun magit-after-save-refresh-status ()
- "Refresh the status buffer of the current repository.
-
-This function is intended to be added to `after-save-hook'.
-
-If the status buffer does not exist or the file being visited in
-the current buffer isn't inside a repository, then do nothing.
-
-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."
- (unless disable-magit-save-buffers
- (--when-let (ignore-errors (magit-mode-get-buffer 'magit-status-mode))
- (add-to-list 'magit-after-save-refresh-buffers it)
- (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.
-Do so if `magit-save-repository-buffers' is non-nil. You should
-not remove this from any hooks, instead set that variable to nil
-if you so desire."
- (when (and magit-save-repository-buffers
- (not disable-magit-save-buffers))
- (setq disable-magit-save-buffers t)
- (let ((msg (current-message)))
- (magit-save-repository-buffers
- (eq magit-save-repository-buffers 'dontask))
- (when (and msg (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)
-
-(defun magit-save-repository-buffers (&optional arg)
- "Save file-visiting buffers belonging to the current repository.
-After any buffer where `buffer-save-without-query' is non-nil
-is saved without asking, the user is asked about each modified
-buffer which visits a file in the current repository. Optional
-argument (the prefix) non-nil means save all with no questions."
- (interactive "P")
- (-when-let (topdir (magit-rev-parse-safe "--show-toplevel"))
- (save-some-buffers
- arg (-partial (lambda (topdir)
- (and buffer-file-name
- ;; Avoid needlessly connecting to unrelated remotes.
- (string-prefix-p topdir buffer-file-name)
- (equal (magit-rev-parse-safe "--show-toplevel")
- topdir)))
- topdir))))
-
-;;; Restore Window Configuration
-
-(defvar magit-inhibit-save-previous-winconf nil)
-
-(defvar-local magit-previous-window-configuration nil)
-(put 'magit-previous-window-configuration 'permanent-local t)
-
-(defun magit-save-window-configuration ()
- "Save the current window configuration.
-
-Later, when the buffer is buried, it may be restored by
-`magit-restore-window-configuration'."
- (if magit-inhibit-save-previous-winconf
- (when (eq magit-inhibit-save-previous-winconf 'unset)
- (setq magit-previous-window-configuration nil))
- (unless (get-buffer-window (current-buffer) (selected-frame))
- (setq magit-previous-window-configuration
- (current-window-configuration)))))
-
-(defun magit-restore-window-configuration (&optional kill-buffer)
- "Bury or kill the current buffer and restore previous window configuration."
- (let ((winconf magit-previous-window-configuration)
- (buffer (current-buffer))
- (frame (selected-frame)))
- (quit-window kill-buffer (selected-window))
- (when (and winconf (equal frame (window-configuration-frame winconf)))
- (set-window-configuration winconf)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (setq magit-previous-window-configuration nil))))))
-
-;;; Buffer History
-
-(defun magit-go-backward ()
- "Move backward in current buffer's history."
- (interactive)
- (if help-xref-stack
- (help-xref-go-back (current-buffer))
- (user-error "No previous entry in buffer's history")))
-
-(defun magit-go-forward ()
- "Move forward in current buffer's history."
- (interactive)
- (if help-xref-forward-stack
- (help-xref-go-forward (current-buffer))
- (user-error "No next entry in buffer's history")))
-
-(defun magit-insert-xref-buttons (&optional _)
- "Insert xref buttons."
- (when (or help-xref-stack help-xref-forward-stack)
- (when help-xref-stack
- (magit-xref-insert-button help-back-label 'magit-xref-backward))
- (when help-xref-forward-stack
- (when help-xref-stack
- (insert " "))
- (magit-xref-insert-button help-forward-label 'magit-xref-forward))))
-
-(defun magit-xref-insert-button (label type)
- (magit-insert-section (button label)
- (insert-text-button label 'type type
- 'help-args (list (current-buffer)))))
-
-(define-button-type 'magit-xref-backward
- :supertype 'help-back
- 'mouse-face 'magit-section-highlight
- 'help-echo (purecopy "mouse-2, RET: go back to previous history entry"))
-
-(define-button-type 'magit-xref-forward
- :supertype 'help-forward
- 'mouse-face 'magit-section-highlight
- 'help-echo (purecopy "mouse-2, RET: go back to next history entry"))
-
-(defun magit-xref-setup ()
- "Insert backward/forward buttons if the major-mode supports it.
-Currently `magit-log-mode', `magit-reflog-mode',
-`magit-diff-mode', and `magit-revision-mode' support it"
- (when (memq major-mode '(magit-log-mode
- magit-reflog-mode
- magit-diff-mode
- magit-revision-mode))
- (when help-xref-stack-item
- (push (cons (point) help-xref-stack-item) help-xref-stack)
- (setq help-xref-forward-stack nil))
- (when (called-interactively-p 'interactive)
- (--when-let (nthcdr 10 help-xref-stack)
- (setcdr it nil)))
- (setq help-xref-stack-item
- `(magit-xref-restore ,default-directory ,@magit-refresh-args))))
-
-(defun magit-xref-restore (&rest args)
- (magit-xref-setup)
- (setq default-directory (car args))
- (setq magit-refresh-args (cdr args))
- (magit-refresh-buffer))
-
-;;; Utilities
-
-(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))))
-
-;;; magit-mode.el ends soon
-(provide 'magit-mode)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-mode.el ends here
+++ /dev/null
-(define-package "magit" "20160219.1502" "A Git porcelain inside Emacs"
- '((emacs "24.4")
- (async "20150909.2257")
- (dash "20151021.113")
- (with-editor "20160128.1201")
- (git-commit "20160119.1409")
- (magit-popup "20160119.1409"))
- :url "https://github.com/magit/magit" :keywords
- '("git" "tools" "vc"))
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; magit-process.el --- process functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements the tools used to run Git for side-effects.
-
-;; Note that the functions used to run Git and then consume its
-;; output, are defined in `magit-git.el'. There's a bit of overlap
-;; though.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'with-editor)
-(require 'magit-utils)
-(require 'magit-section)
-(require 'magit-git)
-(require 'magit-mode)
-
-(eval-when-compile (require 'dired))
-(declare-function dired-uncache 'dired)
-
-;;; Options
-
-(defcustom magit-process-connection-type (not (eq system-type 'cygwin))
- "Connection type used for the Git process.
-
-If nil, use pipes: this is usually more efficient, and works on Cygwin.
-If t, use ptys: this enables Magit to prompt for passphrases when needed."
- :group 'magit-process
- :type '(choice (const :tag "pipe" nil)
- (const :tag "pty" t)))
-
-(defcustom magit-need-cygwin-noglob
- (equal "x0\n" (with-temp-buffer
- (let ((process-environment
- (append magit-git-environment process-environment)))
- (process-file magit-git-executable
- nil (current-buffer) nil
- "-c" "alias.echo=!echo" "echo" "x{0}"))
- (buffer-string)))
- "Whether to use a workaround for Cygwin's globbing behavior.
-
-If non-nil, add environment variables to `process-environment' to
-prevent the git.exe distributed by Cygwin and MSYS2 from
-attempting to perform glob expansion when called from a native
-Windows build of Emacs. See #2246."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(choice (const :tag "Yes" t)
- (const :tag "No" nil)))
-
-(defcustom magit-process-popup-time -1
- "Popup the process buffer if a command takes longer than this many seconds."
- :group 'magit-process
- :type '(choice (const :tag "Never" -1)
- (const :tag "Immediately" 0)
- (integer :tag "After this many seconds")))
-
-(defcustom magit-process-log-max 32
- "Maximum number of sections to keep in a process log buffer.
-When adding a new section would go beyond the limit set here,
-then the older half of the sections are remove. Sections that
-belong to processes that are still running are never removed.
-When this is nil, no sections are ever removed."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(choice (const :tag "Never remove old sections" nil) integer))
-
-(defcustom magit-credential-cache-daemon-socket
- (--some (-let [(prog . args) (split-string it)]
- (if (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"))))
- "If non-nil, start a credential cache daemon using this socket.
-
-When using Git's cache credential helper in the normal way, Emacs
-sends a SIGHUP to the credential daemon after the git subprocess
-has exited, causing the daemon to also quit. This can be avoided
-by starting the `git-credential-cache--daemon' process directly
-from Emacs.
-
-The function `magit-maybe-start-credential-cache-daemon' takes
-care of starting the daemon if necessary, using the value of this
-option as the socket. If this option is nil, then it does not
-start any daemon. Likewise if another daemon is already running,
-then it starts no new daemon. This function has to be a member
-of the hook variable `magit-credential-hook' for this to work.
-If an error occurs while starting the daemon, most likely because
-the necessary executable is missing, then the function removes
-itself from the hook, to avoid further futile attempts."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(choice (file :tag "Socket")
- (const :tag "Don't start a cache daemon" nil)))
-
-(defcustom magit-process-yes-or-no-prompt-regexp
- " [\[(]\\([Yy]\\(?:es\\)?\\)[/|]\\([Nn]o?\\)[\])] ?[?:] ?$"
- "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 a host
- "^\\(Enter \\)?[Pp]assword\\( for '\\(?99:.*\\)'\\)?: ?$"
- "^.*'s password: ?$"
- "^Yubikey for .*: ?$")
- "List of regexps matching password prompts of Git and its subprocesses.
-Also see `magit-process-find-password-functions'."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(repeat (regexp)))
-
-(defcustom magit-process-find-password-functions nil
- "List of functions to try in sequence to get a password.
-
-These functions may be called when git asks for a password, which
-is detected using `magit-process-password-prompt-regexps'. They
-are called if and only if matching the prompt resulted in the
-value of the 99th submatch to be non-nil. Therefore users can
-control for which prompts these functions should be called by
-putting the host name in the 99th submatch, or not.
-
-If the functions are called, then they are called in the order
-given, with the host name as only argument, until one of them
-returns non-nil. If they are not called or none of them returns
-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))
-
-(defcustom magit-process-username-prompt-regexps
- '("^Username for '.*': ?$")
- "List of regexps matching username prompts of Git and its subprocesses."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(repeat (regexp)))
-
-(defface magit-process-ok
- '((t :inherit magit-section-heading :foreground "green"))
- "Face for zero exit-status."
- :group 'magit-faces)
-
-(defface magit-process-ng
- '((t :inherit magit-section-heading :foreground "red"))
- "Face for non-zero exit-status."
- :group 'magit-faces)
-
-;;; Process Mode
-
-(defvar magit-process-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- map)
- "Keymap for `magit-process-mode'.")
-
-(define-derived-mode magit-process-mode magit-mode "Magit Process"
- "Mode for looking at Git process output."
- :group 'magit-process
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-process-buffer (&optional nodisplay)
- "Display the current repository's process buffer.
-
-If that buffer doesn't exist yet, then create it.
-Non-interactively return the buffer and unless
-optional NODISPLAY is non-nil also display it."
- (interactive)
- (let ((topdir (magit-toplevel)))
- (unless topdir
- (magit--with-safe-default-directory nil
- (setq topdir default-directory)
- (let (prev)
- (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 ((default-directory topdir))
- (magit-generate-new-buffer 'magit-process-mode)))))
- (with-current-buffer buffer
- (if magit-root-section
- (when magit-process-log-max
- (magit-process-truncate-log))
- (magit-process-mode)
- (let ((inhibit-read-only t))
- (make-local-variable 'text-property-default-nonsticky)
- (magit-insert-section (processbuf)
- (insert "\n")))))
- (unless nodisplay
- (magit-display-buffer buffer))
- buffer)))
-
-(defun magit-process-kill ()
- "Kill the process at point."
- (interactive)
- (magit-section-when process
- (let ((process (magit-section-value it)))
- (if (eq (process-status process) 'run)
- (when (magit-confirm 'kill-process)
- (kill-process process))
- (user-error "Process isn't running")))))
-
-;;; Synchronous Processes
-
-(defvar magit-process-raise-error nil)
-
-(defun magit-git (&rest args)
- "Call Git synchronously in a separate process, for side-effects.
-
-Option `magit-git-executable' specifies the Git executable.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'. If Git exits with a non-zero status,
-then raise an error."
- (let ((magit-process-raise-error t))
- (magit-call-git args)))
-
-(defun magit-run-git (&rest args)
- "Call Git synchronously in a separate process, and refresh.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-After Git returns, the current buffer (if it is a Magit buffer)
-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'."
- (magit-call-git args)
- (magit-refresh))
-
-(defvar magit-pre-call-git-hook nil)
-
-(defun magit-call-git (&rest args)
- "Call Git synchronously in a separate process.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'."
- (run-hooks 'magit-pre-call-git-hook)
- (apply #'magit-call-process magit-git-executable
- (magit-process-git-arguments args)))
-
-(defun magit-call-process (program &rest args)
- "Call PROGRAM synchronously in a separate process.
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'."
- (-let [(process-buf . section) (magit-process-setup program args)]
- (magit-process-finish
- (let ((inhibit-read-only t))
- (apply #'magit-process-file program nil process-buf nil args))
- process-buf (current-buffer) default-directory section)))
-
-(defun magit-process-file (&rest args)
- "Process files synchronously in a separate process.
-Identical to `process-file' but temporarily enable Cygwin's
-\"noglob\" option during the call."
- (let ((process-environment (append (magit-cygwin-env-vars)
- process-environment)))
- (apply #'process-file args)))
-
-(defun magit-cygwin-env-vars ()
- (append magit-git-environment
- (when magit-need-cygwin-noglob
- (mapcar (lambda (var)
- (concat var "=" (--if-let (getenv var)
- (concat it " noglob")
- "noglob")))
- '("CYGWIN" "MSYS")))))
-
-(defvar magit-this-process nil)
-
-(defun magit-run-git-with-input (&rest args)
- "Call Git in a separate process.
-ARGS is flattened and then used as arguments to Git.
-
-The current buffer's content is used as the process' standard
-input.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The remaining arguments ARGS specify arguments to Git, they are
-flattened before use."
- (declare (indent 1))
- (if (file-remote-p default-directory)
- ;; We lack `process-file-region', so fall back to asynch +
- ;; waiting in remote case.
- (progn
- (magit-start-git (current-buffer) args)
- (while (and magit-this-process
- (eq (process-status magit-this-process) 'run))
- (sleep-for 0.005)))
- (run-hooks 'magit-pre-call-git-hook)
- (-let* ((process-environment (append (magit-cygwin-env-vars)
- process-environment))
- (flat-args (magit-process-git-arguments args))
- ((process-buf . section)
- (magit-process-setup magit-git-executable flat-args))
- (inhibit-read-only t))
- (magit-process-finish
- (apply #'call-process-region (point-min) (point-max)
- magit-git-executable nil process-buf nil flat-args)
- process-buf nil default-directory section))))
-
-(defun magit-run-git-with-logfile (file &rest args)
- "Call Git in a separate process and log its output to FILE.
-This function might have a short halflive."
- (apply #'magit-process-file magit-git-executable nil `(:file ,file) nil
- (magit-process-git-arguments args))
- (magit-refresh))
-
-;;; Asynchronous Processes
-
-(defun magit-run-git-async (&rest args)
- "Start Git, prepare for refresh, and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-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 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)
- "Export GIT_EDITOR and start Git.
-Also prepare for refresh and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-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' and `with-editor' for more information."
- (with-editor "GIT_EDITOR"
- (let ((magit-process-popup-time -1))
- (magit-run-git-async args))))
-
-(defun magit-run-git-sequencer (&rest args)
- "Export GIT_EDITOR and start Git.
-Also prepare for refresh and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-current when this function was called (if it is a Magit buffer
-and still alive), as well as the respective Magit status buffer.
-If the sequence stops at a commit, make the section representing
-that commit the current section by moving `point' there.
-
-See `magit-start-process' and `with-editor' for more information."
- (with-editor "GIT_EDITOR"
- (let ((magit-process-popup-time -1))
- (magit-run-git-async args)))
- (set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel)
- magit-this-process)
-
-(defvar magit-pre-start-git-hook nil)
-
-(defun magit-start-git (input &rest args)
- "Start Git, prepare for refresh, and return the process object.
-
-If INPUT is non-nil, it has to be a buffer or the name of an
-existing buffer. The buffer content becomes the processes
-standard input.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The remaining arguments ARGS specify arguments to Git, they are
-flattened before use.
-
-After Git returns some buffers are refreshed: the buffer that was
-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."
- (run-hooks 'magit-pre-start-git-hook)
- (apply #'magit-start-process magit-git-executable input
- (magit-process-git-arguments args)))
-
-(defun magit-start-process (program &optional input &rest args)
- "Start PROGRAM, prepare for refresh, and return the process object.
-
-If optional argument INPUT is non-nil, it has to be a buffer or
-the name of an existing buffer. The buffer content becomes the
-processes standard input.
-
-The process is started using `start-file-process' and then setup
-to use the sentinel `magit-process-sentinel' and the filter
-`magit-process-filter'. Information required by these functions
-is stored in the process object. When this function returns the
-process has not started to run yet so it is possible to override
-the sentinel and filter.
-
-After the process returns, `magit-process-sentinel' refreshes the
-buffer that was current when `magit-start-process' was called (if
-it is a Magit buffer and still alive), as well as the respective
-Magit status buffer."
- (-let* (((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))
- (process-environment (append (magit-cygwin-env-vars)
- process-environment)))
- (apply #'start-file-process
- (file-name-nondirectory program)
- process-buf program args))))
- (with-editor-set-process-filter process #'magit-process-filter)
- (set-process-sentinel process #'magit-process-sentinel)
- (set-process-buffer process process-buf)
- (process-put process 'section section)
- (process-put process 'command-buf (current-buffer))
- (process-put process 'default-dir default-directory)
- (when inhibit-magit-refresh
- (process-put process 'inhibit-refresh t))
- (setf (magit-section-process section) process)
- (with-current-buffer process-buf
- (set-marker (process-mark process) (point)))
- (when input
- (with-current-buffer input
- (process-send-region process (point-min) (point-max))
- (process-send-eof process)))
- (setq magit-this-process process)
- (setf (magit-section-value section) process)
- (magit-process-display-buffer process)
- process))
-
-;;; Process Internals
-
-(defun magit-process-setup (program args)
- (magit-process-set-mode-line program args)
- (let ((pwd default-directory)
- (buf (magit-process-buffer t)))
- (cons buf (with-current-buffer buf
- (prog1 (magit-process-insert-section pwd program args nil nil)
- (backward-char 1))))))
-
-(defun magit-process-insert-section (pwd program args &optional errcode errlog)
- (let ((inhibit-read-only t)
- (magit-insert-section--parent magit-root-section))
- (goto-char (1- (point-max)))
- (magit-insert-section (process)
- (insert (if errcode
- (format "%3s " (propertize (number-to-string errcode)
- 'face 'magit-process-ng))
- "run "))
- (unless (equal (expand-file-name pwd)
- (expand-file-name default-directory))
- (insert (file-relative-name pwd default-directory) ?\s))
- (insert (propertize program 'face 'magit-section-heading))
- (insert " ")
- (when (and args (equal program magit-git-executable))
- (setq args (-split-at (length magit-git-global-arguments) args))
- (insert (propertize (char-to-string magit-ellipsis)
- 'face 'magit-section-heading
- 'help-echo (mapconcat #'identity (car args) " ")))
- (insert " ")
- (setq args (cadr args)))
- (insert (propertize (mapconcat #'identity args " ")
- 'face 'magit-section-heading))
- (magit-insert-heading)
- (when errlog
- (insert-file-contents errlog)
- (goto-char (1- (point-max))))
- (insert "\n"))))
-
-(defun magit-process-truncate-log ()
- (let* ((head nil)
- (tail (magit-section-children magit-root-section))
- (count (length tail)))
- (when (> (1+ count) magit-process-log-max)
- (while (and (cdr tail)
- (> count (/ magit-process-log-max 2)))
- (let* ((inhibit-read-only t)
- (section (car tail))
- (process (magit-section-process section)))
- (cond ((not process))
- ((memq (process-status process) '(exit signal))
- (delete-region (magit-section-start section)
- (1+ (magit-section-end section)))
- (cl-decf count))
- (t
- (push section head))))
- (pop tail))
- (setf (magit-section-children magit-root-section)
- (nconc (reverse head) tail)))))
-
-(defun magit-process-sentinel (process event)
- "Default sentinel used by `magit-start-process'."
- (when (memq (process-status process) '(exit signal))
- (setq event (substring event 0 -1))
- (when (string-match "^finished" event)
- (message (concat (capitalize (process-name process)) " finished")))
- (magit-process-finish process)
- (when (eq process magit-this-process)
- (setq magit-this-process nil))
- (unless (process-get process 'inhibit-refresh)
- (let ((command-buf (process-get process 'command-buf)))
- (if (buffer-live-p command-buf)
- (with-current-buffer command-buf
- (magit-refresh))
- (with-temp-buffer
- (setq default-directory (process-get process 'default-dir))
- (magit-refresh)))))))
-
-(defun magit-sequencer-process-sentinel (process event)
- "Special sentinel used by `magit-run-git-sequencer'."
- (when (memq (process-status process) '(exit signal))
- (magit-process-sentinel process event)
- (--when-let (magit-mode-get-buffer 'magit-status-mode)
- (with-current-buffer it
- (--when-let
- (magit-get-section
- `((commit . ,(magit-rev-parse "HEAD"))
- (,(pcase (car (cadr (-split-at
- (1+ (length magit-git-global-arguments))
- (process-command process))))
- ((or "rebase" "am") 'rebase-sequence)
- ((or "cherry-pick" "revert") 'sequence)))
- (status)))
- (goto-char (magit-section-start it))
- (magit-section-update-highlight))))))
-
-(defun magit-process-filter (proc string)
- "Default filter used by `magit-start-process'."
- (with-current-buffer (process-buffer proc)
- (let ((inhibit-read-only t))
- (magit-process-yes-or-no-prompt proc string)
- (magit-process-username-prompt proc string)
- (magit-process-password-prompt proc string)
- (goto-char (process-mark proc))
- (setq string (propertize string 'magit-section
- (process-get proc 'section)))
- ;; Find last ^M in string. If one was found, ignore
- ;; everything before it and delete the current line.
- (let ((ret-pos (length string)))
- (while (and (>= (cl-decf ret-pos) 0)
- (/= ?\r (aref string ret-pos))))
- (if (< ret-pos 0)
- (insert string)
- (delete-region (line-beginning-position) (point))
- (insert (substring string (1+ ret-pos)))))
- (set-marker (process-mark proc) (point)))))
-
-(defmacro magit-process-kill-on-abort (proc &rest body)
- (declare (indent 1) (debug (form body)))
- (let ((map (cl-gensym)))
- `(let ((,map (make-sparse-keymap)))
- (set-keymap-parent ,map minibuffer-local-map)
- (define-key ,map "\C-g"
- (lambda ()
- (interactive)
- (ignore-errors (kill-process ,proc))
- (abort-recursive-edit)))
- (let ((minibuffer-local-map ,map))
- ,@body))))
-
-(defun magit-process-yes-or-no-prompt (process string)
- "Forward Yes-or-No prompts to the user."
- (-when-let (beg (string-match magit-process-yes-or-no-prompt-regexp string))
- (let ((max-mini-window-height 30))
- (process-send-string
- process
- (downcase
- (concat
- (match-string
- (if (save-match-data
- (magit-process-kill-on-abort process
- (yes-or-no-p (substring string 0 beg)))) 1 2)
- string)
- "\n"))))))
-
-(defun magit-process-password-auth-source (key)
- "Use `auth-source-search' to get a password.
-If found, return the password. Otherwise, return nil."
- (require 'auth-source)
- (let ((secret (plist-get (car (auth-source-search :max 1 :host key
- :require '(:host)))
- :secret)))
- (if (functionp secret)
- (funcall secret)
- secret)))
-
-(defun magit-process-password-prompt (process string)
- "Find a password based on prompt STRING and send it to git.
-First try the functions in `magit-process-find-password-functions'.
-If none of them returns a password, then read it from the user
-instead."
- (--when-let (magit-process-match-prompt
- magit-process-password-prompt-regexps string)
- (process-send-string
- process (magit-process-kill-on-abort process
- (concat (or (--when-let (match-string 99 string)
- (run-hook-with-args-until-success
- 'magit-process-find-password-functions it))
- (read-passwd it))
- "\n")))))
-
-(defun magit-process-username-prompt (process string)
- "Forward username prompts to the user."
- (--when-let (magit-process-match-prompt
- magit-process-username-prompt-regexps string)
- (process-send-string
- process (magit-process-kill-on-abort process
- (concat (read-string it nil nil (user-login-name)) "\n")))))
-
-(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? (string-match it string) prompts)
- (let ((prompt (match-string 0 string)))
- (cond ((string-suffix-p ": " prompt) prompt)
- ((string-suffix-p ":" prompt) (concat prompt " "))
- (t (concat prompt ": "))))))
-
-(defvar magit-credential-hook nil
- "Hook run before Git needs credentials.")
-
-(defvar magit-credential-cache-daemon-process nil)
-
-(defun magit-maybe-start-credential-cache-daemon ()
- "Maybe start a `git-credential-cache--daemon' process.
-
-If such a process is already running or if the value of option
-`magit-credential-cache-daemon-socket' is nil, then do nothing.
-Otherwise start the process passing the value of that options
-as argument."
- (unless (or (not magit-credential-cache-daemon-socket)
- (process-live-p magit-credential-cache-daemon-process)
- (memq magit-credential-cache-daemon-process
- (list-system-processes)))
- (setq magit-credential-cache-daemon-process
- (or (--first (-let (((&alist 'comm comm 'user user)
- (process-attributes it)))
- (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*"
- magit-git-executable
- "credential-cache--daemon"
- magit-credential-cache-daemon-socket)
- ;; Some Git implementations (e.g. Windows) won't have
- ;; this program; if we fail the first time, stop trying.
- ((debug error)
- (remove-hook 'magit-credential-hook
- #'magit-maybe-start-credential-cache-daemon)))))))
-
-(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)
-
-(defun magit-process-set-mode-line (program args)
- (when (equal program magit-git-executable)
- (setq args (nthcdr (length magit-git-global-arguments) args)))
- (let ((str (concat " " program (and args (concat " " (car args))))))
- (dolist (buf (magit-mode-get-buffers))
- (with-current-buffer buf (setq mode-line-process str)))))
-
-(defun magit-process-unset-mode-line ()
- (dolist (buf (magit-mode-get-buffers))
- (with-current-buffer buf (setq mode-line-process nil))))
-
-(defvar magit-process-error-message-re
- (concat "^\\(?:error\\|fatal\\|git\\): \\(.*\\)" paragraph-separate))
-
-(define-error 'magit-git-error "Git error")
-
-(defvar-local magit-this-error nil)
-
-(defun magit-process-finish (arg &optional process-buf command-buf
- default-dir section)
- (unless (integerp arg)
- (setq process-buf (process-buffer arg)
- command-buf (process-get arg 'command-buf)
- default-dir (process-get arg 'default-dir)
- section (process-get arg 'section)
- arg (process-exit-status arg)))
- (magit-process-unset-mode-line)
- (when (featurep 'dired)
- (dired-uncache default-dir))
- (when (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (let ((inhibit-read-only t)
- (marker (magit-section-start section)))
- (goto-char marker)
- (save-excursion
- (delete-char 3)
- (set-marker-insertion-type marker nil)
- (insert (propertize (format "%3s" arg)
- 'magit-section section
- 'face (if (= arg 0)
- 'magit-process-ok
- 'magit-process-ng)))
- (set-marker-insertion-type marker t))
- (if (= (magit-section-end section)
- (+ (line-end-position) 2))
- (save-excursion
- (goto-char (1+ (line-end-position)))
- (delete-char -1)
- (setf (magit-section-content section) nil))
- (let ((buf (magit-process-buffer t)))
- (when (and (= arg 0)
- (not (--any-p (eq (window-buffer it) buf)
- (window-list))))
- (magit-section-hide section)))))))
- (unless (= arg 0)
- (let ((msg (or (and (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (save-excursion
- (goto-char (magit-section-end section))
- (--when-let (magit-section-content section)
- (when (re-search-backward
- magit-process-error-message-re it t)
- (match-string 1))))))
- "Git failed")))
- (if magit-process-raise-error
- (signal 'magit-git-error (format "%s (in %s)" msg default-dir))
- (--when-let (magit-mode-get-buffer 'magit-status-mode)
- (setq magit-this-error msg))
- (message "%s ... [%s buffer %s for details]" msg
- (-if-let (key (and (buffer-live-p command-buf)
- (with-current-buffer command-buf
- (car (where-is-internal
- 'magit-process-buffer)))))
- (format "Hit %s to see" (key-description key))
- "See")
- (buffer-name process-buf)))))
- arg)
-
-(defun magit-process-display-buffer (process)
- (when (process-live-p process)
- (let ((buf (process-buffer process)))
- (cond ((not (buffer-live-p buf)))
- ((= magit-process-popup-time 0)
- (if (minibufferp)
- (switch-to-buffer-other-window buf)
- (pop-to-buffer buf)))
- ((> magit-process-popup-time 0)
- (run-with-timer magit-process-popup-time nil
- (lambda (p)
- (when (eq (process-status p) 'run)
- (let ((buf (process-buffer p)))
- (when (buffer-live-p buf)
- (if (minibufferp)
- (switch-to-buffer-other-window buf)
- (pop-to-buffer buf))))))
- process))))))
-
-;;; magit-process.el ends soon
-(provide 'magit-process)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-process.el ends here
+++ /dev/null
-;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for interacting with remote
-;; repositories. Commands for cloning, fetching, pulling, and
-;; pushing are defined here.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Clone
-
-(defcustom magit-clone-set-remote-head nil
- "Whether cloning creates the symbolic-ref `<remote>/HEAD'."
- :package-version '(magit . "2.4.2")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-clone-set-remote.pushDefault 'ask
- "Whether to set the value of `remote.pushDefault' after cloning.
-
-If t, then set without asking. If nil, then don't set. If
-`ask', then ask."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(choice (const :tag "set" t)
- (const :tag "ask" ask)
- (const :tag "don't set" nil)))
-
-;;;###autoload
-(defun magit-clone (repository directory)
- "Clone the REPOSITORY to DIRECTORY.
-Then show the status buffer for the new repository."
- (interactive
- (let ((url (magit-read-string-ns "Clone repository")))
- (list url (read-directory-name
- "Clone to: " nil nil nil
- (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
- (match-string 1 url))))))
- (setq directory (file-name-as-directory (expand-file-name directory)))
- (message "Cloning %s..." repository)
- (when (= (magit-call-git "clone" repository
- ;; Stop cygwin git making a "c:" directory.
- (magit-convert-git-filename directory))
- 0)
- (let ((default-directory directory))
- (when (or (eq magit-clone-set-remote.pushDefault t)
- (and magit-clone-set-remote.pushDefault
- (y-or-n-p "Set `remote.pushDefault' to \"origin\"? ")))
- (magit-call-git "config" "remote.pushDefault" "origin"))
- (unless magit-clone-set-remote-head
- (magit-remote-unset-head "origin")))
- (message "Cloning %s...done" repository)
- (magit-status-internal directory)))
-
-;;; Setup
-
-(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset
- "Whether to set the value of `remote.pushDefault' after adding a remote.
-
-If `ask', then always ask. If `ask-if-unset', then ask, but only
-if the variable isn't set already. If nil, then don't ever set.
-If the value is a string, then set without asking, provided the
-name of the name of the added remote is equal to that string and
-the variable isn't already set."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(choice (const :tag "ask if unset" ask-if-unset)
- (const :tag "always ask" ask)
- (string :tag "set if named")
- (const :tag "don't set")))
-
-;;;###autoload (autoload 'magit-remote-popup "magit-remote" nil t)
-(magit-define-popup magit-remote-popup
- "Popup console for remote commands."
- 'magit-commands nil nil
- :man-page "git-remote"
- :actions '((?a "Add" magit-remote-add)
- (?r "Rename" magit-remote-rename)
- (?k "Remove" magit-remote-remove)
- (?u "Set url" magit-remote-set-url)))
-
-(defun magit-read-url (prompt &optional initial-input)
- (let ((url (magit-read-string-ns prompt initial-input)))
- (if (string-prefix-p "~" url)
- (expand-file-name url)
- url)))
-
-;;;###autoload
-(defun magit-remote-add (remote url)
- "Add a remote named REMOTE and fetch it."
- (interactive (list (magit-read-string-ns "Remote name")
- (magit-read-url "Remote url")))
- (if (pcase (list magit-remote-add-set-remote.pushDefault
- (magit-get "remote.defaultPush"))
- (`(,(pred stringp) ,_) t)
- ((or `(ask ,_) `(ask-if-unset nil))
- (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote))))
- (progn (magit-call-git "remote" "add" "-f" remote url)
- (magit-call-git "config" "remote.pushDefault" remote)
- (magit-refresh))
- (magit-run-git-async "remote" "add" "-f" remote url)))
-
-;;;###autoload
-(defun magit-remote-rename (old new)
- "Rename the remote named OLD to NEW."
- (interactive
- (let ((remote (magit-read-remote "Rename remote")))
- (list remote (magit-read-string-ns (format "Rename %s to" remote)))))
- (unless (string= old new)
- (magit-run-git "remote" "rename" old new)))
-
-;;;###autoload
-(defun magit-remote-set-url (remote url)
- "Change the url of the remote named REMOTE to URL."
- (interactive
- (let ((remote (magit-read-remote "Set url of remote")))
- (list remote (magit-read-url
- "Url" (magit-get "remote" remote "url")))))
- (magit-run-git "remote" "set-url" remote url))
-
-;;;###autoload
-(defun magit-remote-remove (remote)
- "Delete the remote named REMOTE."
- (interactive (list (magit-read-remote "Delete remote")))
- (magit-run-git "remote" "rm" remote))
-
-;;;###autoload
-(defun magit-remote-set-head (remote &optional branch)
- "Set the local representation of REMOTE's default branch.
-Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
-accordingly. With a prefix argument query for the branch to be
-used, which allows you to select an incorrect value if you fancy
-doing that."
- (interactive
- (let ((remote (magit-read-remote "Set HEAD for remote")))
- (list remote
- (and current-prefix-arg
- (magit-read-remote-branch (format "Set %s/HEAD to" remote)
- remote nil nil t)))))
- (magit-run-git "remote" "set-head" remote (or branch "--auto")))
-
-;;;###autoload
-(defun magit-remote-unset-head (remote)
- "Unset the local representation of REMOTE's default branch.
-Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\"."
- (interactive (list (magit-read-remote "Unset HEAD for remote")))
- (magit-run-git "remote" "set-head" remote "--delete"))
-
-;;; Fetch
-
-;;;###autoload (autoload 'magit-fetch-popup "magit-remote" nil t)
-(magit-define-popup magit-fetch-popup
- "Popup console for fetch commands."
- 'magit-commands
- :man-page "git-fetch"
- :switches '((?p "Prune deleted branches" "--prune"))
- :actions '("Fetch from"
- (?p magit-get-push-remote magit-fetch-from-pushremote)
- (?u magit-get-remote magit-fetch-from-upstream)
- (?e "elsewhere" magit-fetch)
- (?a "all remotes" magit-fetch-all)
- "Fetch"
- (?m "submodules" magit-submodule-fetch))
- :default-action 'magit-fetch
- :max-action-columns 1)
-
-(defun magit-git-fetch (remote args)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "fetch" remote args))
-
-;;;###autoload
-(defun magit-fetch-from-pushremote (args)
- "Fetch from the push-remote of the current branch."
- (interactive (list (magit-fetch-arguments)))
- (--if-let (magit-get-push-remote)
- (magit-git-fetch it args)
- (--if-let (magit-get-current-branch)
- (user-error "No push-remote is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-fetch-from-upstream (args)
- "Fetch from the upstream repository of the current branch."
- (interactive (list (magit-fetch-arguments)))
- (--if-let (magit-get-remote)
- (magit-git-fetch it args)
- (--if-let (magit-get-current-branch)
- (user-error "No upstream is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-fetch (remote args)
- "Fetch from another repository."
- (interactive (list (magit-read-remote "Fetch remote")
- (magit-fetch-arguments)))
- (magit-git-fetch remote args))
-
-;;;###autoload
-(defun magit-fetch-all (args)
- "Fetch from all remotes."
- (interactive (list (magit-fetch-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update" args))
-
-;;;###autoload
-(defun magit-fetch-all-prune ()
- "Fetch from all remotes, and prune.
-Prune remote tracking branches for branches that have been
-removed on the respective remote."
- (interactive)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update" "--prune"))
-
-;;;###autoload
-(defun magit-fetch-all-no-prune ()
- "Fetch from all remotes."
- (interactive)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update"))
-
-;;; Pull
-
-;;;###autoload (autoload 'magit-pull-popup "magit-remote" nil t)
-(magit-define-popup magit-pull-popup
- "Popup console for pull commands."
- 'magit-commands
- :man-page "git-pull"
- :variables '("Variables"
- (?r "branch.%s.rebase"
- magit-cycle-branch*rebase
- magit-pull-format-branch*rebase))
- :actions '((lambda ()
- (--if-let (magit-get-current-branch)
- (concat
- (propertize "Pull into " 'face 'magit-popup-heading)
- (propertize it 'face 'magit-branch-local)
- (propertize " from" 'face 'magit-popup-heading))
- (propertize "Pull from" 'face 'magit-popup-heading)))
- (?p magit-get-push-branch magit-pull-from-pushremote)
- (?u magit-get-upstream-branch magit-pull-from-upstream)
- (?e "elsewhere" magit-pull))
- :default-action 'magit-pull
- :max-action-columns 1)
-
-;;;###autoload (autoload 'magit-pull-and-fetch-popup "magit-remote" nil t)
-(magit-define-popup magit-pull-and-fetch-popup
- "Popup console for pull and fetch commands.
-
-This popup is intended as a replacement for the separate popups
-`magit-pull-popup' and `magit-fetch-popup'. To use it, add this
-to your init file:
-
- (with-eval-after-load \\='magit-remote
- (define-key magit-mode-map \"f\" \\='magit-pull-and-fetch-popup)
- (define-key magit-mode-map \"F\" nil))
-
-The combined popup does not offer all commands and arguments
-available from the individual popups. Instead of the argument
-`--prune' and the command `magit-fetch-all' it uses two commands
-`magit-fetch-prune' and `magit-fetch-no-prune'. And the commands
-`magit-fetch-from-pushremote' and `magit-fetch-from-upstream' are
-missing. To add them use something like:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-pull-and-fetch-popup ?U
- \\='magit-get-upstream-branch
- \\='magit-fetch-from-upstream-remote ?F)
- (magit-define-popup-action \\='magit-pull-and-fetch-popup ?P
- \\='magit-get-push-branch
- \\='magit-fetch-from-push-remote ?F))"
- 'magit-commands
- :man-page "git-pull"
- :variables '("Pull variables"
- (?r "branch.%s.rebase"
- magit-cycle-branch*rebase
- magit-pull-format-branch*rebase))
- :actions '((lambda ()
- (--if-let (magit-get-current-branch)
- (concat
- (propertize "Pull into " 'face 'magit-popup-heading)
- (propertize it 'face 'magit-branch-local)
- (propertize " from" 'face 'magit-popup-heading))
- (propertize "Pull from" 'face 'magit-popup-heading)))
- (?p magit-get-push-branch magit-pull-from-pushremote)
- (?u magit-get-upstream-branch magit-pull-from-upstream)
- (?e "elsewhere" magit-pull)
- "Fetch from"
- (?f "remotes" magit-fetch-all-no-prune)
- (?F "remotes and prune" magit-fetch-all-prune)
- "Fetch"
- (?m "submodules" magit-submodule-fetch))
- :default-action 'magit-fetch
- :max-action-columns 1)
-
-(defun magit-pull-format-branch*rebase ()
- (magit-popup-format-variable (format "branch.%s.rebase"
- (or (magit-get-current-branch) "<name>"))
- '("true" "false")
- "false" "pull.rebase"))
-
-(defun magit-git-pull (source args)
- (run-hooks 'magit-credential-hook)
- (-let [(remote . branch)
- (magit-split-branch-name source)]
- (magit-run-git-with-editor "pull" args remote branch)))
-
-;;;###autoload
-(defun magit-pull-from-pushremote (args)
- "Pull from the push-remote of the current branch."
- (interactive (list (magit-pull-arguments)))
- (--if-let (magit-get-push-branch)
- (magit-git-pull it args)
- (--if-let (magit-get-current-branch)
- (user-error "No push-remote is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-pull-from-upstream (args)
- "Pull from the upstream of the current branch."
- (interactive (list (magit-pull-arguments)))
- (--if-let (magit-get-upstream-branch)
- (magit-git-pull it args)
- (--if-let (magit-get-current-branch)
- (user-error "No upstream is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-pull (source args)
- "Pull from a branch read in the minibuffer."
- (interactive (list (magit-read-remote-branch "Pull" nil nil nil t)
- (magit-pull-arguments)))
- (magit-git-pull source args))
-
-;;; Push
-
-(defcustom magit-push-current-set-remote-if-missing t
- "Whether to configure missing remotes before pushing.
-
-When nil, then the command `magit-push-current-to-pushremote' and
-`magit-push-current-to-upstream' do not appear in the push popup
-if the push-remote resp. upstream is not configured. If the user
-invokes one of these commands anyway, then it raises an error.
-
-When non-nil, then these commands always appear in the push
-popup. But if the required configuration is missing, then they
-do appear in a way that indicates that this is the case. If the
-user invokes one of them, then it asks for the necessary
-configuration, stores the configuration, and then uses it to push
-a first time.
-
-This option also affects whether the argument `--set-upstream' is
-available in the popup. If the value is t, then that argument is
-redundant. But note that changing the value of this option does
-not take affect immediately, the argument will only be added or
-removed after restarting Emacs."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;;###autoload (autoload 'magit-push-popup "magit-remote" nil t)
-(magit-define-popup magit-push-popup
- "Popup console for push commands."
- 'magit-commands
- :man-page "git-push"
- :switches `((?f "Force" "--force-with-lease")
- (?h "Disable hooks" "--no-verify")
- (?d "Dry run" "--dry-run")
- ,@(and (not magit-push-current-set-remote-if-missing)
- '((?u "Set upstream" "--set-upstream"))))
- :actions '((lambda ()
- (--when-let (magit-get-current-branch)
- (concat (propertize "Push " 'face 'magit-popup-heading)
- (propertize it 'face 'magit-branch-local)
- (propertize " to" 'face 'magit-popup-heading))))
- (?p magit--push-current-to-pushremote-desc
- magit-push-current-to-pushremote)
- (?u magit--push-current-to-upstream-desc
- magit-push-current-to-upstream)
- (?e "elsewhere\n" magit-push-current)
- "Push"
- (?o "another branch" magit-push)
- (?T "a tag" magit-push-tag)
- (?m "matching branches" magit-push-matching)
- (?t "all tags" magit-push-tags))
- :max-action-columns 2)
-
-(defun magit-git-push (branch target args)
- (run-hooks 'magit-credential-hook)
- (-let [(remote . target)
- (magit-split-branch-name target)]
- (magit-run-git-async "push" "-v" args remote
- (format "%s:refs/heads/%s" branch target))))
-
-;;;###autoload
-(defun magit-push-current-to-pushremote (args &optional push-remote)
- "Push the current branch to `branch.<name>.pushRemote'.
-If that variable is unset, then push to `remote.pushDefault'.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the push-remote is not configured, then read the push-remote from
-the user, set it, and then push to it. With a prefix argument
-the push-remote can be changed before pushed to it."
- (interactive
- (list (magit-push-arguments)
- (and (magit--push-current-set-pushremote-p current-prefix-arg)
- (magit-read-remote (format "Set push-remote of %s and push there"
- (magit-get-current-branch))))))
- (--if-let (magit-get-current-branch)
- (progn (when push-remote
- (magit-call-git "config"
- (format "branch.%s.pushRemote"
- (magit-get-current-branch))
- push-remote))
- (-if-let (remote (magit-get-push-remote it))
- (if (member remote (magit-list-remotes))
- (magit-git-push it (concat remote "/" it) args)
- (user-error "Remote `%s' doesn't exist" remote))
- (user-error "No push-remote is configured for %s" it)))
- (user-error "No branch is checked out")))
-
-(defun magit--push-current-set-pushremote-p (&optional change)
- (and (or change
- (and magit-push-current-set-remote-if-missing
- (not (magit-get-push-remote))))
- (magit-get-current-branch)))
-
-(defun magit--push-current-to-pushremote-desc ()
- (--if-let (magit-get-push-branch)
- (concat (magit-branch-set-face it) "\n")
- (and (magit--push-current-set-pushremote-p)
- (concat (propertize "pushRemote" 'face 'bold)
- ", after setting that\n"))))
-
-;;;###autoload
-(defun magit-push-current-to-upstream (args &optional upstream)
- "Push the current branch to its upstream branch.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the upstream is not configured, then read the upstream from the
-user, set it, and then push to it. With a prefix argument the
-upstream can be changed before pushed to it."
- (interactive
- (list (magit-push-arguments)
- (and (magit--push-current-set-upstream-p current-prefix-arg)
- (magit-read-upstream-branch))))
- (--if-let (magit-get-current-branch)
- (progn
- (when upstream
- (magit-set-branch*merge/remote it upstream))
- (-if-let (target (magit-get-upstream-branch it))
- (magit-git-push it target args)
- (user-error "No upstream is configured for %s" it)))
- (user-error "No branch is checked out")))
-
-(defun magit--push-current-set-upstream-p (&optional change)
- (and (or change
- (and magit-push-current-set-remote-if-missing
- (not (magit-get-upstream-branch))))
- (magit-get-current-branch)))
-
-(defun magit--push-current-to-upstream-desc ()
- (--if-let (magit-get-upstream-branch)
- (concat (magit-branch-set-face it) "\n")
- (and (magit--push-current-set-upstream-p)
- (concat (propertize "@{upstream}" 'face 'bold)
- ", after setting that\n"))))
-
-;;;###autoload
-(defun magit-push-current (target args)
- "Push the current branch to a branch read in the minibuffer."
- (interactive
- (--if-let (magit-get-current-branch)
- (list (magit-read-remote-branch (format "Push %s to" it)
- nil nil it 'confirm)
- (magit-push-arguments))
- (user-error "No branch is checked out")))
- (magit-git-push (magit-get-current-branch) target args))
-
-;;;###autoload
-(defun magit-push (source target args)
- "Push an arbitrary branch or commit somewhere.
-Both the source and the target are read in the minibuffer."
- (interactive
- (let ((source (magit-read-local-branch-or-commit "Push")))
- (list source
- (magit-read-remote-branch (format "Push %s to" source) nil
- (magit-get-upstream-branch source)
- source 'confirm)
- (magit-push-arguments))))
- (magit-git-push source target args))
-
-;;;###autoload
-(defun magit-push-matching (remote &optional args)
- "Push all matching branches to another repository.
-If multiple remotes exist, then read one from the user.
-If just one exists, use that without requiring confirmation."
- (interactive (list (magit-read-remote "Push matching branches to" nil t)
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote ":"))
-
-;;;###autoload
-(defun magit-push-tags (remote &optional args)
- "Push all tags to another repository.
-If only one remote exists, then push to that. Otherwise prompt
-for a remote, offering the remote configured for the current
-branch as default."
- (interactive (list (magit-read-remote "Push tags to remote" nil t)
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" remote "--tags" args))
-
-;;;###autoload
-(defun magit-push-tag (tag remote &optional args)
- "Push a tag to another repository."
- (interactive
- (let ((tag (magit-read-tag "Push tag")))
- (list tag (magit-read-remote (format "Push %s to remote" tag) nil t)
- (magit-push-arguments))))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" remote tag args))
-
-;;;###autoload
-(defun magit-push-implicitly (args)
- "Push somewhere without using an explicit refspec.
-
-This command simply runs \"git push -v [ARGS]\". ARGS are the
-arguments specified in the popup buffer. No explicit refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?P
- 'magit-push-implicitly--desc
- 'magit-push-implicitly ?p t))
-
-The function `magit-push-implicitly--desc' attempts to predict
-what this command will do, the value it returns is displayed in
-the popup buffer."
- (interactive (list (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args))
-
-(defun magit-push-implicitly--desc ()
- (let ((default (magit-get "push.default")))
- (unless (equal default "nothing")
- (or (-when-let* ((remote (or (magit-get-remote)
- (magit-remote-p "origin")))
- (refspec (magit-get "remote" remote "push")))
- (format "%s using %s"
- (propertize remote 'face 'magit-branch-remote)
- (propertize refspec 'face 'bold)))
- (--when-let (and (not (magit-get-push-branch))
- (magit-get-upstream-branch))
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (propertize "@{upstream}" 'face 'bold)))
- (--when-let (magit-get-push-branch)
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (propertize "pushRemote" 'face 'bold)))
- (--when-let (magit-get-@{push}-branch)
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (propertize "@{push}" 'face 'bold)))
- (format "using %s (%s is %s)\n"
- (propertize "git push" 'face 'bold)
- (propertize "push.default" 'face 'bold)
- (propertize default 'face 'bold))))))
-
-;;;###autoload
-(defun magit-push-to-remote (remote args)
- "Push to REMOTE without using an explicit refspec.
-The REMOTE is read in the minibuffer.
-
-This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
-are the arguments specified in the popup buffer. No refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?r
- 'magit-push-to-remote--desc
- 'magit-push-to-remote ?p t))"
- (interactive (list (magit-read-remote "Push to remote")
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote))
-
-(defun magit-push-to-remote--desc ()
- (format "using %s\n" (propertize "git push <remote>" 'face 'bold)))
-
-;;; Email
-
-;;;###autoload (autoload 'magit-patch-popup "magit-remote" nil t)
-(magit-define-popup magit-patch-popup
- "Popup console for patch commands."
- 'magit-commands
- :man-page "git-format-patch"
- :switches '("Switches for formatting patches"
- (?l "Add cover letter" "--cover-letter"))
- :options '("Options for formatting patches"
- (?f "From" "--from=")
- (?t "To" "--to=")
- (?c "CC" "--cc=")
- (?r "In reply to" "--in-reply-to=")
- (?v "Reroll count" "--reroll-count=")
- (?s "Thread style" "--thread=")
- (?U "Context lines" "-U")
- (?M "Detect renames" "-M")
- (?C "Detect copies" "-C")
- (?A "Diff algorithm" "--diff-algorithm="
- magit-diff-select-algorithm)
- (?o "Output directory" "--output-directory="))
- :actions '((?p "Format patches" magit-format-patch)
- (?r "Request pull" magit-request-pull))
- :default-action 'magit-format-patch)
-
-;;;###autoload
-(defun magit-format-patch (range args)
- "Create patches for the commits in RANGE.
-When a single commit is given for RANGE, create a patch for the
-changes introduced by that commit (unlike 'git format-patch'
-which creates patches for all commits that are reachable from
-HEAD but not from the specified commit)."
- (interactive
- (list (-if-let (revs (magit-region-values 'commit))
- (concat (car (last revs)) "^.." (car revs))
- (let ((range (magit-read-range-or-commit "Format range or commit")))
- (if (string-match-p "\\.\\." range)
- range
- (format "%s~..%s" range range))))
- (magit-patch-arguments)))
- (magit-call-git "format-patch" range args)
- (when (member "--cover-letter" args)
- (find-file
- (expand-file-name
- "0000-cover-letter.patch"
- (let ((topdir (magit-toplevel)))
- (or (--some (and (string-match "--output-directory=\\(.+\\)" it)
- (expand-file-name (match-string 1 it) topdir))
- args)
- topdir))))))
-
-;;;###autoload
-(defun magit-request-pull (url start end)
- "Request upstream to pull from you public repository.
-
-URL is the url of your publically accessible repository.
-START is a commit that already is in the upstream repository.
-END is the last commit, usually a branch name, which upstream
-is asked to pull. START has to be reachable from that commit."
- (interactive
- (list (magit-get "remote" (magit-read-remote "Remote") "url")
- (magit-read-branch-or-commit "Start" (magit-get-upstream-branch))
- (magit-read-branch-or-commit "End")))
- (let ((dir default-directory))
- ;; mu4e changes default-directory
- (compose-mail)
- (setq default-directory dir))
- (message-goto-body)
- (magit-git-insert "request-pull" start url end)
- (set-buffer-modified-p nil))
-
-;;; magit-remote.el ends soon
-(provide 'magit-remote)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-remote.el ends here
+++ /dev/null
-;;; magit-section.el --- section functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements "sections" as used in all Magit buffers.
-;; If you have used Magit before then you probably know what that
-;; means, otherwise think "read-only Org-Mode for Git", kinda.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-utils)
-
-(defvar magit-keep-region-overlay)
-
-;;; Options
-
-(defgroup magit-section nil
- "Expandable sections."
- :group 'magit)
-
-(defcustom magit-section-show-child-count t
- "Whether to append the number of children to section headings."
- :package-version '(magit . "2.1.0")
- :group 'magit-section
- :type 'boolean)
-
-(defcustom magit-section-movement-hook
- '(magit-hunk-set-window-start
- magit-log-maybe-update-revision-buffer
- magit-log-maybe-show-more-commits)
- "Hook run by `magit-section-goto'.
-That function in turn is used by all section movement commands."
- :package-version '(magit . "2.3.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-hunk-set-window-start
- magit-status-maybe-update-revision-buffer
- magit-status-maybe-update-blob-buffer
- magit-log-maybe-update-revision-buffer
- magit-log-maybe-update-blob-buffer
- magit-log-maybe-show-more-commits))
-
-(defcustom magit-section-highlight-hook
- '(magit-diff-highlight
- magit-section-highlight
- magit-section-highlight-selection)
- "Functions used to highlight the current section.
-Each function is run with the current section as only argument
-until one of them returns non-nil."
- :package-version '(magit . "2.1.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-diff-highlight
- magit-section-highlight
- magit-section-highlight-selection))
-
-(defcustom magit-section-unhighlight-hook
- '(magit-diff-unhighlight)
- "Functions used to unhighlight the previously current section.
-Each function is run with the current section as only argument
-until one of them returns non-nil. Most sections are properly
-unhighlighted without requiring a specialized unhighlighter,
-diff-related sections being the only exception."
- :package-version '(magit . "2.1.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-diff-unhighlight))
-
-(defcustom magit-section-set-visibility-hook
- '(magit-diff-expansion-threshold
- magit-section-set-visibility-from-cache)
- "Hook used to set the initial visibility of a section.
-Stop at the first function that returns non-nil. The value
-should be `show' or `hide'. If no function returns non-nil
-determine the visibility as usual, i.e. use the hardcoded
-section specific default (see `magit-insert-section')."
- :package-version '(magit . "2.4.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-diff-expansion-threshold
- magit-section-set-visibility-from-cache))
-
-(defface magit-section-highlight
- '((((class color) (background light)) :background "grey95")
- (((class color) (background dark)) :background "grey20"))
- "Face for highlighting the current section."
- :group 'magit-faces)
-
-(defface magit-section-heading
- '((((class color) (background light)) :foreground "DarkGoldenrod4" :weight bold)
- (((class color) (background dark)) :foreground "LightGoldenrod2" :weight bold))
- "Face for section headings."
- :group 'magit-faces)
-
-(defface magit-section-secondary-heading '((t :weight bold))
- "Face for section headings of some secondary headings."
- :group 'magit-faces)
-
-(defface magit-section-heading-selection
- '((((class color) (background light)) :foreground "salmon4")
- (((class color) (background dark)) :foreground "LightSalmon3"))
- "Face for selected section headings."
- :group 'magit-faces)
-
-;;; Core
-
-(cl-defstruct magit-section
- type value start content end hidden washer refined
- source diff-header process parent children)
-
-(defvar-local magit-root-section nil
- "The root section in the current buffer.
-All other sections are descendants of this section. The value
-of this variable is set by `magit-insert-section' and you should
-never modify it.")
-(put 'magit-root-section 'permanent-local t)
-
-(defun magit-current-section ()
- "Return the section at point."
- (or (get-text-property (point) 'magit-section) magit-root-section))
-
-(defun magit-section-ident (section)
- "Return an unique identifier for SECTION.
-The return value has the form ((TYPE . VALUE)...)."
- (cons (cons (magit-section-type section)
- (magit-section-value section))
- (--when-let (magit-section-parent section)
- (magit-section-ident it))))
-
-(defun magit-get-section (ident &optional root)
- "Return the section identified by IDENT.
-IDENT has to be a list as returned by `magit-section-ident'."
- (setq ident (reverse ident))
- (let ((section (or root magit-root-section)))
- (when (eq (car (pop ident)) (magit-section-type section))
- (while (and ident
- (setq section
- (--first
- (and (eq (caar ident) (magit-section-type it))
- (equal (cdar ident) (magit-section-value it)))
- (magit-section-children section))))
- (pop ident))
- section)))
-
-(defvar magit-insert-section--current nil "For internal use only.")
-(defvar magit-insert-section--parent nil "For internal use only.")
-(defvar magit-insert-section--oldroot nil "For internal use only.")
-
-;;; Commands
-;;;; Movement
-
-(defun magit-section-forward ()
- "Move to the beginning of the next visible section."
- (interactive)
- (if (eobp)
- (user-error "No next section")
- (let ((section (magit-current-section)))
- (if (magit-section-parent section)
- (let ((next (and (not (magit-section-hidden section))
- (not (= (magit-section-end section) (1+ (point))))
- (car (magit-section-children section)))))
- (while (and section (not next))
- (unless (setq next (car (magit-section-siblings section 'next)))
- (setq section (magit-section-parent section))))
- (if next
- (magit-section-goto next)
- (user-error "No next section")))
- (magit-section-goto 1)))))
-
-(defun magit-section-backward ()
- "Move to the beginning of the current or the previous visible section.
-When point is at the beginning of a section then move to the
-beginning of the previous visible section. Otherwise move to
-the beginning of the current section."
- (interactive)
- (if (bobp)
- (user-error "No previous section")
- (let ((section (magit-current-section)) children)
- (cond
- ((and (= (point) (1- (magit-section-end section)))
- (setq children (magit-section-children section)))
- (magit-section-goto (car (last children))))
- ((and (magit-section-parent section)
- (not (= (point) (magit-section-start section))))
- (magit-section-goto section))
- (t
- (let ((prev (car (magit-section-siblings section 'prev))))
- (if prev
- (while (and (not (magit-section-hidden prev))
- (setq children (magit-section-children prev)))
- (setq prev (car (last children))))
- (setq prev (magit-section-parent section)))
- (cond (prev
- (magit-section-goto prev))
- ((magit-section-parent section)
- (user-error "No previous section"))
- ;; Eob special cases.
- ((not (get-text-property (1- (point)) 'invisible))
- (magit-section-goto -1))
- (t
- (goto-char (previous-single-property-change
- (1- (point)) 'invisible))
- (forward-line -1)
- (magit-section-goto (magit-current-section))))))))))
-
-(defun magit-section-up ()
- "Move to the beginning of the parent section."
- (interactive)
- (--if-let (magit-section-parent (magit-current-section))
- (magit-section-goto it)
- (user-error "No parent section")))
-
-(defun magit-section-forward-sibling ()
- "Move to the beginning of the next sibling section.
-If there is no next sibling section, then move to the parent."
- (interactive)
- (let ((current (magit-current-section)))
- (if (magit-section-parent current)
- (--if-let (car (magit-section-siblings current 'next))
- (magit-section-goto it)
- (magit-section-forward))
- (magit-section-goto 1))))
-
-(defun magit-section-backward-sibling ()
- "Move to the beginning of the previous sibling section.
-If there is no previous sibling section, then move to the parent."
- (interactive)
- (let ((current (magit-current-section)))
- (if (magit-section-parent current)
- (--if-let (car (magit-section-siblings current 'prev))
- (magit-section-goto it)
- (magit-section-backward))
- (magit-section-goto -1))))
-
-(defun magit-section-goto (arg)
- (if (integerp arg)
- (progn (forward-line arg)
- (setq arg (magit-current-section)))
- (goto-char (magit-section-start arg)))
- (run-hook-with-args 'magit-section-movement-hook arg))
-
-(defun magit-section-set-window-start (section)
- "Ensure the beginning of SECTION is visible."
- (unless (pos-visible-in-window-p (magit-section-end section))
- (set-window-start (selected-window) (magit-section-start section))))
-
-(defun magit-hunk-set-window-start (section)
- "Ensure the beginning of the `hunk' SECTION is visible.
-It the SECTION has a different type, then do nothing."
- (when (eq (magit-section-type section) 'hunk)
- (magit-section-set-window-start section)))
-
-(defmacro magit-define-section-jumper (name heading type &optional value)
- "Define an interactive function to go some section.
-Together TYPE and VALUE identify the section.
-HEADING is the displayed heading of the section."
- (declare (indent defun))
- `(defun ,name (&optional expand) ,(format "\
-Jump to the section \"%s\".
-With a prefix argument also expand it." heading)
- (interactive "P")
- (--if-let (magit-get-section
- (cons (cons ',type ,value)
- (magit-section-ident magit-root-section)))
- (progn (goto-char (magit-section-start it))
- (when expand
- (with-local-quit (magit-section-show it))
- (recenter 0)))
- (message ,(format "Section \"%s\" wasn't found" heading)))))
-
-;;;; Visibility
-
-(defun magit-section-show (section)
- "Show the body of the current section."
- (interactive (list (magit-current-section)))
- (setf (magit-section-hidden section) nil)
- (-when-let (washer (magit-section-washer section))
- (setf (magit-section-washer section) nil)
- (let ((inhibit-read-only t)
- (magit-insert-section--parent section)
- (content (magit-section-content section)))
- (save-excursion
- (if (and content (< content (magit-section-end section)))
- (funcall washer section) ; already partially washed (hunk)
- (goto-char (magit-section-end section))
- (setf (magit-section-content section) (point-marker))
- (funcall washer)
- (setf (magit-section-end section) (point-marker)))))
- (magit-section-update-highlight))
- (-when-let (beg (magit-section-content section))
- (remove-overlays beg (magit-section-end section) 'invisible t))
- (magit-section-update-visibility-cache section)
- (dolist (child (magit-section-children section))
- (if (magit-section-hidden child)
- (magit-section-hide child)
- (magit-section-show child))))
-
-(defun magit-section-hide (section)
- "Hide the body of the current section."
- (interactive (list (magit-current-section)))
- (if (eq section magit-root-section)
- (user-error "Cannot hide root section")
- (setf (magit-section-hidden section) t)
- (-when-let (beg (magit-section-content section))
- (let ((end (magit-section-end section)))
- (remove-overlays beg end 'invisible t)
- (let ((o (make-overlay beg end)))
- (overlay-put o 'evaporate t)
- (overlay-put o 'invisible t))))))
-
-(defun magit-section-toggle (section)
- "Toggle visibility of the body of the current section."
- (interactive (list (magit-current-section)))
- (if (eq section magit-root-section)
- (user-error "Cannot hide root section")
- (goto-char (magit-section-start section))
- (if (magit-section-hidden section)
- (magit-section-show section)
- (magit-section-hide section))))
-
-(defun magit-section-toggle-children (section)
- "Toggle visibility of bodies of children of the current section."
- (interactive (list (magit-current-section)))
- (goto-char (magit-section-start section))
- (let* ((children (magit-section-children section))
- (show (-any? 'magit-section-hidden children)))
- (dolist (c children)
- (setf (magit-section-hidden c) show)))
- (magit-section-show section))
-
-(defun magit-section-show-children (section &optional depth)
- "Recursively show the bodies of children of the current section.
-With a prefix argument show children that deep and hide deeper
-children."
- (interactive (list (magit-current-section)))
- (magit-section-show-children-1 section depth)
- (magit-section-show section))
-
-(defun magit-section-show-children-1 (section &optional depth)
- (dolist (s (magit-section-children section))
- (setf (magit-section-hidden s) nil)
- (if depth
- (if (> depth 0)
- (magit-section-show-children-1 s (1- depth))
- (magit-section-hide s))
- (magit-section-show-children-1 s))))
-
-(defun magit-section-hide-children (section)
- "Recursively hide the bodies of children of the current section."
- (interactive (list (magit-current-section)))
- (mapc 'magit-section-hide (magit-section-children section)))
-
-(defun magit-section-show-headings (section)
- "Recursively show headings of children of the current section.
-Only show the headings, previously shown text-only bodies are
-hidden."
- (interactive (list (magit-current-section)))
- (magit-section-show-headings-1 section)
- (magit-section-show section))
-
-(defun magit-section-show-headings-1 (section)
- (dolist (s (magit-section-children section))
- (setf (magit-section-hidden s) nil)
- (when (or (magit-section-children s)
- (not (magit-section-content s)))
- (magit-section-show-headings-1 s))))
-
-(defun magit-section-cycle (section)
- "Cycle visibility of current section and its children."
- (interactive (list (magit-current-section)))
- (goto-char (magit-section-start section))
- (if (magit-section-hidden section)
- (progn (magit-section-show section)
- (magit-section-hide-children section))
- (let ((children (magit-section-children section)))
- (cond ((and (-any? 'magit-section-hidden children)
- (-any? 'magit-section-children children))
- (magit-section-show-headings section))
- ((-any? 'magit-section-hidden-body children)
- (magit-section-show-children section))
- (t
- (magit-section-hide section))))))
-
-(defun magit-section-cycle-global ()
- "Cycle visibility of all sections in the current buffer."
- (interactive)
- (let ((children (magit-section-children magit-root-section)))
- (cond ((and (-any? 'magit-section-hidden children)
- (-any? 'magit-section-children children))
- (magit-section-show-headings magit-root-section))
- ((-any? 'magit-section-hidden-body children)
- (magit-section-show-children magit-root-section))
- (t
- (mapc 'magit-section-hide children)))))
-
-(defun magit-section-cycle-diffs ()
- "Cycle visibility of diff-related sections in the current buffer."
- (interactive)
- (-when-let (sections
- (cond ((derived-mode-p 'magit-status-mode)
- (--mapcat
- (when it
- (when (magit-section-hidden it)
- (magit-section-show it))
- (magit-section-children it))
- (list (magit-get-section '((staged) (status)))
- (magit-get-section '((unstaged) (status))))))
- ((derived-mode-p 'magit-diff-mode)
- (--filter (eq (magit-section-type it) 'file)
- (magit-section-children magit-root-section)))))
- (if (-any? 'magit-section-hidden sections)
- (dolist (s sections)
- (magit-section-show s)
- (magit-section-hide-children s))
- (let ((children (cl-mapcan 'magit-section-children sections)))
- (cond ((and (-any? 'magit-section-hidden children)
- (-any? 'magit-section-children children))
- (mapc 'magit-section-show-headings sections))
- ((-any? 'magit-section-hidden-body children)
- (mapc 'magit-section-show-children sections))
- (t
- (mapc 'magit-section-hide sections)))))))
-
-(defun magit-section-hidden-body (section &optional pred)
- (--if-let (magit-section-children section)
- (funcall (or pred '-any?) 'magit-section-hidden-body it)
- (and (magit-section-content section)
- (magit-section-hidden section))))
-
-(defun magit-section-invisible-p (section)
- "Return t if the SECTION's body is invisible.
-When the body of an ancestor of SECTION is collapsed then
-SECTION's body (and heading) obviously cannot be visible."
- (or (magit-section-hidden section)
- (--when-let (magit-section-parent section)
- (magit-section-invisible-p it))))
-
-(defun magit-section-show-level (level)
- "Show surrounding sections up to LEVEL.
-If LEVEL is negative show up to the absolute value.
-Sections at higher levels are hidden."
- (if (< level 0)
- (let ((s (magit-current-section)))
- (setq level (- level))
- (while (> (1- (length (magit-section-ident s))) level)
- (setq s (magit-section-parent s))
- (goto-char (magit-section-start s)))
- (magit-section-show-children magit-root-section (1- level)))
- (cl-do* ((s (magit-current-section) (magit-section-parent s))
- (i (1- (length (magit-section-ident s))) (cl-decf i)))
- ((cond ((< i level) (magit-section-show-children s (- level i 1)) t)
- ((= i level) (magit-section-hide s) t))
- (magit-section-goto s)))))
-
-(defun magit-section-show-level-1 ()
- "Show surrounding sections on first level."
- (interactive)
- (magit-section-show-level 1))
-
-(defun magit-section-show-level-1-all ()
- "Show all sections on first level."
- (interactive)
- (magit-section-show-level -1))
-
-(defun magit-section-show-level-2 ()
- "Show surrounding sections up to second level."
- (interactive)
- (magit-section-show-level 2))
-
-(defun magit-section-show-level-2-all ()
- "Show all sections up to second level."
- (interactive)
- (magit-section-show-level -2))
-
-(defun magit-section-show-level-3 ()
- "Show surrounding sections up to third level."
- (interactive)
- (magit-section-show-level 3))
-
-(defun magit-section-show-level-3-all ()
- "Show all sections up to third level."
- (interactive)
- (magit-section-show-level -3))
-
-(defun magit-section-show-level-4 ()
- "Show surrounding sections up to fourth level."
- (interactive)
- (magit-section-show-level 4))
-
-(defun magit-section-show-level-4-all ()
- "Show all sections up to fourth level."
- (interactive)
- (magit-section-show-level -4))
-
-;;;; Auxiliary
-
-(defun magit-describe-section ()
- "Show information about the section at point.
-This command is intended for debugging purposes."
- (interactive)
- (let ((section (magit-current-section)))
- (message "%S %S %s-%s"
- (magit-section-value section)
- (apply 'vector (mapcar 'car (magit-section-ident section)))
- (marker-position (magit-section-start section))
- (marker-position (magit-section-end section)))))
-
-;;; Match
-
-(defun magit-section-match (condition &optional section)
- "Return t if SECTION matches CONDITION.
-SECTION defaults to the section at point.
-
-Conditions can take the following forms:
- (CONDITION...) matches if any of the CONDITIONs matches.
- [TYPE...] matches if the first TYPE matches the type
- of the section at point, the second matches
- that of its parent, and so on.
- [* TYPE...] matches sections that match [TYPE...] and
- also recursively all their child sections.
- TYPE matches TYPE regardless of its parents.
-
-Each TYPE is a symbol. Note that is not necessary to specify all
-TYPEs up to the root section as printed by `magit-describe-type',
-unless of course your want to be that precise."
- ;; When recursing SECTION actually is a type list. Matching
- ;; macros also pass such a list instead of a section struct.
- (let ((types (if (magit-section-p section)
- (mapcar 'car (magit-section-ident section))
- section)))
- (when (or types section (magit-current-section))
- (if (listp condition)
- (--first (magit-section-match it types) condition)
- (magit-section-match-1 (if (symbolp condition)
- (list condition)
- (append condition nil))
- types)))))
-
-(defun magit-section-match-1 (l1 l2)
- (or (null l1)
- (if (eq (car l1) '*)
- (or (magit-section-match-1 (cdr l1) l2)
- (and l2
- (magit-section-match-1 l1 (cdr l2))))
- (and l2
- (equal (car l1) (car l2))
- (magit-section-match-1 (cdr l1) (cdr l2))))))
-
-(defmacro magit-section-when (condition &rest body)
- "If the section at point matches CONDITION evaluate BODY.
-
-If the section matches evaluate BODY forms sequentially and
-return the value of the last one, or if there are no BODY forms
-return the value of the section. If the section does not match
-return nil.
-
-See `magit-section-match' for the forms CONDITION can take."
- (declare (indent 1)
- (debug (sexp body)))
- `(--when-let (magit-current-section)
- (when (magit-section-match ',condition
- (mapcar 'car (magit-section-ident it)))
- ,@(or body '((magit-section-value it))))))
-
-(defmacro magit-section-case (&rest clauses)
- "Choose among clauses on the type of the section at point.
-
-Each clause looks like (CONDITION BODY...). The type of the
-section is compared against each CONDITION; the BODY forms of the
-first match are evaluated sequentially and the value of the last
-form is returned. Inside BODY the symbol `it' is bound to the
-section at point. If no clause succeeds or if there is no
-section at point return nil.
-
-See `magit-section-match' for the forms CONDITION can take.
-Additionally a CONDITION of t is allowed in the final clause, and
-matches if no other CONDITION match, even if there is no section
-at point."
- (declare (indent 0)
- (debug (&rest (sexp body))))
- (let ((ident (cl-gensym "id")))
- `(let* ((it (magit-current-section))
- (,ident (and it (mapcar 'car (magit-section-ident it)))))
- (cond ,@(mapcar (lambda (clause)
- `(,(or (eq (car clause) t)
- `(and it (magit-section-match
- ',(car clause) ,ident)))
- ,@(cdr clause)))
- clauses)))))
-;;; Create
-
-(defvar magit-insert-section-hook nil
- "Hook run after `magit-insert-section's BODY.
-Avoid using this hook and only ever do so if you know
-what you are doing and are sure there is no other way.")
-
-(defmacro magit-insert-section (&rest args)
- "Insert a section at point.
-
-TYPE is the section type, a symbol. Many commands that act on
-the current section behave differently depending on that type.
-Also if a variable `magit-TYPE-section-map' exists, then use
-that as the text-property `keymap' of all text belonging to the
-section (but this may be overwritten in subsections).
-
-Optional VALUE is the value of the section, usually a string
-that is required when acting on the section.
-
-When optional HIDE is non-nil collapse the section body by
-default, i.e. when first creating the section, but not when
-refreshing the buffer. Else expand it by default. This can be
-overwritten using `magit-section-set-visibility-hook'. When a
-section is recreated during a refresh, then the visibility of
-predecessor is inherited and HIDE is ignored (but the hook is
-still honored).
-
-BODY is any number of forms that actually insert the section's
-heading and body. Optional NAME, if specified, has to be a
-symbol, which is then bound to the struct of the section being
-inserted.
-
-Before BODY is evaluated the `start' of the section object is set
-to the value of `point' and after BODY was evaluated its `end' is
-set to the new value of `point'; BODY is responsible for moving
-`point' forward.
-
-If it turns out inside BODY that the section is empty, then
-`magit-cancel-section' can be used to abort and remove all traces
-of the partially inserted section. This can happen when creating
-a section by washing Git's output and Git didn't actually output
-anything this time around.
-
-\(fn [NAME] (TYPE &optional VALUE HIDE) &rest BODY)"
- (declare (indent defun)
- (debug ([&optional symbolp] (symbolp &optional form form) body)))
- (let ((s (if (symbolp (car args))
- (pop args)
- (cl-gensym "section"))))
- `(let* ((,s (make-magit-section
- :type ',(nth 0 (car args))
- :value ,(nth 1 (car args))
- :start (point-marker)
- :parent magit-insert-section--parent)))
- (setf (magit-section-hidden ,s)
- (-if-let (value (run-hook-with-args-until-success
- 'magit-section-set-visibility-hook ,s))
- (eq value 'hide)
- (--if-let (and magit-insert-section--oldroot
- (magit-get-section
- (magit-section-ident ,s)
- magit-insert-section--oldroot))
- (magit-section-hidden it)
- ,(nth 2 (car args)))))
- (let ((magit-insert-section--current ,s)
- (magit-insert-section--parent ,s)
- (magit-insert-section--oldroot
- (or magit-insert-section--oldroot
- (unless magit-insert-section--parent
- (prog1 magit-root-section
- (setq magit-root-section ,s))))))
- (catch 'cancel-section
- ,@(cdr args)
- (run-hooks 'magit-insert-section-hook)
- (magit-insert-child-count ,s)
- (set-marker-insertion-type (magit-section-start ,s) t)
- (let* ((end (setf (magit-section-end ,s) (point-marker)))
- (map (intern (format "magit-%s-section-map"
- (magit-section-type ,s))))
- (map (and (boundp map) (symbol-value map))))
- (save-excursion
- (goto-char (magit-section-start ,s))
- (while (< (point) end)
- (let ((next (or (next-single-property-change
- (point) 'magit-section)
- end)))
- (unless (get-text-property (point) 'magit-section)
- (put-text-property (point) next 'magit-section ,s)
- (when map
- (put-text-property (point) next 'keymap map)))
- (goto-char next)))))
- (if (eq ,s magit-root-section)
- (magit-section-show ,s)
- (setf (magit-section-children (magit-section-parent ,s))
- (nconc (magit-section-children (magit-section-parent ,s))
- (list ,s)))))
- ,s))))
-
-(defun magit-cancel-section ()
- (when magit-insert-section--current
- (if (not (magit-section-parent magit-insert-section--current))
- (insert "(empty)\n")
- (delete-region (magit-section-start magit-insert-section--current)
- (point))
- (setq magit-insert-section--current nil)
- (throw 'cancel-section nil))))
-
-(defun magit-insert-heading (&rest args)
- "Insert the heading for the section currently being inserted.
-
-This function should only be used inside `magit-insert-section'.
-
-When called without any arguments, then just set the `content'
-slot of the object representing the section being inserted to
-a marker at `point'. The section should only contain a single
-line when this function is used like this.
-
-When called with arguments ARGS, which have to be strings, then
-insert those strings at point. The section should not contain
-any text before this happens and afterwards it should again only
-contain a single line. If the `face' property is set anywhere
-inside any of these strings, then insert all of them unchanged.
-Otherwise use the `magit-section-heading' face for all inserted
-text.
-
-The `content' property of the section struct is the end of the
-heading (which lasts from `start' to `content') and the beginning
-of the the body (which lasts from `content' to `end'). If the
-value of `content' is nil, then the section has no heading and
-its body cannot be collapsed. If a section does have a heading
-then its height must be exactly one line, including a trailing
-newline character. This isn't enforced, you are responsible for
-getting it right. The only exception is that this function does
-insert a newline character if necessary."
- (declare (indent defun))
- (when args
- (let ((heading (apply #'concat args)))
- (insert (if (next-single-property-change 0 'face (concat "0" heading))
- heading
- (propertize heading 'face 'magit-section-heading)))))
- (unless (bolp)
- (insert ?\n))
- (setf (magit-section-content magit-insert-section--current) (point-marker)))
-
-(defvar magit-insert-headers-hook nil "For internal use only.")
-
-(defun magit-insert-headers (hooks)
- (let ((magit-insert-section-hook
- (cons 'magit-insert-remaining-headers
- (if (listp magit-insert-section-hook)
- magit-insert-section-hook
- (list magit-insert-section-hook))))
- (magit-insert-headers-hook hooks)
- wrapper)
- (while (and (setq wrapper (pop magit-insert-headers-hook))
- (= (point) (point-min)))
- (funcall wrapper))))
-
-(defun magit-insert-remaining-headers ()
- (if (= (point) (point-min))
- (magit-cancel-section)
- (magit-insert-heading)
- (remove-hook 'magit-insert-section-hook 'magit-insert-remaining-headers)
- (mapc #'funcall magit-insert-headers-hook)
- (insert "\n")))
-
-(defun magit-insert-child-count (section)
- "Modify SECTION's heading to contain number of child sections.
-
-If `magit-section-show-child-count' is non-nil and the SECTION
-has children and its heading ends with \":\", then replace that
-with \" (N)\", where N is the number of child sections.
-
-This function is called by `magit-insert-section' after that has
-evaluated its BODY. Admittedly that's a bit of a hack."
- ;; This has to be fast, not pretty!
- (let (content count)
- (when (and magit-section-show-child-count
- (setq count (length (magit-section-children section)))
- (> count 0)
- (setq content (magit-section-content section))
- (eq (char-before (1- content)) ?:))
- (save-excursion
- (goto-char (- content 2))
- (insert (format " (%s)" count))
- (delete-char 1)))))
-
-;;; Update
-
-(defvar-local magit-section-highlight-overlays nil)
-(defvar-local magit-section-highlighted-section nil)
-(defvar-local magit-section-highlighted-sections nil)
-(defvar-local magit-section-unhighlight-sections nil)
-
-(defun magit-section-update-region (_)
- ;; Don't show complete region. Highlighting emphasizes headings.
- (magit-region-sections))
-
-(defun magit-section-update-highlight ()
- (let ((section (magit-current-section)))
- (unless (eq section magit-section-highlighted-section)
- (let ((inhibit-read-only t)
- (deactivate-mark nil)
- (selection (magit-region-sections)))
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (setq magit-section-unhighlight-sections
- magit-section-highlighted-sections
- magit-section-highlighted-sections nil)
- (unless (eq section magit-root-section)
- (run-hook-with-args-until-success
- 'magit-section-highlight-hook section selection))
- (--each magit-section-unhighlight-sections
- (run-hook-with-args-until-success
- 'magit-section-unhighlight-hook it selection))
- (restore-buffer-modified-p nil)
- (unless (eq magit-section-highlighted-section section)
- (setq magit-section-highlighted-section
- (unless (magit-section-hidden section) section))))
- (setq deactivate-mark nil))))
-
-(defun magit-section-highlight (section selection)
- "Highlight SECTION and if non-nil all SELECTION.
-This function works for any section but produces undesirable
-effects for diff related sections, which by default are
-highlighted using `magit-diff-highlight'. Return t."
- (cond (selection
- (magit-section-make-overlay (magit-section-start (car selection))
- (magit-section-end (car (last selection)))
- 'magit-section-highlight)
- (magit-section-highlight-selection nil selection))
- (t
- (magit-section-make-overlay (magit-section-start section)
- (magit-section-end section)
- 'magit-section-highlight)))
- t)
-
-(defun magit-section-highlight-selection (_ selection)
- "Highlight the section selection region.
-If SELECTION is non-nil then it is a list of sections selected by
-the region. The headings of these sections are then highlighted.
-
-This is a fallback for people who don't want to highlight the
-current section and therefore removed `magit-section-highlight'
-from `magit-section-highlight-hook'.
-
-This function is necessary to ensure that a representation of
-such a region is visible. If neither of these functions were
-part of the hook variable, then such a region would be
-invisible."
- (when selection
- (--each selection
- (magit-section-make-overlay (magit-section-start it)
- (or (magit-section-content it)
- (magit-section-end it))
- 'magit-section-heading-selection))
- t))
-
-(defun magit-section-make-overlay (start end face)
- ;; Yes, this doesn't belong here. But the alternative of
- ;; spreading this hack across the code base is even worse.
- (when (and magit-keep-region-overlay
- (memq face '(magit-section-heading-selection
- magit-diff-file-heading-selection
- magit-diff-hunk-heading-selection)))
- (setq face (list :foreground (face-foreground face))))
- (let ((ov (make-overlay start end nil t)))
- (overlay-put ov 'face face)
- (overlay-put ov 'evaporate t)
- (push ov magit-section-highlight-overlays)
- ov))
-
-(defun magit-section-goto-successor (section line char arg)
- (let ((ident (magit-section-ident section)))
- (--if-let (magit-get-section ident)
- (let ((start (magit-section-start it)))
- (goto-char start)
- (unless (eq it magit-root-section)
- (ignore-errors
- (forward-line line)
- (forward-char char))
- (unless (eq (magit-current-section) it)
- (goto-char start))))
- (or (and (eq (magit-section-type section) 'hunk)
- (-when-let (parent (magit-get-section
- (magit-section-ident
- (magit-section-parent section))))
- (let* ((children (magit-section-children parent))
- (siblings (magit-section-siblings section 'prev))
- (previous (nth (length siblings) children)))
- (if (not arg)
- (--when-let (or previous (car (last children)))
- (goto-char (magit-section-start it)))
- (when previous
- (goto-char (magit-section-start previous)))
- (if (and (stringp arg)
- (re-search-forward
- arg (magit-section-end parent) t))
- (goto-char (match-beginning 0))
- (goto-char (magit-section-end (car (last children))))
- (forward-line -1)
- (while (looking-at "^ ") (forward-line -1))
- (while (looking-at "^[-+]") (forward-line -1))
- (forward-line))))))
- (goto-char (--if-let (magit-section-goto-successor-1 section)
- (if (eq (magit-section-type it) 'button)
- (point-min)
- (magit-section-start it))
- (point-min)))))))
-
-(defun magit-section-goto-successor-1 (section)
- (or (--when-let (pcase (magit-section-type section)
- (`staged 'unstaged)
- (`unstaged 'staged)
- (`unpushed 'unpulled)
- (`unpulled 'unpushed))
- (magit-get-section `((,it) (status))))
- (--when-let (car (magit-section-siblings section 'next))
- (magit-get-section (magit-section-ident it)))
- (--when-let (car (magit-section-siblings section 'prev))
- (magit-get-section (magit-section-ident it)))
- (--when-let (magit-section-parent section)
- (or (magit-get-section (magit-section-ident it))
- (magit-section-goto-successor-1 it)))))
-
-;;; Visibility
-
-(defvar-local magit-section-visibility-cache nil)
-(put 'magit-section-visibility-cache 'permanent-local t)
-
-(defun magit-section-set-visibility-from-cache (section)
- "Set SECTION's visibility to the cached value.
-Currently the cache can only be used to remember that a section's
-body should be collapsed, not that it should be expanded. Return
-either `hide' or nil."
- (and (member (magit-section-visibility-ident section)
- magit-section-visibility-cache)
- 'hide))
-
-(cl-defun magit-section-cache-visibility
- (&optional (section magit-insert-section--current))
- (let ((ident (magit-section-visibility-ident section)))
- (if (magit-section-hidden section)
- (cl-pushnew ident magit-section-visibility-cache :test #'equal)
- (setq magit-section-visibility-cache
- (delete ident magit-section-visibility-cache)))))
-
-(defun magit-section-update-visibility-cache (section)
- (setq magit-section-visibility-cache
- (delete (magit-section-visibility-ident section)
- magit-section-visibility-cache)))
-
-(defun magit-section-visibility-ident (section)
- (let ((type (magit-section-type section))
- (value (magit-section-value section)))
- (cons type
- (cond ((not (memq type '(unpulled unpushed))) value)
- ((string-match-p "@{upstream}" value) value)
- ;; Unfortunately Git chokes on "@{push}" when the
- ;; value of `push.default' does not allow a 1:1
- ;; mapping. But collapsed logs of unpushed and
- ;; unpulled commits in the status buffer should
- ;; remain invisible after changing branches.
- ;; So we have to pretend the value is constant.
- ((string-match-p "\\`\\.\\." value) "..@{push}")
- (t "@{push}..")))))
-
-;;; Utilities
-
-(cl-defun magit-section-selected-p (section &optional (selection nil sselection))
- (and (not (eq section magit-root-section))
- (or (eq section (magit-current-section))
- (memq section (if sselection
- selection
- (setq selection (magit-region-sections))))
- (--when-let (magit-section-parent section)
- (magit-section-selected-p it selection)))))
-
-(defun magit-section-parent-value (section)
- (setq section (magit-section-parent section))
- (when section (magit-section-value section)))
-
-(defun magit-section-siblings (section &optional direction)
- "Return a list of the sibling sections of SECTION.
-
-If optional DIRECTION is `prev' then return siblings that come
-before SECTION, if it is `next' then return siblings that come
-after SECTION. For all other values return all siblings
-excluding SECTION itself."
- (-when-let (parent (magit-section-parent section))
- (let ((siblings (magit-section-children parent)))
- (pcase direction
- (`prev (cdr (member section (reverse siblings))))
- (`next (cdr (member section siblings)))
- (_ (remq section siblings))))))
-
-(defun magit-region-values (&rest types)
- "Return a list of the values of the selected sections.
-
-Also see `magit-region-sections' whose doc-string explains when a
-region is a valid section selection. If the region is not active
-or is not a valid section selection, then return nil. If optional
-TYPES is non-nil then the selection not only has to be valid; the
-types of all selected sections additionally have to match one of
-TYPES, or nil is returned."
- (mapcar 'magit-section-value (apply 'magit-region-sections types)))
-
-(defun magit-region-sections (&rest types)
- "Return a list of the selected sections.
-
-When the region is active and constitutes a valid section
-selection, then return a list of all selected sections. This is
-the case when the region begins in the heading of a section and
-ends in the heading of a sibling of that first section. When
-the selection is not valid then return nil. Most commands that
-can act on the selected sections, then instead just act on the
-current section, the one point is in.
-
-When the region looks like it would in any other buffer then
-the selection is invalid. When the selection is valid then the
-region uses the `magit-section-highlight'. This does not apply
-to diffs were things get a bit more complicated, but even here
-if the region looks like it usually does, then that's not a
-valid selection as far as this function is concerned.
-
-If optional TYPES is non-nil then the selection not only has to
-be valid; the types of all selected sections additionally have to
-match one of TYPES, or nil is returned."
- (when (use-region-p)
- (let* ((rbeg (region-beginning))
- (rend (region-end))
- (sbeg (get-text-property rbeg 'magit-section))
- (send (get-text-property rend 'magit-section)))
- (unless (memq send (list sbeg magit-root-section nil))
- (let ((siblings (magit-section-siblings sbeg 'next)) sections)
- (when (and (memq send siblings)
- (magit-section-position-in-heading-p sbeg rbeg)
- (magit-section-position-in-heading-p send rend))
- (while siblings
- (push (car siblings) sections)
- (when (eq (pop siblings) send)
- (setq siblings nil)))
- (setq sections (cons sbeg (nreverse sections)))
- (when (or (not types)
- (--all-p (memq (magit-section-type it) types) sections))
- sections)))))))
-
-(defun magit-section-position-in-heading-p (section pos)
- "Return t if POSITION is inside the heading of SECTION."
- (and (>= pos (magit-section-start section))
- (< pos (or (magit-section-content section)
- (magit-section-end section)))
- t))
-
-(defun magit-section-internal-region-p (&optional section)
- "Return t if the region is active and inside SECTION's body.
-If optional SECTION is nil, use the current section."
- (and (region-active-p)
- (or section (setq section (magit-current-section)))
- (let ((beg (get-text-property (region-beginning) 'magit-section)))
- (and (eq beg (get-text-property (region-end) 'magit-section))
- (eq beg section)))
- (not (or (magit-section-position-in-heading-p section (region-beginning))
- (magit-section-position-in-heading-p section (region-end))))
- t))
-
-(defun magit-wash-sequence (function)
- "Repeatedly call FUNCTION until it returns nil or eob is reached.
-FUNCTION has to move point forward or return nil."
- (while (and (not (eobp)) (funcall function))))
-
-(defun magit-add-section-hook (hook function &optional at append local)
- "Add to the value of section hook HOOK the function FUNCTION.
-
-Add FUNCTION at the beginning of the hook list unless optional
-APPEND is non-nil, in which case FUNCTION is added at the end.
-If FUNCTION already is a member then move it to the new location.
-
-If optional AT is non-nil and a member of the hook list, then
-add FUNCTION next to that instead. Add before or after AT, or
-replace AT with FUNCTION depending on APPEND. If APPEND is the
-symbol `replace', then replace AT with FUNCTION. For any other
-non-nil value place FUNCTION right after AT. If nil, then place
-FUNCTION right before AT. If FUNCTION already is a member of the
-list but AT is not, then leave FUNCTION where ever it already is.
-
-If optional LOCAL is non-nil, then modify the hook's buffer-local
-value rather than its global value. This makes the hook local by
-copying the default value. That copy is then modified.
-
-HOOK should be a symbol. If HOOK is void, it is first set to nil.
-HOOK's value must not be a single hook function. FUNCTION should
-be a function that takes no arguments and inserts one or multiple
-sections at point, moving point forward. FUNCTION may choose not
-to insert its section(s), when doing so would not make sense. It
-should not be abused for other side-effects. To remove FUNCTION
-again use `remove-hook'."
- (unless (boundp hook)
- (error "Cannot add function to undefined hook variable %s" hook))
- (or (default-boundp hook) (set-default hook nil))
- (let ((value (if local
- (if (local-variable-p hook)
- (symbol-value hook)
- (unless (local-variable-if-set-p hook)
- (make-local-variable hook))
- (copy-sequence (default-value hook)))
- (default-value hook))))
- (if at
- (when (setq at (member at value))
- (setq value (delq function value))
- (cond ((eq append 'replace)
- (setcar at function))
- (append
- (push function (cdr at)))
- (t
- (push (car at) (cdr at))
- (setcar at function))))
- (setq value (delq function value)))
- (unless (member function value)
- (setq value (if append
- (append value (list function))
- (cons function value))))
- (when (eq append 'replace)
- (setq value (delq at value)))
- (if local
- (set hook value)
- (set-default hook value))))
-
-;;; magit-section.el ends soon
-(provide 'magit-section)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-section.el ends here
+++ /dev/null
-;;; magit-sequence.el --- history manipulation in Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Support for Git commands that replay commits and help the user make
-;; changes along the way. Supports `cherry-pick', `revert', `rebase',
-;; `rebase--interactive' and `am'.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-;;;; Faces
-
-(defface magit-sequence-pick
- '((t :inherit default))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-stop
- '((((class color) (background light)) :foreground "DarkOliveGreen4")
- (((class color) (background dark)) :foreground "DarkSeaGreen2"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-part
- '((((class color) (background light)) :foreground "Goldenrod4")
- (((class color) (background dark)) :foreground "LightGoldenrod2"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-head
- '((((class color) (background light)) :foreground "SkyBlue4")
- (((class color) (background dark)) :foreground "LightSkyBlue1"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-drop
- '((((class color) (background light)) :foreground "IndianRed")
- (((class color) (background dark)) :foreground "IndianRed"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-done
- '((t :inherit magit-hash))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-onto
- '((t :inherit magit-sequence-done))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-;;; Common
-
-;;;###autoload
-(defun magit-sequencer-continue ()
- "Resume the current cherry-pick or revert sequence."
- (interactive)
- (if (magit-sequencer-in-progress-p)
- (if (magit-anything-unstaged-p t)
- (user-error "Cannot continue due to unstaged changes")
- (magit-run-git-sequencer
- (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue"))
- (user-error "No cherry-pick or revert in progress")))
-
-;;;###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")))
-
-;;;###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")))
-
-(defun magit-sequencer-in-progress-p ()
- (or (magit-cherry-pick-in-progress-p)
- (magit-revert-in-progress-p)))
-
-;;; Cherry-Pick
-
-;;;###autoload (autoload 'magit-cherry-pick-popup "magit-sequence" nil t)
-(magit-define-popup magit-cherry-pick-popup
- "Popup console for cherry-pick commands."
- 'magit-commands
- :man-page "git-cherry-pick"
- :switches '((?s "Add Signed-off-by lines" "--signoff")
- (?e "Edit commit messages" "--edit")
- (?x "Reference cherry in commit message" "-x")
- (?F "Attempt fast-forward" "--ff")
- (?m "Reply merge relative to parent" "--mainline="))
- :options '((?s "Strategy" "--strategy="))
- :actions '((?A "Cherry Pick" magit-cherry-pick)
- (?a "Cherry Apply" magit-cherry-apply))
- :sequence-actions '((?A "Continue" magit-sequencer-continue)
- (?s "Skip" magit-sequencer-skip)
- (?a "Abort" magit-sequencer-abort))
- :sequence-predicate 'magit-sequencer-in-progress-p
- :default-arguments '("--ff"))
-
-(defun magit-cherry-pick-read-args (prompt)
- (list (or (nreverse (magit-region-values 'commit))
- (magit-read-other-branch-or-commit prompt))
- (magit-cherry-pick-arguments)))
-
-;;;###autoload
-(defun magit-cherry-pick (commit &optional args)
- "Cherry-pick COMMIT.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then pick all of them,
-without prompting."
- (interactive (magit-cherry-pick-read-args "Cherry-pick"))
- (magit-assert-one-parent (car (if (listp commit)
- commit
- (split-string commit "\\.\\.")))
- "cherry-pick")
- (magit-run-git-sequencer "cherry-pick" args commit))
-
-;;;###autoload
-(defun magit-cherry-apply (commit &optional args)
- "Apply the changes in COMMIT but do not commit them.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then apply all of them,
-without prompting."
- (interactive (magit-cherry-pick-read-args "Apply changes from commit"))
- (magit-assert-one-parent commit "cherry-pick")
- (magit-run-git-sequencer "cherry-pick" "--no-commit"
- (remove "--ff" args) commit))
-
-(defun magit-cherry-pick-in-progress-p ()
- ;; .git/sequencer/todo does not exist when there is only one commit left.
- (file-exists-p (magit-git-dir "CHERRY_PICK_HEAD")))
-
-;;; Revert
-
-;;;###autoload (autoload 'magit-revert-popup "magit-sequence" nil t)
-(magit-define-popup magit-revert-popup
- "Popup console for revert commands."
- 'magit-commands
- :man-page "git-revert"
- :switches '((?s "Add Signed-off-by lines" "--signoff"))
- :options '((?s "Strategy" "--strategy="))
- :actions '((?V "Revert commit(s)" magit-revert)
- (?v "Revert changes" magit-revert-no-commit))
- :sequence-actions '((?V "Continue" magit-sequencer-continue)
- (?s "Skip" magit-sequencer-skip)
- (?a "Abort" magit-sequencer-abort))
- :sequence-predicate 'magit-sequencer-in-progress-p)
-
-(defun magit-revert-read-args (prompt)
- (list (or (magit-region-values 'commit)
- (magit-read-branch-or-commit prompt))
- (magit-revert-arguments)))
-
-;;;###autoload
-(defun magit-revert (commit &optional args)
- "Revert COMMIT by creating a new commit.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting."
- (interactive (magit-revert-read-args "Revert commit"))
- (magit-assert-one-parent commit "revert")
- (magit-run-git-sequencer "revert" args commit))
-
-;;;###autoload
-(defun magit-revert-no-commit (commit &optional args)
- "Revert COMMIT by applying it in reverse to the worktree.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting."
- (interactive (magit-revert-read-args "Revert changes"))
- (magit-assert-one-parent commit "revert")
- (magit-run-git-sequencer "revert" "--no-commit" args commit))
-
-(defun magit-revert-in-progress-p ()
- ;; .git/sequencer/todo does not exist when there is only one commit left.
- (file-exists-p (magit-git-dir "REVERT_HEAD")))
-
-;;; Patch
-
-;;;###autoload (autoload 'magit-am-popup "magit-sequence" nil t)
-(magit-define-popup magit-am-popup
- "Popup console for mailbox commands."
- 'magit-commands
- :man-page "git-am"
- :switches '((?3 "Fall back on 3way merge" "--3way")
- (?s "Add Signed-off-by lines" "--signoff")
- (?c "Remove text before scissors line" "--scissors")
- (?k "Inhibit removal of email cruft" "--keep")
- (?b "Limit removal of email cruft" "--keep-non-patch")
- (?d "Use author date as committer date"
- "--committer-date-is-author-date")
- (?D "Use committer date as author date" "--ignore-date"))
- :options '((?p "Remove leading slashes from paths" "-p"
- magit-popup-read-number))
- :actions '((?w "Apply patches" magit-am-apply-patches)
- (?m "Apply maildir" magit-am-apply-maildir))
- :default-arguments '("--3way")
- :default-actions 'magit-am-apply-patches
- :sequence-actions '((?w "Continue" magit-am-continue)
- (?s "Skip" magit-am-skip)
- (?a "Abort" magit-am-abort))
- :sequence-predicate 'magit-am-in-progress-p)
-
-;;;###autoload
-(defun magit-am-apply-patches (&optional files args)
- "Apply the patches FILES."
- (interactive (list (or (magit-region-values 'file)
- (list (let ((default (magit-file-at-point)))
- (read-file-name
- (if default
- (format "Apply patch (%s): " default)
- "Apply patch: ")
- nil default))))
- (magit-am-arguments)))
- (magit-run-git-sequencer "am" args "--" (mapcar 'expand-file-name files)))
-
-;;;###autoload
-(defun magit-am-apply-maildir (&optional maildir args)
- "Apply the patches from MAILDIR."
- (interactive (list (read-file-name "Apply mbox or Maildir: ")
- (magit-am-arguments)))
- (magit-run-git-sequencer "am" args (expand-file-name maildir)))
-
-;;;###autoload
-(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")))
-
-;;;###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")))
-
-;;;###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")))
-
-(defun magit-am-in-progress-p ()
- (file-exists-p (magit-git-dir "rebase-apply/applying")))
-
-;;; Rebase
-
-;;;###autoload (autoload 'magit-rebase-popup "magit-sequence" nil t)
-(magit-define-popup magit-rebase-popup
- "Key menu for rebasing."
- 'magit-commands
- :man-page "git-rebase"
- :switches '((?k "Keep empty commits" "--keep-empty")
- (?p "Preserve merges" "--preserve-merges")
- (?c "Lie about author date" "--committer-date-is-author-date")
- (?a "Autosquash" "--autosquash")
- (?A "Autostash" "--autostash")
- (?i "Interactive" "--interactive"))
- :actions '((lambda ()
- (concat (propertize "Rebase " 'face 'magit-popup-heading)
- (propertize (or (magit-get-current-branch) "HEAD")
- 'face 'magit-branch-local)
- (propertize " onto" 'face 'magit-popup-heading)))
- (?p (lambda ()
- (--when-let (magit-get-push-branch) (concat it "\n")))
- magit-rebase-onto-pushremote)
- (?u (lambda ()
- (--when-let (magit-get-upstream-branch) (concat it "\n")))
- magit-rebase-onto-upstream)
- (?e "elsewhere" magit-rebase)
- "Rebase"
- (?i "interactively" magit-rebase-interactive)
- (?m "to edit a commit" magit-rebase-edit-commit)
- (?s "subset" magit-rebase-subset)
- (?w "to reword a commit" magit-rebase-reword-commit) nil
- (?f "to autosquash" magit-rebase-autosquash))
- :sequence-actions '((?r "Continue" magit-rebase-continue)
- (?s "Skip" magit-rebase-skip)
- (?e "Edit" magit-rebase-edit)
- (?a "Abort" magit-rebase-abort))
- :sequence-predicate 'magit-rebase-in-progress-p
- :max-action-columns 2)
-
-(defun magit-git-rebase (target args)
- (magit-run-git-sequencer "rebase" target args))
-
-;;;###autoload
-(defun magit-rebase-onto-pushremote (args)
- "Rebase the current branch onto `branch.<name>.pushRemote'.
-If that variable is unset, then rebase onto `remote.pushDefault'."
- (interactive (list (magit-rebase-arguments)))
- (--if-let (magit-get-current-branch)
- (-if-let (remote (magit-get-push-remote it))
- (if (member remote (magit-list-remotes))
- (magit-git-rebase (concat remote "/" it) args)
- (user-error "Remote `%s' doesn't exist" remote))
- (user-error "No push-remote is configured for %s" it))
- (user-error "No branch is checked out")))
-
-;;;###autoload
-(defun magit-rebase-onto-upstream (args)
- "Rebase the current branch onto its upstream branch."
- (interactive (list (magit-rebase-arguments)))
- (--if-let (magit-get-current-branch)
- (-if-let (target (magit-get-upstream-branch it))
- (magit-git-rebase target args)
- (user-error "No upstream is configured for %s" it))
- (user-error "No branch is checked out")))
-
-;;;###autoload
-(defun magit-rebase (target args)
- "Rebase the current branch onto a branch read in the minibuffer.
-All commits that are reachable from head but not from the
-selected branch TARGET are being rebased."
- (interactive (list (magit-read-other-branch-or-commit "Rebase onto")
- (magit-rebase-arguments)))
- (message "Rebasing...")
- (magit-git-rebase target args)
- (message "Rebasing...done"))
-
-;;;###autoload
-(defun magit-rebase-subset (newbase start args)
- "Rebase a subset of the current branches history onto a new base.
-Rebase commits from START to `HEAD' onto NEWBASE.
-START has to be selected from a list of recent commits."
- (interactive (list (magit-read-other-branch-or-commit
- "Rebase subset onto" nil
- (magit-get-upstream-branch))
- nil
- (magit-rebase-arguments)))
- (if start
- (progn (message "Rebasing...")
- (magit-run-git-sequencer "rebase" "--onto" newbase start args)
- (message "Rebasing...done"))
- (magit-log-select
- `(lambda (commit)
- (magit-rebase-subset ,newbase (concat commit "^") (list ,@args)))
- (concat "Type %p on a commit to rebase it "
- "and commits above it onto " newbase ","))))
-
-(defun magit-rebase-interactive-1 (commit args message &optional editor)
- (declare (indent 2))
- (when commit
- (if (eq commit :merge-base)
- (setq commit (--if-let (magit-get-upstream-branch)
- (magit-git-string "merge-base" it "HEAD")
- nil))
- (when (magit-git-failure "merge-base" "--is-ancestor" commit "HEAD")
- (user-error "%s isn't an ancestor of HEAD" commit))
- (if (magit-commit-parents commit)
- (setq commit (concat commit "^"))
- (setq args (cons "--root" args)))))
- (when (and commit
- (magit-git-lines "rev-list" "--merges" (concat commit "..HEAD")))
- (magit-read-char-case "Proceed despite merge in rebase range? " nil
- (?c "[c]ontinue")
- (?s "[s]elect other" (setq commit nil))
- (?a "[a]bort" (user-error "Quit"))))
- (if commit
- (let ((process-environment process-environment))
- (when editor
- (setenv "GIT_SEQUENCE_EDITOR" editor))
- (magit-run-git-sequencer "rebase" "-i" args
- (unless (member "--root" args) commit)))
- (magit-log-select
- `(lambda (commit)
- (magit-rebase-interactive-1 commit (list ,@args) ,message ,editor))
- message)))
-
-;;;###autoload
-(defun magit-rebase-interactive (commit args)
- "Start an interactive rebase sequence."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to rebase it and all commits above it,"))
-
-;;;###autoload
-(defun magit-rebase-autosquash (args)
- "Combine squash and fixup commits with their intended targets."
- (interactive (list (magit-rebase-arguments)))
- (magit-rebase-interactive-1 :merge-base (cons "--autosquash" args)
- "Type %p on a commit to squash into it and then rebase as necessary,"
- "true"))
-
-;;;###autoload
-(defun magit-rebase-edit-commit (commit args)
- "Edit a single older commit using rebase."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to edit it,"
- "perl -i -p -e '++$x if not $x and s/^pick/edit/'"))
-
-;;;###autoload
-(defun magit-rebase-reword-commit (commit args)
- "Reword a single older commit using rebase."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to reword its message,"
- "perl -i -p -e '++$x if not $x and s/^pick/reword/'"))
-
-;;;###autoload
-(defun magit-rebase-continue ()
- "Restart the current rebasing operation."
- (interactive)
- (if (magit-rebase-in-progress-p)
- (if (magit-anything-unstaged-p t)
- (user-error "Cannot continue rebase with unstaged changes")
- (magit-run-git-sequencer "rebase" "--continue"))
- (user-error "No rebase in progress")))
-
-;;;###autoload
-(defun magit-rebase-skip ()
- "Skip the current commit and restart the current rebase operation."
- (interactive)
- (if (magit-rebase-in-progress-p)
- (magit-run-git-sequencer "rebase" "--skip")
- (user-error "No rebase in progress")))
-
-;;;###autoload
-(defun magit-rebase-edit ()
- "Edit the todo list of the current rebase operation."
- (interactive)
- (if (magit-rebase-in-progress-p)
- (magit-run-git-sequencer "rebase" "--edit-todo")
- (user-error "No rebase in progress")))
-
-;;;###autoload
-(defun magit-rebase-abort ()
- "Abort the current rebase operation, restoring the original branch."
- (interactive)
- (if (magit-rebase-in-progress-p)
- (magit-run-git "rebase" "--abort")
- (user-error "No rebase in progress")))
-
-(defun magit-rebase-in-progress-p ()
- "Return t if a rebase is in progress."
- (or (file-exists-p (magit-git-dir "rebase-merge"))
- (file-exists-p (magit-git-dir "rebase-apply/onto"))))
-
-;;; Sections
-
-(defun magit-insert-sequencer-sequence ()
- "Insert section for the on-going cherry-pick or revert sequence.
-If no such sequence is in progress, do nothing."
- (let ((picking (magit-cherry-pick-in-progress-p)))
- (when (or picking (magit-revert-in-progress-p))
- (magit-insert-section (sequence)
- (magit-insert-heading (if picking "Cherry Picking" "Reverting"))
- (-when-let (lines (cdr (magit-file-lines (magit-git-dir "sequencer/todo"))))
- (dolist (line (nreverse lines))
- (when (string-match "^\\(pick\\|revert\\) \\([^ ]+\\) \\(.*\\)$" line)
- (magit-bind-match-strings (cmd hash msg) line
- (magit-insert-section (commit hash)
- (insert (propertize cmd 'face 'magit-sequence-pick)
- " " (propertize hash 'face 'magit-hash)
- " " msg "\n"))))))
- (magit-sequence-insert-sequence
- (magit-file-line (magit-git-dir (if picking
- "CHERRY_PICK_HEAD"
- "REVERT_HEAD")))
- (magit-file-line (magit-git-dir "sequencer/head")))
- (insert "\n")))))
-
-(defun magit-insert-am-sequence ()
- "Insert section for the on-going patch applying sequence.
-If no such sequence is in progress, do nothing."
- (when (magit-am-in-progress-p)
- (magit-insert-section (rebase-sequence)
- (magit-insert-heading "Applying patches")
- (let ((patches (nreverse (magit-rebase-patches)))
- patch commit)
- (while patches
- (setq patch (pop patches)
- commit (magit-rev-verify-commit
- (cadr (split-string (magit-file-line patch)))))
- (cond ((and commit patches)
- (magit-sequence-insert-commit
- "pick" commit 'magit-sequence-pick))
- (patches
- (magit-sequence-insert-am-patch
- "pick" patch 'magit-sequence-pick))
- (commit
- (magit-sequence-insert-sequence commit "ORIG_HEAD"))
- (t
- (magit-sequence-insert-am-patch
- "stop" patch 'magit-sequence-stop)
- (magit-sequence-insert-sequence nil "ORIG_HEAD")))))
- (insert ?\n))))
-
-(defun magit-sequence-insert-am-patch (type patch face)
- (magit-insert-section (file patch)
- (insert (propertize type 'face face)
- ?\s (propertize (file-name-nondirectory patch) 'face 'magit-hash)
- ?\n)))
-
-(defun magit-insert-rebase-sequence ()
- "Insert section for the on-going rebase sequence.
-If no such sequence is in progress, do nothing."
- (when (magit-rebase-in-progress-p)
- (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge")))
- (dir (if interactive "rebase-merge/" "rebase-apply/"))
- (name (-> (concat dir "head-name") magit-git-dir magit-file-line))
- (onto (-> (concat dir "onto") magit-git-dir magit-file-line))
- (onto (or (magit-rev-name onto name)
- (magit-rev-name onto "refs/heads/*") onto))
- (name (or (magit-rev-name name "refs/heads/*") name)))
- (magit-insert-section (rebase-sequence)
- (magit-insert-heading (format "Rebasing %s onto %s" name onto))
- (if interactive
- (magit-rebase-insert-merge-sequence)
- (magit-rebase-insert-apply-sequence))
- (magit-sequence-insert-sequence
- (magit-file-line
- (magit-git-dir
- (concat dir (if interactive "stopped-sha" "original-commit"))))
- onto (--map (cadr (split-string it))
- (magit-file-lines (magit-git-dir "rebase-merge/done"))))
- (insert ?\n)))))
-
-(defun magit-rebase-insert-merge-sequence ()
- (dolist (line (nreverse
- (magit-file-lines
- (magit-git-dir "rebase-merge/git-rebase-todo"))))
- (when (string-match "^\\([^# ]+\\) \\([^ ]+\\) .*$" line)
- (magit-bind-match-strings (action hash) line
- (magit-sequence-insert-commit action hash 'magit-sequence-pick)))))
-
-(defun magit-rebase-insert-apply-sequence ()
- (dolist (patch (nreverse (cdr (magit-rebase-patches))))
- (magit-sequence-insert-commit
- "pick" (cadr (split-string (magit-file-line patch))) 'magit-sequence-pick)))
-
-(defun magit-rebase-patches ()
- (directory-files (magit-git-dir "rebase-apply") t "^[0-9]\\{4\\}$"))
-
-(defun magit-sequence-insert-sequence (stop onto &optional orig)
- (let ((head (magit-rev-parse "HEAD")) done)
- (setq onto (if onto (magit-rev-parse onto) head))
- (setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD")))
- (when (and stop (not (member stop done)))
- (let ((id (magit-patch-id stop)))
- (--if-let (--first (equal (magit-patch-id it) id) done)
- (setq stop it)
- (cond
- ((--first (magit-rev-equal it 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...
- ((magit-anything-unmerged-p)
- ;; ...and time travel isn't for the faint of heart.
- (magit-sequence-insert-commit "join" stop 'magit-sequence-part))
- ((magit-anything-modified-p t)
- ;; ...and the dust hasn't settled yet...
- (magit-sequence-insert-commit
- (let ((staged (magit-commit-tree "oO" nil "HEAD"))
- (unstaged (magit-commit-worktree "oO" "--reset")))
- (cond
- ;; ...but we could end up at the same tree just by committing.
- ((or (magit-rev-equal staged stop)
- (magit-rev-equal unstaged stop)) "goal")
- ;; ...but the changes are still there, untainted.
- ((or (equal (magit-patch-id staged) id)
- (equal (magit-patch-id unstaged) id)) "same")
- ;; ...and some changes are gone and/or others were added.
- (t "work")))
- stop 'magit-sequence-part))
- ;; The commit is definitely gone...
- ((--first (magit-rev-equal it stop) done)
- ;; ...but all of its changes are still in effect.
- (magit-sequence-insert-commit "poof" stop 'magit-sequence-drop))
- (t
- ;; ...and some changes are gone and/or other changes were added.
- (magit-sequence-insert-commit "gone" stop 'magit-sequence-drop)))
- (setq stop nil))))
- (dolist (rev done)
- (apply 'magit-sequence-insert-commit
- (cond ((equal rev stop)
- ;; ...but its reincarnation lives on.
- ;; Or it didn't die in the first place.
- (list (if (and (equal rev head)
- (equal (magit-patch-id (concat stop "^"))
- (magit-patch-id (car (last orig 2)))))
- "stop" ; We haven't done anything yet.
- "same") ; There are new commits.
- rev (if (equal rev head)
- 'magit-sequence-head
- 'magit-sequence-stop)))
- ((equal rev head)
- (list "done" rev 'magit-sequence-head))
- (t
- (list "done" rev 'magit-sequence-done)))))
- (magit-sequence-insert-commit "onto" onto
- (if (equal onto head)
- 'magit-sequence-head
- 'magit-sequence-onto))))
-
-(defun magit-sequence-insert-commit (type hash face)
- (magit-insert-section (commit hash)
- (insert (propertize type 'face face) ?\s
- (magit-format-rev-summary hash) ?\n)))
-
-;;; magit-sequence.el ends soon
-(provide 'magit-sequence)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-sequence.el ends here
+++ /dev/null
-;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Support for Git stashes.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-stash-popup "magit-stash" nil t)
-(magit-define-popup magit-stash-popup
- "Popup console for stash commands."
- 'magit-commands
- :man-page "git-stash"
- :switches '((?u "Also save untracked files" "--include-untracked")
- (?a "Also save untracked and ignored files" "--all"))
- :actions '((?z "Save" magit-stash)
- (?Z "Snapshot" magit-snapshot)
- (?p "Pop" magit-stash-pop)
- (?i "Save index" magit-stash-index)
- (?I "Snapshot index" magit-snapshot-index)
- (?a "Apply" magit-stash-apply)
- (?w "Save worktree" magit-stash-worktree)
- (?W "Snapshot worktree" magit-snapshot-worktree)
- (?l "List" magit-stash-list)
- (?x "Save keeping index" magit-stash-keep-index)
- (?r "Snapshot to wipref" magit-wip-commit)
- (?v "Show" magit-stash-show)
- (?b "Branch" magit-stash-branch)
- (?k "Drop" magit-stash-drop) nil
- (?f "Format patch" magit-stash-format-patch))
- :default-action 'magit-stash
- :max-action-columns 3)
-
-;;;###autoload
-(defun magit-stash (message &optional include-untracked)
- "Create a stash of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message t t include-untracked t))
-
-;;;###autoload
-(defun magit-stash-index (message)
- "Create a stash of the index only.
-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)))
- (magit-stash-save message t nil nil t 'worktree))
-
-;;;###autoload
-(defun magit-stash-worktree (message &optional include-untracked)
- "Create a stash of the working tree only.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message nil t include-untracked t 'index))
-
-;;;###autoload
-(defun magit-stash-keep-index (message &optional include-untracked)
- "Create a stash of the index and working tree, keeping index intact.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message t t include-untracked t 'index))
-
-(defun magit-stash-read-args ()
- (list (magit-stash-read-message)
- (magit-stash-read-untracked)))
-
-(defun magit-stash-read-untracked ()
- (let ((prefix (prefix-numeric-value current-prefix-arg))
- (args (magit-stash-arguments)))
- (cond ((or (= prefix 16) (member "--all" args)) 'all)
- ((or (= prefix 4) (member "--include-untracked" args)) t))))
-
-(defun magit-stash-read-message ()
- (let* ((default (format "On %s: "
- (or (magit-get-current-branch) "(no branch)")))
- (input (magit-read-string "Stash message" default)))
- (if (equal input default)
- (concat default (magit-rev-format "%h %s"))
- input)))
-
-;;;###autoload
-(defun magit-snapshot (&optional include-untracked)
- "Create a snapshot of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-snapshot-read-args))
- (magit-snapshot-save t t include-untracked t))
-
-;;;###autoload
-(defun magit-snapshot-index ()
- "Create a snapshot of the index only.
-Unstaged and untracked changes are not stashed."
- (interactive)
- (magit-snapshot-save t nil nil t))
-
-;;;###autoload
-(defun magit-snapshot-worktree (&optional include-untracked)
- "Create a snapshot of the working tree only.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-snapshot-read-args))
- (magit-snapshot-save nil t include-untracked t))
-
-(defun magit-snapshot-read-args ()
- (list (magit-stash-read-untracked)))
-
-(defun magit-snapshot-save (index worktree untracked &optional refresh)
- (magit-stash-save (concat "WIP on " (magit-stash-summary))
- index worktree untracked refresh t))
-
-;;;###autoload
-(defun magit-stash-apply (stash)
- "Apply a stash to the working tree.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index."
- (interactive (list (magit-read-stash "Apply stash" t)))
- (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
- (magit-refresh)
- (magit-run-git "stash" "apply" stash)))
-
-(defun magit-stash-pop (stash)
- "Apply a stash to the working tree and remove it from stash list.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index
-and forgo removing the stash."
- (interactive (list (magit-read-stash "Apply pop" t)))
- (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
- (magit-stash-drop stash)
- (magit-run-git "stash" "apply" stash)))
-
-;;;###autoload
-(defun magit-stash-drop (stash)
- "Remove a stash from the stash list.
-When the region is active offer to drop all contained stashes."
- (interactive (list (--if-let (magit-region-values 'stash)
- (magit-confirm t nil "Drop %i stashes" it)
- (magit-read-stash "Drop stash"))))
- (dolist (stash (if (listp stash)
- (nreverse (prog1 stash (setq stash (car stash))))
- (list stash)))
- (message "Deleted refs/%s (was %s)" stash
- (magit-rev-parse "--short" stash))
- (magit-call-git "reflog" "delete" "--updateref" "--rewrite" stash))
- (-when-let (ref (and (string-match "\\(.+\\)@{[0-9]+}$" stash)
- (match-string 1 stash)))
- (unless (string-match "^refs/" ref)
- (setq ref (concat "refs/" ref)))
- (unless (magit-rev-verify (concat ref "@{0}"))
- (magit-run-git "update-ref" "-d" ref)))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-stash-clear (ref)
- "Remove all stashes saved in REF's reflog by deleting REF."
- (interactive
- (let ((ref (or (magit-section-when 'stashes) "refs/stash")))
- (if (magit-confirm t (format "Drop all stashes in %s" ref))
- (list ref)
- (user-error "Abort"))))
- (magit-run-git "update-ref" "-d" ref))
-
-;;;###autoload
-(defun magit-stash-branch (stash branch)
- "Create and checkout a new BRANCH from STASH."
- (interactive (list (magit-read-stash "Branch stash" t)
- (magit-read-string-ns "Branch name")))
- (magit-run-git "stash" "branch" branch stash))
-
-;;;###autoload
-(defun magit-stash-format-patch (stash)
- "Create a patch from STASH"
- (interactive (list (magit-read-stash "Create patch from stash" t)))
- (with-temp-file (magit-rev-format "0001-%f.patch" stash)
- (magit-git-insert "stash" "show" "-p" stash))
- (magit-refresh))
-
-;;; Plumbing
-
-(defun magit-stash-save (message index worktree untracked
- &optional refresh keep noerror ref)
- (if (or (and index (magit-staged-files t))
- (and worktree (magit-modified-files t))
- (and untracked (magit-untracked-files (eq untracked 'all))))
- (magit-with-toplevel
- (magit-stash-store message (or ref "refs/stash")
- (magit-stash-create message index worktree untracked))
- (if (eq keep 'worktree)
- (with-temp-buffer
- (magit-git-insert "diff" "--cached")
- (magit-run-git-with-input
- "apply" "--reverse" "--cached" "--ignore-space-change" "-")
- (magit-run-git-with-input
- "apply" "--reverse" "--ignore-space-change" "-"))
- (unless (eq keep t)
- (if (eq keep 'index)
- (magit-call-git "checkout" "--" ".")
- (magit-call-git "reset" "--hard" "HEAD"))
- (when untracked
- (magit-call-git "clean" "-f" (and (eq untracked 'all) "-x")))))
- (when refresh
- (magit-refresh)))
- (unless noerror
- (user-error "No %s changes to save" (cond ((not index) "unstaged")
- ((not worktree) "staged")
- (t "local"))))))
-
-(defun magit-stash-store (message ref commit)
- (magit-update-ref ref message commit t))
-
-(defun magit-stash-create (message index worktree untracked)
- (unless (magit-rev-parse "--verify" "HEAD")
- (error "You do not have the initial commit yet"))
- (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false")
- magit-git-global-arguments))
- (default-directory (magit-toplevel))
- (summary (magit-stash-summary))
- (head "HEAD"))
- (when (and worktree (not index))
- (setq head (magit-commit-tree "pre-stash index" nil "HEAD")))
- (or (setq index (magit-commit-tree (concat "index on " summary) nil head))
- (error "Cannot save the current index state"))
- (and untracked
- (setq untracked (magit-untracked-files (eq untracked 'all)))
- (setq untracked (magit-with-temp-index nil nil
- (or (and (magit-update-files untracked)
- (magit-commit-tree
- (concat "untracked files on " summary)))
- (error "Cannot save the untracked files")))))
- (magit-with-temp-index index "-m"
- (when worktree
- (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head))
- (error "Cannot save the current worktree state")))
- (or (magit-commit-tree message nil head index untracked)
- (error "Cannot save the current worktree state")))))
-
-(defun magit-stash-summary ()
- (concat (or (magit-get-current-branch) "(no branch)")
- ": " (magit-rev-format "%h %s")))
-
-;;; Sections
-
-(defvar magit-stashes-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-stash-clear)
- map)
- "Keymap for `stashes' section.")
-
-(defvar magit-stash-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-stash-show)
- (define-key map [remap magit-delete-thing] 'magit-stash-drop)
- (define-key map "a" 'magit-stash-apply)
- (define-key map "A" 'magit-stash-pop)
- map)
- "Keymap for `stash' sections.")
-
-(magit-define-section-jumper magit-jump-to-stashes
- "Stashes" stashes "refs/stash")
-
-(cl-defun magit-insert-stashes (&optional (ref "refs/stash")
- (heading "Stashes:"))
- "Insert `stashes' section showing reflog for \"refs/stash\".
-If optional REF is non-nil show reflog for that instead.
-If optional HEADING is non-nil use that as section heading
-instead of \"Stashes:\"."
- (when (magit-rev-verify ref)
- (magit-insert-section (stashes ref (not magit-status-expand-stashes))
- (magit-insert-heading heading)
- (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
- "reflog" "--format=%gd %at %gs" ref))))
-
-;;; List Stashes
-
-;;;###autoload
-(defun magit-stash-list ()
- "List all stashes in a buffer."
- (interactive)
- (magit-mode-setup #'magit-stashes-mode "refs/stash"))
-
-(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes"
- "Mode for looking at lists of stashes."
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(cl-defun magit-stashes-refresh-buffer (ref)
- (magit-insert-section (stashesbuf)
- (magit-insert-heading (if (equal ref "refs/stash")
- "Stashes:"
- (format "Stashes [%s]:" ref)))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
- "reflog" "--format=%gd %at %gs" ref)))
-
-;;; Show Stash
-
-(defcustom magit-stash-sections-hook
- '(magit-insert-stash-worktree
- magit-insert-stash-index
- magit-insert-stash-untracked)
- "Hook run to insert sections into stash buffers."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type 'hook)
-
-;;;###autoload
-(defun magit-stash-show (stash &optional args files)
- "Show all diffs of a stash in a buffer."
- (interactive (cons (or (and (not current-prefix-arg)
- (magit-stash-at-point))
- (magit-read-stash "Show stash"))
- (-let [(args files) (magit-diff-arguments)]
- (list (delete "--stat" args) files))))
- (magit-mode-setup #'magit-stash-mode stash nil args files))
-
-(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash"
- "Mode for looking at individual stashes."
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-stash-refresh-buffer (stash _const _args _files)
- (setq header-line-format
- (concat
- "\s" (propertize (capitalize stash) 'face 'magit-section-heading)
- "\s" (magit-rev-format "%s" stash)))
- (magit-insert-section (stash)
- (run-hooks 'magit-stash-sections-hook)))
-
-(defun magit-stash-insert-section (commit range message &optional files)
- (magit-insert-section (commit commit)
- (magit-insert-heading message)
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" range "-p" "--no-prefix"
- (nth 2 magit-refresh-args)
- "--" (or files (nth 3 magit-refresh-args)))))
-
-(defun magit-insert-stash-index ()
- "Insert section showing the index commit of the stash."
- (let ((stash (car magit-refresh-args)))
- (magit-stash-insert-section (format "%s^2" stash)
- (format "%s^..%s^2" stash stash)
- "Index")))
-
-(defun magit-insert-stash-worktree ()
- "Insert section showing the worktree commit of the stash."
- (let ((stash (car magit-refresh-args)))
- (magit-stash-insert-section stash
- (format "%s^2..%s" stash stash)
- "Working tree")))
-
-(defun magit-insert-stash-untracked ()
- "Insert section showing the untracked files commit of the stash."
- (let ((stash (car magit-refresh-args))
- (rev (concat (car magit-refresh-args) "^3")))
- (when (magit-rev-verify rev)
- (magit-stash-insert-section (format "%s^3" stash)
- (format "%s^..%s^3" stash stash)
- "Untracked files"
- (magit-git-items "ls-tree" "-z" "--name-only"
- "--full-tree" rev)))))
-
-;;; magit-stash.el ends soon
-(provide 'magit-stash)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-stash.el ends here
+++ /dev/null
-;;; magit-submodule.el --- submodule support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2015 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-submodule-popup "magit-submodule" nil t)
-(magit-define-popup magit-submodule-popup
- "Popup console for submodule commands."
- 'magit-commands nil nil
- :man-page "git-submodule"
- :actions '((?a "Add" magit-submodule-add)
- (?b "Setup" magit-submodule-setup)
- (?i "Init" magit-submodule-init)
- (?u "Update" magit-submodule-update)
- (?s "Sync" magit-submodule-sync)
- (?f "Fetch" magit-submodule-fetch)
- (?d "Deinit" magit-submodule-deinit)))
-
-;;;###autoload
-(defun magit-submodule-add (url &optional path)
- "Add the repository at URL as a submodule.
-Optional PATH is the path to the submodule relative to the root
-of the superproject. If it is nil then the path is determined
-based on URL."
- (interactive
- (magit-with-toplevel
- (let ((path (read-file-name
- "Add submodule: " nil nil nil
- (magit-section-when [file untracked]
- (directory-file-name (magit-section-value it))))))
- (when path
- (setq path (file-name-as-directory (expand-file-name path)))
- (when (member path (list "" default-directory))
- (setq path nil)))
- (list (magit-read-string-ns
- "Remote url"
- (and path (magit-git-repo-p path t)
- (let ((default-directory path))
- (magit-get "remote" (or (magit-get-remote) "origin")
- "url"))))
- (and path (directory-file-name (file-relative-name path)))))))
- (magit-run-git "submodule" "add" url path))
-
-;;;###autoload
-(defun magit-submodule-setup ()
- "Clone and register missing submodules and checkout appropriate commits."
- (interactive)
- (magit-submodule-update t))
-
-;;;###autoload
-(defun magit-submodule-init ()
- "Register submodules listed in \".gitmodules\" into \".git/config\"."
- (interactive)
- (magit-with-toplevel
- (magit-run-git-async "submodule" "init")))
-
-;;;###autoload
-(defun magit-submodule-update (&optional init)
- "Clone missing submodules and checkout appropriate commits.
-With a prefix argument also register submodules in \".git/config\"."
- (interactive "P")
- (magit-with-toplevel
- (magit-run-git-async "submodule" "update" (and init "--init"))))
-
-;;;###autoload
-(defun magit-submodule-sync ()
- "Update each submodule's remote URL according to \".gitmodules\"."
- (interactive)
- (magit-with-toplevel
- (magit-run-git-async "submodule" "sync")))
-
-;;;###autoload
-(defun magit-submodule-fetch (&optional all)
- "Fetch all submodules.
-With a prefix argument fetch all remotes."
- (interactive "P")
- (magit-with-toplevel
- (magit-run-git-async "submodule" "foreach"
- (format "git fetch %s || true" (if all "--all" "")))))
-
-;;;###autoload
-(defun magit-submodule-deinit (path)
- "Unregister the submodule at PATH."
- (interactive
- (list (magit-completing-read "Deinit module" (magit-get-submodules)
- nil t nil nil (magit-section-when module))))
- (magit-with-toplevel
- (magit-run-git-async "submodule" "deinit" path)))
-
-;;; Sections
-
-;;;###autoload
-(defun magit-insert-submodule-commits (section range)
- "For internal use, don't add to a hook."
- (if (magit-section-hidden section)
- (setf (magit-section-washer section)
- (apply-partially #'magit-insert-submodule-commits section range))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'module)
- "log" "--oneline" range)
- (when (> (point) (magit-section-content section))
- (delete-char -1))))
-
-;;;###autoload
-(defun magit-insert-unpulled-module-commits ()
- "Insert sections for all submodules with unpulled commits.
-These sections can be expanded to show the respective commits."
- (-when-let (modules (magit-get-submodules))
- (magit-insert-section section (unpulled-modules)
- (magit-insert-heading "Unpulled modules:")
- (magit-with-toplevel
- (dolist (module modules)
- (let ((default-directory
- (expand-file-name (file-name-as-directory module))))
- (-when-let (tracked (magit-get-upstream-ref))
- (magit-insert-section sec (file module t)
- (magit-insert-heading
- (concat (propertize module 'face 'magit-diff-file-heading) ":"))
- (magit-insert-submodule-commits
- section (concat "HEAD.." tracked)))))))
- (if (> (point) (magit-section-content section))
- (insert ?\n)
- (magit-cancel-section)))))
-
-;;;###autoload
-(defun magit-insert-unpushed-module-commits ()
- "Insert sections for all submodules with unpushed commits.
-These sections can be expanded to show the respective commits."
- (-when-let (modules (magit-get-submodules))
- (magit-insert-section section (unpushed-modules)
- (magit-insert-heading "Unpushed modules:")
- (magit-with-toplevel
- (dolist (module modules)
- (let ((default-directory
- (expand-file-name (file-name-as-directory module))))
- (-when-let (tracked (magit-get-upstream-ref))
- (magit-insert-section sec (file module t)
- (magit-insert-heading
- (concat (propertize module 'face 'magit-diff-file-heading) ":"))
- (magit-insert-submodule-commits
- section (concat tracked "..HEAD")))))))
- (if (> (point) (magit-section-content section))
- (insert ?\n)
- (magit-cancel-section)))))
-
-;;; magit-submodule.el ends soon
-(provide 'magit-submodule)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-submodule.el ends here
+++ /dev/null
-;;; magit-utils.el --- various utilities -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Contains code from GNU Emacs https://www.gnu.org/software/emacs,
-;; released under the GNU General Public License version 3 or later.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library defines several utility functions used by several
-;; other libraries which cannot depend on one another (because
-;; circular dependencies are not good). Luckily most (all) of these
-;; functions have very little (nothing) to do with Git, so we not only
-;; have to do this, it even makes sense.
-
-;; Unfortunately there are also some options which are used by several
-;; libraries which cannot depend on one another, they are defined here
-;; too.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(eval-when-compile (require 'ido))
-(declare-function ido-completing-read+ 'ido-completing-read+)
-
-(defvar magit-wip-before-change-mode)
-
-;;; Options
-
-(defcustom magit-completing-read-function 'magit-builtin-completing-read
- "Function to be called when requesting input from the user.
-
-For Helm users, the simplest way to get Helm completion is to
-turn on `helm-mode' and leave this option set to the default
-value. However, if you prefer to not use `helm-mode' but still
-want Magit to use Helm for completion, you can set this option to
-`helm--completing-read-default'."
- :group 'magit
- :type '(radio (function-item magit-builtin-completing-read)
- (function-item magit-ido-completing-read)
- (function-item helm--completing-read-default)
- (function :tag "Other")))
-
-(defcustom magit-no-confirm nil
- "A list of symbols for actions Magit should not confirm, or t.
-
-Many potentially dangerous commands by default ask the user for
-confirmation. Each of the below symbols stands for an action
-which, when invoked unintentionally or without being fully aware
-of the consequences, could lead to tears. In many cases there
-are several commands that perform variations of a certain action,
-so we don't use the command names but more generic symbols.
-
-Applying changes:
-
- `discard' Discarding one or more changes (i.e. hunks or the
- complete diff for a file) loses that change, obviously.
-
- `reverse' Reverting one or more changes can usually be undone
- by reverting the reversion.
-
- `stage-all-changes', `unstage-all-changes' When there are both
- staged and unstaged changes, then un-/staging everything would
- destroy that distinction. Of course that also applies when
- un-/staging a single change, but then less is lost and one does
- that so often that having to confirm every time would be
- unacceptable.
-
-Files:
-
- `delete' When a file that isn't yet tracked by Git is deleted
- then it is completely lost, not just the last changes. Very
- dangerous.
-
- `trash' Instead of deleting a file it can also be move to the
- system trash. Obviously much less dangerous than deleting it.
-
- Also see option `magit-delete-by-moving-to-trash'.
-
- `resurrect' A deleted file can easily be resurrected by
- \"deleting\" the deletion, which is done using the same command
- that was used to delete the same file in the first place.
-
- `rename' Renaming a file can easily be undone.
-
-Sequences:
-
- `reset-bisect' Aborting (known to Git as \"resetting\") a
- bisect operation loses all information collected so far.
-
- `abort-merge' Aborting a merge throws away all conflict
- resolutions which has already been carried out by the user.
-
- `merge-dirty' Merging with a dirty worktree can make it hard to
- go back to the state before the merge was initiated.
-
-References:
-
- `delete-unmerged-branch' Once a branch has been deleted it can
- only be restored using low-level recovery tools provided by
- Git. And even then the reflog is gone. The user always has
- to confirm the deletion of a branch by accepting the default
- choice (or selecting another branch), but when a branch has
- not been merged yet, also make sure the user is aware of that.
-
- `drop-stashes' Dropping a stash is dangerous because Git stores
- stashes in the reflog. Once a stash is removed, there is no
- going back without using low-level recovery tools provided by
- Git. When a single stash is dropped, then the user always has
- to confirm by accepting the default (or selecting another).
- This action only concerns the deletion of multiple stashes at
- once.
-
-Various:
-
- `kill-process' There seldom is a reason to kill a process.
-
-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
- 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
- for confirmation for any of these actions, you are still better
- of adding all of the respective symbols individually.
-
- When `magit-wip-before-change-mode' is enabled then these actions
- can fairly easily be undone: `discard', `reverse',
- `stage-all-changes', and `unstage-all-changes'. If and only if
- this mode is enabled then `safe-with-wip' has the same effect
- as adding all of these symbols individually."
- :package-version '(magit . "2.1.0")
- :group 'magit
- :type '(choice (const :tag "No confirmation needed" t)
- (set (const reverse) (const discard)
- (const rename) (const resurrect)
- (const trash) (const delete)
- (const abort-merge) (const merge-dirty)
- (const drop-stashes) (const resect-bisect)
- (const kill-process) (const delete-unmerged-branch)
- (const stage-all-changes) (const unstage-all-changes)
- (const safe-with-wip))))
-
-(defcustom magit-ellipsis ?…
- "Character used to abbreviate text."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'character)
-
-(defcustom magit-update-other-window-delay 0.2
- "Delay before automatically updating the other window.
-
-When moving around in certain buffers certain other buffers,
-which are being displayed in another window, may optionally be
-updated to display information about the section at point.
-
-When holding down a key to move by more than just one section,
-then that would update that buffer for each section on the way.
-To prevent that, updating the revision buffer is delayed, and
-this option controls for how long. For optimal experience you
-might have to adjust this delay and/or the keyboard repeat rate
-and delay of your graphical environment or operating system."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'number)
-
-;;; User Input
-
-(defun magit-completing-read
- (prompt collection &optional predicate require-match initial-input hist def)
- "Magit wrapper around `completing-read' or an alternative function.
-
-Option `magit-completing-read-function' can be used to wrap
-around another `completing-read'-like function. Unless it
-doesn't have the exact same signature, an additional wrapper is
-required. Even if it has the same signature it might be a good
-idea to wrap it, so that `magit-prompt-with-default' can be used.
-
-See `completing-read' for the meanings of the arguments, but note
-that this wrapper makes the following changes:
-
-- If REQUIRE-MATCH is nil and the user exits without a choice,
- then return nil instead of an empty string.
-
-- If REQUIRE-MATCH is non-nil and the users exits without a
- choice, then raise an user-error.
-
-- \": \" is appended to PROMPT.
-
-- If a `magit-completing-read-function' is used which in turn
- uses `magit-prompt-with-completion' and DEF is non-nil, then
- PROMPT is modified to end with \" (default DEF): \".
-
-The use of another completing function and/or wrapper obviously
-results in additional differences."
- (let ((reply (funcall magit-completing-read-function
- (concat prompt ": ") collection predicate
- require-match initial-input hist def)))
- (if (string= reply "")
- (if require-match
- (user-error "Nothing selected")
- nil)
- reply)))
-
-(defun magit-builtin-completing-read
- (prompt choices &optional predicate require-match initial-input hist def)
- "Magit wrapper for standard `completing-read' function."
- (completing-read (magit-prompt-with-default prompt def)
- choices predicate require-match
- initial-input hist def))
-
-(defun magit-ido-completing-read
- (prompt choices &optional predicate require-match initial-input hist def)
- "Ido-based `completing-read' almost-replacement.
-
-Unfortunately `ido-completing-read' is not suitable as a
-drop-in replacement for `completing-read', instead we use
-`ido-completing-read+' from the third-party package by the
-same name."
- (if (require 'ido-completing-read+ nil t)
- (ido-completing-read+ prompt choices predicate require-match
- initial-input hist def)
- (display-warning 'magit "ido-completing-read+ is not installed
-
-To use Ido completion with Magit you need to install the
-third-party `ido-completing-read+' packages. Falling
-back to built-in `completing-read' for now." :error)
- (magit-builtin-completing-read prompt choices predicate require-match
- initial-input hist def)))
-
-(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 magit-minibuffer-local-ns-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map minibuffer-local-map)
- (define-key map "\s" 'magit-whitespace-disallowed)
- (define-key map "\t" 'magit-whitespace-disallowed)
- map))
-
-(defun magit-whitespace-disallowed ()
- "Beep to tell the user that whitespace is not allowed."
- (interactive)
- (ding)
- (message "Whitespace isn't allowed here")
- (setq defining-kbd-macro nil)
- (force-mode-line-update))
-
-(defun magit-read-string (prompt &optional initial-input history default-value
- inherit-input-method no-whitespace)
- "Read a string from the minibuffer, prompting with string PROMPT.
-
-This is similar to `read-string', but
-* empty input is only allowed if DEFAULT-VALUE is non-nil in
- which case that is returned,
-* whitespace is not allowed if NO-WHITESPACE is non-nil,
-* \": \" is appended to PROMPT, and
-* an invalid DEFAULT-VALUE is silently ignored."
- (when default-value
- (when (consp default-value)
- (setq default-value (car default-value)))
- (unless (stringp default-value)
- (setq default-value nil)))
- (let* ((minibuffer-completion-table nil)
- (val (read-from-minibuffer
- (magit-prompt-with-default (concat prompt ": ") default-value)
- initial-input (and no-whitespace magit-minibuffer-local-ns-map)
- nil history default-value inherit-input-method)))
- (when (and (string= val "") default-value)
- (setq val default-value))
- (cond ((string= val "")
- (user-error "Need non-empty input"))
- ((and no-whitespace (string-match-p "[\s\t\n]" val))
- (user-error "Input contains whitespace"))
- (t val))))
-
-(defun magit-read-string-ns (prompt &optional initial-input history
- default-value inherit-input-method)
- "Call `magit-read-string' with non-nil NO-WHITESPACE."
- (magit-read-string prompt initial-input history default-value
- inherit-input-method t))
-
-(defmacro magit-read-char-case (prompt verbose &rest clauses)
- (declare (indent 2)
- (debug (form form &rest (characterp form body))))
- `(pcase (read-char-choice
- (concat ,prompt
- ,(concat (mapconcat 'cadr clauses ", ")
- (and verbose ", or [C-g] to abort") " "))
- ',(mapcar 'car clauses))
- ,@(--map `(,(car it) ,@(cddr it)) clauses)))
-
-(cl-defun magit-confirm (action &optional prompt prompt-n (items nil sitems))
- (declare (indent defun))
- (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items))
- prompt (format (concat (or prompt (magit-confirm-make-prompt action))
- "? ")
- (car items)))
- (cond ((and (not (eq action t))
- (or (eq magit-no-confirm t)
- (memq action
- `(,@magit-no-confirm
- ,@(and magit-wip-before-change-mode
- (memq 'safe-with-wip magit-no-confirm)
- `(discard reverse
- stage-all-changes
- unstage-all-changes))))))
- (or (not sitems) items))
- ((not sitems)
- (y-or-n-p prompt))
- ((= (length items) 1)
- (and (y-or-n-p prompt) items))
- ((> (length items) 1)
- (let ((buffer (get-buffer-create " *Magit Confirm*")))
- (with-current-buffer buffer
- (with-current-buffer-window
- buffer (cons 'display-buffer-below-selected
- '((window-height . fit-window-to-buffer)))
- (lambda (window _value)
- (with-selected-window window
- (unwind-protect (and (y-or-n-p prompt-n) items)
- (when (window-live-p window)
- (quit-restore-window window 'kill)))))
- (dolist (item items)
- (insert item "\n"))))))))
-
-(defun magit-confirm-files (action files &optional prompt)
- (when files
- (unless prompt
- (setq prompt (magit-confirm-make-prompt action)))
- (magit-confirm action
- (concat prompt " %s")
- (concat prompt " %i files")
- files)))
-
-(defun magit-confirm-make-prompt (action)
- (let ((prompt (symbol-name action)))
- (replace-regexp-in-string
- "-" " " (concat (upcase (substring prompt 0 1)) (substring prompt 1)))))
-
-;;; Text Utilities
-
-(defmacro magit-bind-match-strings (varlist string &rest body)
- "Bind variables to submatches according to VARLIST then evaluate BODY.
-Bind the symbols in VARLIST to submatches of the current match
-data, starting with 1 and incrementing by 1 for each symbol. If
-the last match was against a string then that has to be provided
-as STRING."
- (declare (indent 2) (debug (listp form body)))
- (let ((s (cl-gensym "string"))
- (i 0))
- `(let ((,s ,string))
- (let ,(save-match-data
- (--map (list it (list 'match-string (cl-incf i) s)) varlist))
- ,@body))))
-
-(defun magit-delete-line ()
- "Delete the rest of the current line."
- (delete-region (point) (1+ (line-end-position))))
-
-(defun magit-delete-match (&optional num)
- "Delete text matched by last search.
-If optional NUM is specified only delete that subexpression."
- (delete-region (match-beginning (or num 0))
- (match-end (or num 0))))
-
-(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)))))
-
-(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)))))
-
-;;; magit-utils.el ends soon
-(provide 'magit-utils)
-;; Local Variables:
-;; coding: utf-8
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-utils.el ends here
+++ /dev/null
-;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library defines tree global modes which automatically commit
-;; snapshots to branch specific work-in-progress refs before and after
-;; making changes, and two commands which can be used to do so on
-;; demand.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-log)
-
-;;; Options
-
-(defgroup magit-wip nil
- "Automatically commit to work-in-progress refs."
- :group 'magit-extensions)
-
-(defcustom magit-wip-after-save-local-mode-lighter " sWip"
- "Lighter for Magit-Wip-After-Save-Local mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-(defcustom magit-wip-after-apply-mode-lighter " aWip"
- "Lighter for Magit-Wip-After-Apply mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-(defcustom magit-wip-before-change-mode-lighter " cWip"
- "Lighter for Magit-Wip-Before-Change mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-(defcustom magit-wip-namespace "refs/wip/"
- "Namespace used for work-in-progress refs.
-The wip refs are named \"<namespace/>index/<branchref>\"
-and \"<namespace/>wtree/<branchref>\". When snapshots
-are created while the `HEAD' is detached then \"HEAD\"
-is used as `branch-ref'."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-;;; Modes
-
-(define-minor-mode magit-wip-after-save-local-mode
- "After saving, also commit to a worktree work-in-progress ref.
-
-After saving the current file-visiting buffer this mode also
-commits the changes to the worktree work-in-progress ref for
-the current branch.
-
-This mode should be enabled globally by turning on the globalized
-variant `magit-wip-after-save-mode'."
- :package-version '(magit . "2.1.0")
- :lighter magit-wip-after-save-local-mode-lighter
- (if magit-wip-after-save-local-mode
- (if (and buffer-file-name (magit-inside-worktree-p))
- (add-hook 'after-save-hook 'magit-wip-commit-buffer-file t t)
- (setq magit-wip-after-save-local-mode nil)
- (user-error "Need a worktree and a file"))
- (remove-hook 'after-save-hook 'magit-wip-commit-buffer-file t)))
-
-(defun magit-wip-after-save-local-mode-turn-on ()
- (and buffer-file-name
- (ignore-errors (magit-inside-worktree-p))
- (magit-file-tracked-p buffer-file-name)
- (magit-wip-after-save-local-mode)))
-
-;;;###autoload
-(define-globalized-minor-mode magit-wip-after-save-mode
- magit-wip-after-save-local-mode magit-wip-after-save-local-mode-turn-on
- :package-version '(magit . "2.1.0")
- :group 'magit-wip)
-
-(defun magit-wip-commit-buffer-file ()
- "Commit visited file to a worktree work-in-progress ref.
-
-Also see `magit-wip-after-save-mode' which calls this function
-automatically whenever a buffer visiting a tracked file is saved."
- (interactive)
- (--when-let (magit-wip-get-ref)
- (magit-with-toplevel
- (let ((file (file-relative-name buffer-file-name)))
- (magit-wip-commit-worktree
- it (list file) (if (called-interactively-p 'any)
- (format "wip-save %s after save" file)
- (format "autosave %s after save" file)))))))
-
-;;;###autoload
-(define-minor-mode magit-wip-after-apply-mode
- "Commit to work-in-progress refs.
-
-After applying a change using any \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected files to the current wip refs. For each branch there
-may be two wip refs; one contains snapshots of the files as found
-in the worktree and the other contains snapshots of the entries
-in the index."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :lighter magit-wip-after-change-mode-lighter
- :global t)
-
-(defun magit-wip-commit-after-apply (&optional files msg)
- (when magit-wip-after-apply-mode
- (magit-wip-commit files msg)))
-
-;;;###autoload
-(define-minor-mode magit-wip-before-change-mode
- "Commit to work-in-progress refs before certain destructive changes.
-
-Before invoking a revert command or an \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected tracked files to the current wip refs. For each branch
-there may be two wip refs; one contains snapshots of the files
-as found in the worktree and the other contains snapshots of the
-entries in the index.
-
-Only changes to files which could potentially be affected by the
-command which is about to be called are committed."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :lighter magit-wip-before-change-mode-lighter
- :global t)
-
-(defun magit-wip-commit-before-change (&optional files msg)
- (when magit-wip-before-change-mode
- (magit-with-toplevel
- (magit-wip-commit files msg))))
-
-;;; Core
-
-(defun magit-wip-commit (&optional files msg)
- "Commit all tracked files to the work-in-progress refs.
-
-Interactively, commit all changes to all tracked files using
-a generic commit message. With a prefix-argument the commit
-message is read in the minibuffer.
-
-Non-interactively, only commit changes to FILES using MSG as
-commit message."
- (interactive (list nil (if current-prefix-arg
- (magit-read-string "Wip commit message")
- "wip-save tracked files")))
- (--when-let (magit-wip-get-ref)
- (magit-wip-commit-index it files msg)
- (magit-wip-commit-worktree it files msg)))
-
-(defun magit-wip-commit-index (ref files msg &optional cached-only)
- (let* ((wipref (concat magit-wip-namespace "index/" ref))
- (parent (magit-wip-get-parent ref wipref)))
- (when (magit-git-failure "diff-index" "--quiet"
- (and cached-only "--cached")
- parent "--" files)
- (magit-wip-update-wipref wipref (magit-git-string "write-tree")
- parent files msg "index"))))
-
-(defun magit-wip-commit-worktree (ref files msg)
- (let* ((wipref (concat magit-wip-namespace "wtree/" ref))
- (parent (magit-wip-get-parent ref wipref))
- (tree (magit-with-temp-index parent "--reset"
- (if files
- (magit-call-git "add" "--" files)
- (magit-with-toplevel
- (magit-call-git "add" "-u" ".")))
- (magit-git-string "write-tree"))))
- (when (magit-git-failure "diff-tree" "--quiet" parent tree "--" files)
- (magit-wip-update-wipref wipref tree parent files msg "worktree"))))
-
-(defun magit-wip-update-wipref (wipref tree parent files msg start-msg)
- (let ((len (length files)))
- (unless (and msg (not (= (aref msg 0) ?\s)))
- (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)))))
- msg)))
- (unless (equal parent wipref)
- (setq start-msg (concat "restart autosaving " start-msg))
- (magit-update-ref wipref start-msg
- (magit-git-string "commit-tree" "-p" parent
- "-m" start-msg
- (concat parent "^{tree}")))
- (setq parent wipref))
- (magit-update-ref wipref msg
- (magit-git-string "commit-tree" tree
- "-p" parent "-m" msg))))
-
-(defun magit-wip-get-ref ()
- (let ((ref (or (magit-git-string "symbolic-ref" "HEAD") "HEAD")))
- (when (magit-rev-verify ref)
- ref)))
-
-(defun magit-wip-get-parent (ref wipref)
- (if (and (magit-rev-verify wipref)
- (equal (magit-git-string "merge-base" wipref ref)
- (magit-rev-verify ref)))
- wipref
- ref))
-
-;;; Log
-
-(defun magit-wip-log-current (branch args files count)
- "Show log for the current branch and its wip refs.
-With a negative prefix argument only show the worktree wip ref.
-The absolute numeric value of the prefix argument controls how
-many \"branches\" of each wip ref are shown."
- (interactive
- (nconc (list (or (magit-get-current-branch) "HEAD"))
- (magit-log-arguments)
- (list (prefix-numeric-value current-prefix-arg))))
- (magit-wip-log branch args files count))
-
-(defun magit-wip-log (branch args files count)
- "Show log for a branch and its wip refs.
-With a negative prefix argument only show the worktree wip ref.
-The absolute numeric value of the prefix argument controls how
-many \"branches\" of each wip ref are shown."
- (interactive
- (nconc (list (magit-completing-read
- "Log branch and its wip refs"
- (-snoc (magit-list-local-branch-names) "HEAD")
- nil t nil 'magit-revision-history
- (or (magit-branch-at-point)
- (magit-get-current-branch)
- "HEAD")))
- (magit-log-arguments)
- (list (prefix-numeric-value current-prefix-arg))))
- (unless (equal branch "HEAD")
- (setq branch (concat "refs/heads/" branch)))
- (magit-log (nconc (list branch)
- (magit-wip-log-get-tips
- (concat magit-wip-namespace "wtree/" branch)
- (abs count))
- (and (>= count 0)
- (magit-wip-log-get-tips
- (concat magit-wip-namespace "index/" branch)
- (abs count))))
- args files))
-
-(defun magit-wip-log-get-tips (wipref count)
- (-when-let (reflog (magit-git-lines "reflog" wipref))
- (let (tips)
- (while (and reflog (> count 1))
- (setq reflog (cl-member "^[^ ]+ [^:]+: restart autosaving"
- reflog :test #'string-match-p))
- (when (and (cadr reflog)
- (string-match "^[^ ]+ \\([^:]+\\)" (cadr reflog)))
- (push (match-string 1 (cadr reflog)) tips))
- (setq reflog (cddr reflog))
- (cl-decf count))
- (cons wipref (nreverse tips)))))
-
-;;; magit-wip.el ends soon
-(provide 'magit-wip)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-wip.el ends here
+++ /dev/null
-;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Kyle Meyer <kyleNOSPAMkyleam.com>
-;; Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-;; Former-Maintainers:
-;; Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-;; Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-;; Phil Jackson <philNOSPAMshellarchive.co.uk>
-;; Rémi Vanicat <vanicatNOSPAMdebian.org>
-;; Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-
-;; Package-Requires: ((emacs "24.4") (async "20150909.2257") (dash "20151021.113") (with-editor "20160128.1201") (git-commit "20160119.1409") (magit-popup "20160119.1409"))
-;; Keywords: git tools vc
-;; Homepage: https://github.com/magit/magit
-
-;; Magit requires at least GNU Emacs 24.4 and Git 1.9.4.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Magit is an interface to the version control system Git,
-;; implemented as an Emacs package. Magit aspires to be a complete
-;; Git porcelain. While we cannot (yet) claim, that Magit wraps and
-;; improves upon each and every Git command, it is complete enough to
-;; allow even experienced Git users to perform almost all of their
-;; daily version control tasks directly from within Emacs. While many
-;; fine Git clients exist, only Magit and Git itself deserve to be
-;; called porcelains.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'with-editor)
-(require 'git-commit)
-(require 'magit-core)
-(require 'magit-diff)
-(require 'magit-apply)
-(require 'magit-log)
-
-(require 'format-spec)
-(require 'package nil t) ; used in `magit-version'
-
-(eval-when-compile (require 'dired-x))
-(declare-function dired-jump 'dired-x)
-(eval-when-compile (require 'eshell))
-(declare-function eshell-parse-arguments 'eshell)
-(eval-when-compile (require 'message))
-(declare-function message-goto-body 'message)
-
-(defconst magit--minimal-git "1.9.4")
-(defconst magit--minimal-emacs "24.4")
-
-;;; Options
-;;;; Status Mode
-
-(defgroup magit-status nil
- "Inspect and manipulate Git repositories."
- :group 'magit-modes)
-
-(defcustom magit-status-mode-hook nil
- "Hook run after entering Magit-Status mode."
- :group 'magit-status
- :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)
- "Hook run to insert headers into the status buffer.
-
-This hook is run by `magit-insert-status-headers', which in turn
-has to be a member of `magit-insert-status-sections' to be used
-at 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))
-
-(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-unpulled-from-upstream
- magit-insert-unpulled-from-pushremote
- magit-insert-unpushed-to-upstream
- magit-insert-unpushed-to-pushremote)
- "Hook run to insert sections into a status buffer."
- :package-version '(magit . "2.4.0")
- :group 'magit-status
- :type 'hook)
-
-(defvar magit-status-refresh-hook nil
- "Hook run after a status buffer has been refreshed.")
-
-(make-obsolete-variable 'magit-status-refresh-hook "\
-use `magit-pre-refresh-hook', `magit-post-refresh-hook',
- `magit-refresh-buffer-hook', or `magit-status-mode-hook' instead.
-
- If you want to run a function every time the status buffer is
- refreshed, in order to do something with that buffer, then use:
-
- (add-hook 'magit-refresh-buffer-hook
- (lambda ()
- (when (derived-mode-p 'magit-status-mode)
- ...)))
-
- If your hook function should run regardless of whether the
- status buffer exists or not, then use `magit-pre-refresh-hook'
- or `magit-post-refresh-hook'.
-
- If your hook function only has to be run once, when the buffer
- is first created, then `magit-status-mode-hook' instead.
-" "Magit 2.4.0")
-
-(defcustom magit-status-expand-stashes t
- "Whether the list of stashes is expanded initially."
- :package-version '(magit . "2.3.0")
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-status-show-hashes-in-headers nil
- "Whether headers in the status buffer show hashes.
-The functions which respect this option are
-`magit-insert-head-branch-header',
-`magit-insert-upstream-branch-header', and
-`magit-insert-push-branch-header'."
- :package-version '(magit . "2.4.0")
- :group 'magit-status
- :type 'boolean)
-
-;;;; Refs Mode
-
-(defgroup magit-refs nil
- "Inspect and manipulate Git branches and tags."
- :group 'magit-modes)
-
-(defcustom magit-refs-mode-hook nil
- "Hook run after entering Magit-Refs mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :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)
- "Hook run to insert sections into a references buffer."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :type 'hook)
-
-(defcustom magit-refs-show-commit-count nil
- "Whether to show commit counts in Magit-Refs mode buffers.
-
-all Show counts for branches and tags.
-branch Show counts for branches only.
-nil Never show counts.
-
-To change the value in an existing buffer use the command
-`magit-refs-show-commit-count'"
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :safe (lambda (val) (memq val '(all branch nil)))
- :type '(choice (const all :tag "For branches and tags")
- (const branch :tag "For branches only")
- (const nil :tag "Never")))
-(put 'magit-refs-show-commit-count 'safe-local-variable 'symbolp)
-(put 'magit-refs-show-commit-count 'permanent-local t)
-
-(defcustom magit-refs-show-margin 'branch
- "Whether to initially show the margin in refs buffers.
-
-When non-nil the committer name and date are initially displayed
-in the margin of refs buffers. The margin can be shown or hidden
-in the current buffer using the command `magit-toggle-margin'."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :safe (lambda (val) (memq val '(all branch nil)))
- :type '(choice (const all :tag "For branches and tags")
- (const branch :tag "For branches only")
- (const nil :tag "Never")))
-
-(defcustom magit-visit-ref-create nil
- "Whether `magit-visit-ref' may create new branches.
-
-When this is non-nil, then \"visiting\" a remote branch in a
-refs buffer works by creating a new local branch which tracks
-the remote branch and then checking out the new local branch."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :group 'magit-commands
- :type 'boolean)
-
-;;;; Miscellaneous
-
-(defcustom magit-branch-read-upstream-first t
- "When creating a branch, read upstream before name of new branch."
- :package-version '(magit . "2.2.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-branch-prefer-remote-upstream nil
- "Whether to favor remote upstreams when creating new branches.
-
-When a new branch is created, Magit offers the branch, commit, or
-stash as the default starting point of the new branch. If there
-is no such thing at point, then it falls back to offer the
-current branch as starting-point. The user may then accept that
-default or pick something else.
-
-If the chosen starting-point is a branch, then it may also be set
-as the upstream of the new branch, depending on the value of the
-Git variable `branch.autoSetupMerge'. By default this is done
-for remote branches, but not for local branches.
-
-You might prefer to always use some remote branch as upstream.
-If the chosen starting-point is (1) a local branch, (2) whose
-name is a member of the value of this option, (3) the upstream of
-that local branch is a remote branch with the same name, and (4)
-that remote branch can be fast-forwarded to the local branch,
-then the chosen branch is used as starting-point, but its own
-upstream is used as the upstream of the new branch.
-
-Assuming the chosen branch matches these conditions you would end
-up with with e.g.:
-
- feature --upstream--> origin/master
-
-instead of
-
- feature --upstream--> master --upstream--> origin/master
-
-Which you prefer is a matter of personal preference. If you do
-prefer the former, then you should add branches such as \"master\",
-\"next\", and \"maint\" to the value of this options."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(repeat string))
-
-(defcustom magit-repository-directories nil
- "Directories containing Git repositories.
-Magit checks these directories for Git repositories and offers
-them as choices when `magit-status' is used with a prefix
-argument."
- :group 'magit
- :type '(repeat string))
-
-(defcustom magit-repository-directories-depth 3
- "The maximum depth to look for Git repositories.
-When looking for a Git repository below the directories in
-`magit-repository-directories', only descend this many levels
-deep."
- :group 'magit
- :type 'integer)
-
-;;;; Faces
-
-(defface magit-header-line
- '((t :inherit magit-section-heading))
- "Face for the `header-line'."
- :group 'magit-faces)
-
-(defface magit-dimmed
- '((((class color) (background light)) :foreground "grey50")
- (((class color) (background dark)) :foreground "grey50"))
- "Face for text that shouldn't stand out."
- :group 'magit-faces)
-
-(defface magit-hash
- '((((class color) (background light)) :foreground "grey60")
- (((class color) (background dark)) :foreground "grey40"))
- "Face for the sha1 part of the log output."
- :group 'magit-faces)
-
-(defface magit-tag
- '((((class color) (background light)) :foreground "Goldenrod4")
- (((class color) (background dark)) :foreground "LightGoldenrod2"))
- "Face for tag labels shown in log buffer."
- :group 'magit-faces)
-
-(defface magit-branch-remote
- '((((class color) (background light)) :foreground "DarkOliveGreen4")
- (((class color) (background dark)) :foreground "DarkSeaGreen2"))
- "Face for remote branch head labels shown in log buffer."
- :group 'magit-faces)
-
-(defface magit-branch-local
- '((((class color) (background light)) :foreground "SkyBlue4")
- (((class color) (background dark)) :foreground "LightSkyBlue1"))
- "Face for local branches."
- :group 'magit-faces)
-
-(defface magit-branch-current
- '((((class color) (background light)) :inherit magit-branch-local :box t)
- (((class color) (background dark)) :inherit magit-branch-local :box t))
- "Face for current branch."
- :group 'magit-faces)
-
-(defface magit-head
- '((((class color) (background light)) :inherit magit-branch-local)
- (((class color) (background dark)) :inherit magit-branch-local))
- "Face for the symbolic ref \"HEAD\"."
- :group 'magit-faces)
-
-(defface magit-refname
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for refnames without a dedicated face."
- :group 'magit-faces)
-
-(defface magit-refname-stash
- '((t :inherit magit-refname))
- "Face for wip refnames."
- :group 'magit-faces)
-
-(defface magit-refname-wip
- '((t :inherit magit-refname))
- "Face for wip refnames."
- :group 'magit-faces)
-
-(defface magit-signature-good
- '((t :foreground "green"))
- "Face for good signatures."
- :group 'magit-faces)
-
-(defface magit-signature-bad
- '((t :foreground "red"))
- "Face for bad signatures."
- :group 'magit-faces)
-
-(defface magit-signature-untrusted
- '((t :foreground "cyan"))
- "Face for good untrusted signatures."
- :group 'magit-faces)
-
-(defface magit-cherry-unmatched
- '((t :foreground "cyan"))
- "Face for unmatched cherry commits."
- :group 'magit-faces)
-
-(defface magit-cherry-equivalent
- '((t :foreground "magenta"))
- "Face for equivalent cherry commits."
- :group 'magit-faces)
-
-(defface magit-filename
- '((t :weight normal))
- "Face for filenames."
- :group 'magit-faces)
-
-;;; Inspect
-;;;; Status Mode
-;;;;; Status Core
-
-(defvar magit-status-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "jz" 'magit-jump-to-stashes)
- (define-key map "jt" 'magit-jump-to-tracked)
- (define-key map "jn" 'magit-jump-to-untracked)
- (define-key map "ju" 'magit-jump-to-unstaged)
- (define-key map "js" 'magit-jump-to-staged)
- (define-key map "jfu" 'magit-jump-to-unpulled-from-upstream)
- (define-key map "jfp" 'magit-jump-to-unpulled-from-pushremote)
- (define-key map "jpu" 'magit-jump-to-unpushed-to-upstream)
- (define-key map "jpp" 'magit-jump-to-unpushed-to-pushremote)
- map)
- "Keymap for `magit-status-mode'.")
-
-(eval-after-load 'dired-x
- '(define-key magit-status-mode-map [remap dired-jump] 'magit-dired-jump))
-
-(define-derived-mode magit-status-mode magit-mode "Magit"
- "Mode for looking at Git status.
-
-This mode is documented in info node `(magit)Status buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] to visit the change or commit at point.
-
-Type \\[magit-dispatch-popup] to see available prefix popups.
-
-Staging and applying changes is documented in info node
-`(magit)Staging and unstaging' and info node `(magit)Applying'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\<magit-status-mode-map>\
-Type \\[magit-commit-popup] to create a commit.
-
-\\{magit-status-mode-map}"
- :group 'magit-status
- (hack-dir-local-variables-non-file-buffer))
-
-;;;###autoload
-(defun magit-status (&optional directory)
- "Show the status of the current Git repository in a buffer.
-With a prefix argument prompt for a repository to be shown.
-With two prefix arguments prompt for an arbitrary directory.
-If that directory isn't the root of an existing repository
-then offer to initialize it as a new repository."
- (interactive
- (list (and (or current-prefix-arg (not (magit-toplevel)))
- (magit-read-repository
- (>= (prefix-numeric-value current-prefix-arg) 16)))))
- (if directory
- (let ((toplevel (magit-toplevel directory)))
- (setq directory (file-name-as-directory (expand-file-name directory)))
- (if (and toplevel (string-equal directory toplevel))
- (magit-status-internal directory)
- (when (y-or-n-p
- (if toplevel
- (format "%s is a repository. Create another in %s? "
- toplevel directory)
- (format "Create repository in %s? " directory)))
- (magit-init directory))))
- (magit-status-internal default-directory)))
-
-(put 'magit-status 'interactive-only 'magit-status-internal)
-
-;;;###autoload
-(defun magit-status-internal (directory)
- (magit-tramp-asserts directory)
- (let ((default-directory directory))
- (magit-mode-setup #'magit-status-mode)))
-
-;;;;; Standard Status Sections
-
-(defvar magit-status-sections-hook-1 nil)
-
-(defun magit-status-refresh-buffer ()
- (magit-git-exit-code "update-index" "--refresh")
- (magit-insert-section (status)
- (if (-all-p #'functionp magit-status-sections-hook)
- (run-hooks 'magit-status-sections-hook)
- (message "`magit-status-sections-hook' contains entries that are \
-no longer valid.\nUsing standard value instead. Please re-configure")
- (sit-for 5)
- (let ((magit-status-sections-hook-1
- (eval (car (get 'magit-status-sections-hook 'standard-value)))))
- (run-hooks 'magit-status-sections-hook-1))))
- (run-hooks 'magit-status-refresh-hook))
-
-(defun magit-insert-status-headers ()
- "Insert header sections appropriate for `magit-status-mode' buffers.
-The sections are inserted by running the functions on the hook
-`magit-status-headers-hook'."
- (if (magit-rev-verify "HEAD")
- (magit-insert-headers magit-status-headers-hook)
- (insert "In the beginning there was darkness\n\n")))
-
-(defun magit-insert-error-header ()
- "Insert the message about the Git error that just occured.
-
-This function is only aware of the last error that occur when Git
-was run for side-effects. If, for example, an error occurs while
-generating a diff, then that error won't be inserted. Refreshing
-the status buffer causes this section to disappear again."
- (when magit-this-error
- (magit-insert-section (error 'git)
- (insert (propertize (format "%-10s" "GitError! ")
- 'face 'magit-section-heading))
- (insert (propertize magit-this-error 'face 'font-lock-warning-face))
- (-when-let (key (car (where-is-internal 'magit-process-buffer)))
- (insert (format " [Type `%s' for details]" (key-description key))))
- (insert ?\n))
- (setq magit-this-error nil)))
-
-(cl-defun magit-insert-head-branch-header
- (&optional (branch (magit-get-current-branch)))
- "Insert a header line about BRANCH.
-When BRANCH is nil, use the current branch or, if none, the
-detached `HEAD'."
- (let ((output (magit-rev-format "%h %s" (or branch "HEAD"))))
- (string-match "^\\([^ ]+\\) \\(.*\\)" output)
- (magit-bind-match-strings (commit summary) output
- (if branch
- (magit-insert-section (branch branch)
- (insert (format "%-10s" "Head: "))
- (when magit-status-show-hashes-in-headers
- (insert (propertize commit 'face 'magit-hash) ?\s))
- (insert (propertize branch 'face 'magit-branch-local))
- (insert ?\s summary ?\n))
- (magit-insert-section (commit commit)
- (insert (format "%-10s" "Head: "))
- (insert (propertize commit 'face 'magit-hash))
- (insert ?\s summary ?\n))))))
-
-(cl-defun magit-insert-upstream-branch-header
- (&optional (branch (magit-get-current-branch))
- (pull (magit-get-upstream-branch branch))
- keyword)
- "Insert a header line about branch usually pulled into current branch."
- (when pull
- (magit-insert-section (branch pull)
- (insert (format "%-10s"
- (or keyword
- (if (magit-get-boolean "branch" branch "rebase")
- "Rebase: "
- "Merge: "))))
- (--when-let (and magit-status-show-hashes-in-headers
- (magit-rev-format "%h" pull))
- (insert (propertize it 'face 'magit-hash) ?\s))
- (insert (propertize pull 'face
- (if (string= (magit-get "branch" branch "remote") ".")
- 'magit-branch-local
- 'magit-branch-remote)))
- (insert ?\s)
- (if (magit-rev-verify pull)
- (insert (or (magit-rev-format "%s" pull) ""))
- (insert (propertize "is missing" 'face 'font-lock-warning-face)))
- (insert ?\n))))
-
-(cl-defun magit-insert-push-branch-header
- (&optional (branch (magit-get-current-branch))
- (push (magit-get-push-branch branch)))
- "Insert a header line about the branch the current branch is pushed to."
- (when push
- (magit-insert-section (branch push)
- (insert (format "%-10s" "Push: "))
- (--when-let (and magit-status-show-hashes-in-headers
- (magit-rev-format "%h" push))
- (insert (propertize it 'face 'magit-hash) ?\s))
- (insert (propertize push 'face 'magit-branch-remote) ?\s)
- (if (magit-rev-verify push)
- (insert (or (magit-rev-format "%s" push) ""))
- (insert (propertize "is missing" 'face 'font-lock-warning-face)))
- (insert ?\n))))
-
-(defun magit-insert-tags-header ()
- "Insert a header line about the current and/or next tag."
- (let* ((this-tag (magit-get-current-tag nil t))
- (next-tag (magit-get-next-tag nil t))
- (this-cnt (cadr this-tag))
- (next-cnt (cadr next-tag))
- (this-tag (car this-tag))
- (next-tag (car next-tag))
- (both-tags (and this-tag next-tag t)))
- (when (or this-tag next-tag)
- (magit-insert-section (tag (or this-tag next-tag))
- (insert (format "%-10s" (if both-tags "Tags: " "Tag: ")))
- (when this-tag
- (insert (magit-format-status-tag-sentence this-tag this-cnt nil)))
- (when both-tags
- (insert ", "))
- (when next-tag
- (insert (magit-format-status-tag-sentence next-tag next-cnt t)))
- (insert ?\n)))))
-
-(defun magit-format-status-tag-sentence (tag count next)
- (concat (propertize tag 'face 'magit-tag)
- (and (> count 0)
- (format " (%s)"
- (propertize (format "%s" count) 'face
- (if next 'magit-tag 'magit-branch-local))))))
-
-(defun magit-insert-diff-filter-header ()
- "Insert a header line showing the effective diff filters."
- (when magit-diff-section-file-args
- (magit-insert-section (filter 'diff)
- (insert (propertize (format "%-10s" "Filter! ")
- 'face 'magit-section-heading))
- (insert (mapconcat #'identity magit-diff-section-file-args " "))
- (insert ?\n))))
-
-(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked)
-
-(defvar magit-untracked-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map "s" 'magit-stage)
- map)
- "Keymap for the `untracked' section.")
-
-(defun magit-insert-untracked-files ()
- "Maybe insert a list or tree of untracked files.
-Do so depending on the value of `status.showUntrackedFiles'."
- (let ((show (or (magit-get "status.showUntrackedFiles") "normal")))
- (unless (equal show "no")
- (if (equal show "all")
- (-when-let (files (magit-untracked-files))
- (magit-insert-section (untracked)
- (magit-insert-heading "Untracked files:")
- (magit-insert-un/tracked-files-1 files nil)
- (insert ?\n)))
- (-when-let
- (files (--mapcat (and (eq (aref it 0) ??)
- (list (substring it 3)))
- (magit-git-items "status" "-z" "--porcelain")))
- (magit-insert-section (untracked)
- (magit-insert-heading "Untracked files:")
- (dolist (file files)
- (magit-insert-section (file file)
- (insert (propertize file 'face 'magit-filename) ?\n))))
- (insert ?\n))))))
-
-(defun magit-insert-un/tracked-files-1 (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 'face 'magit-filename) ?\n)))
- (magit-insert-section (file dir t)
- (insert (propertize dir 'file 'magit-filename) ?\n)
- (magit-insert-heading)
- (setq files (magit-insert-un/tracked-files-1 files dir))))))
- files)
-
-;;;;; Auxiliary Status Sections
-
-(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked)
-
-(defun magit-insert-tracked-files ()
- "Insert a tree of tracked files."
- (-when-let (files (magit-list-files))
- (magit-insert-section (tracked nil t)
- (magit-insert-heading "Tracked files:")
- (magit-insert-un/tracked-files-1 files nil)
- (insert ?\n))))
-
-(defun magit-insert-user-header ()
- "Insert a header line about the current user."
- (let ((name (magit-get "user.name"))
- (email (magit-get "user.email")))
- (when (and name email)
- (magit-insert-section (user name)
- (insert (format "%-10s" "User: "))
- (insert (propertize name 'face 'magit-log-author))
- (insert " <" email ">\n")))))
-
-(defun magit-insert-repo-header ()
- "Insert a header line showing the path to the repository top-level."
- (let ((topdir (magit-toplevel)))
- (magit-insert-section (repo topdir)
- (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir))))))
-
-(defun magit-insert-remote-header ()
- "Insert a header line about the remote of the current branch.
-
-If no remote is configured for the current branch, then fall back
-showing the \"origin\" remote, or if that does not exist the first
-remote in alphabetic order."
- (--when-let (or (magit-get-remote)
- (let ((remotes (magit-list-remotes)))
- (or (car (member "origin" remotes))
- (car remotes))))
- (magit-insert-section (remote it)
- (insert (format "%-10s" "Remote: "))
- (insert (propertize it 'face 'magit-branch-remote) ?\s)
- (insert (magit-get "remote" it "url") ?\n))))
-
-;;;;; Status Miscellaneous
-
-(defun ido-enter-magit-status ()
- "Drop into `magit-status' from file switching.
-
-To make this command available use something like:
-
- (add-hook \\='ido-setup-hook
- (lambda ()
- (define-key ido-completion-map
- (kbd \"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:
-
- (define-key ido-common-completion-map
- (kbd \"C-x g\") 'ido-enter-magit-status)"
- (interactive)
- (with-no-warnings ; FIXME these are internal variables
- (setq ido-exit 'fallback fallback 'magit-status))
- (exit-minibuffer))
-
-(defun magit-status-maybe-update-revision-buffer (&optional _)
- "When moving in the status buffer, update the revision buffer.
-If there is no revision buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-status-mode)
- (magit-log-maybe-update-revision-buffer-1)))
-
-(defun magit-status-maybe-update-blob-buffer (&optional _)
- "When moving in the status buffer, update the blob buffer.
-If there is no blob buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-status-mode)
- (magit-log-maybe-update-blob-buffer-1)))
-
-;;;; Refs Mode
-
-(defvar magit-refs-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-y" 'magit-refs-set-show-commit-count)
- map)
- "Keymap for `magit-refs-mode'.")
-
-(define-derived-mode magit-refs-mode magit-mode "Magit Refs"
- "Mode which lists and compares references.
-
-This mode is documented in info node `(magit)References buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit or branch at point.
-
-Type \\[magit-branch-popup] to see available branch commands.
-Type \\[magit-merge-popup] to merge the branch or commit at point.
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-Type \\[magit-reset] to reset HEAD to the commit at point.
-
-\\{magit-refs-mode-map}"
- :group 'magit-refs
- (hack-dir-local-variables-non-file-buffer))
-
-;;;###autoload (autoload 'magit-show-refs-popup "magit" nil t)
-(magit-define-popup magit-show-refs-popup
- "Popup console for `magit-show-refs'."
- 'magit-refs
- :man-page "git-branch"
- :switches '((?m "Merged to HEAD" "--merged")
- (?M "Merged to master" "--merged=master")
- (?n "Not merged to HEAD" "--no-merged")
- (?N "Not merged to master" "--no-merged=master"))
- :options '((?c "Contains" "--contains=" magit-read-branch-or-commit)
- (?m "Merged" "--merged=" magit-read-branch-or-commit)
- (?n "Not merged" "--no-merged=" magit-read-branch-or-commit))
- :actions '((?y "Show refs, comparing them with HEAD"
- magit-show-refs-head)
- (?c "Show refs, comparing them with current branch"
- magit-show-refs-current)
- (?o "Show refs, comparing them with other branch"
- magit-show-refs))
- :default-action 'magit-show-refs-head
- :use-prefix 'popup)
-
-;;;###autoload
-(defun magit-show-refs-head (&optional args)
- "List and compare references in a dedicated buffer.
-Refs are compared with `HEAD'."
- (interactive (list (magit-show-refs-arguments)))
- (magit-show-refs nil args))
-
-;;;###autoload
-(defun magit-show-refs-current (&optional args)
- "List and compare references in a dedicated buffer.
-Refs are compared with the current branch or `HEAD' if
-it is detached."
- (interactive (list (magit-show-refs-arguments)))
- (magit-show-refs (magit-get-current-branch) args))
-
-;;;###autoload
-(defun magit-show-refs (&optional ref args)
- "List and compare references in a dedicated buffer.
-Refs are compared with a branch read form the user."
- (interactive (list (magit-read-other-branch "Compare with")
- (magit-show-refs-arguments)))
- (magit-mode-setup #'magit-refs-mode ref args))
-
-(defun magit-refs-refresh-buffer (&rest _ignore)
- (setq magit-set-buffer-margin-refresh (not magit-show-margin))
- (unless (magit-rev-verify (or (car magit-refresh-args) "HEAD"))
- (setq magit-refs-show-commit-count nil))
- (magit-insert-section (branchbuf)
- (run-hooks 'magit-refs-sections-hook)))
-
-(defun magit-insert-branch-description ()
- "Insert header containing the description of the current branch.
-Insert a header line with the name and description of the
-current branch. The description is taken from the Git variable
-`branch.<NAME>.description'; if that is undefined then no header
-line is inserted at all."
- (let ((branch (magit-get-current-branch)))
- (--when-let (magit-git-lines
- "config" (format "branch.%s.description" branch))
- (magit-insert-section (branchdesc branch t)
- (magit-insert-heading branch ": " (car it))
- (insert (mapconcat 'identity (cdr it) "\n"))
- (insert "\n\n")))))
-
-(defconst magit-refs-branch-line-re
- (concat "^"
- "\\(?:[ \\*]\\) "
- "\\(?1:([^)]+)\\|[^ ]+?\\)" ; branch
- "\\(?: +\\)"
- "\\(?2:[0-9a-fA-F]+\\) " ; sha1
- "\\(?:\\["
- "\\(?4:[^:]+\\)" ; upstream
- "\\(?:: \\(?:"
- "\\(?7:gone\\)\\|" ; gone
- "\\(?:ahead \\(?5:[0-9]+\\)\\)?" ; ahead
- "\\(?:, \\)?"
- "\\(?:behind \\(?6:[0-9]+\\)\\)?" ; behind
- "\\)\\)?"
- "\\] \\)?"
- "\\(?3:.*\\)")) ; message
-
-(defvar magit-refs-local-branch-format "%4c %-25n %U%m\n"
- "Format used for local branches in refs buffers.")
-(defvar magit-refs-remote-branch-format "%4c %-25n %m\n"
- "Format used for remote branches in refs buffers.")
-(defvar magit-refs-tags-format "%4c %-25n %m\n"
- "Format used for tags in refs buffers.")
-(defvar magit-refs-indent-cherry-lines 3
- "Indentation of cherries in refs buffers.")
-
-(defvar magit-branch-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-visit-ref)
- (define-key map [remap magit-delete-thing] 'magit-branch-delete)
- (define-key map "R" 'magit-branch-rename)
- map)
- "Keymap for `branch' sections.")
-
-(defvar magit-remote-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-remote-remove)
- (define-key map "R" 'magit-remote-rename)
- map)
- "Keymap for `remote' sections.")
-
-(defun magit-refs-set-show-commit-count ()
- "Change for which refs the commit count is shown."
- (interactive)
- (setq-local magit-refs-show-commit-count
- (magit-read-char-case "Show commit counts for " nil
- (?a "[a]ll refs" 'all)
- (?b "[b]ranches only" t)
- (?n "[n]othing" nil)))
- (magit-refresh))
-
-(defun magit-visit-ref ()
- "Visit the reference or revision at point.
-
-In most places use `magit-show-commit' to visit the reference or
-revision at point.
-
-In `magit-refs-mode', when there is a reference at point, instead
-checkout that reference. When option `magit-visit-ref-create' is
-non-nil and point is on remote branch, then create a local branch
-with the same name and check it out.
-
-With a prefix argument only focus on the reference at point, i.e.
-the commit counts and cherries are updated to be relative to that
-reference, but it is not checked out."
- (interactive)
- (if (derived-mode-p 'magit-refs-mode)
- (magit-section-case
- (([branch * branchbuf]
- [tag * branchbuf])
- (let ((ref (magit-section-value (magit-current-section))))
- (if current-prefix-arg
- (magit-show-refs ref)
- (if (magit-section-when [branch remote])
- (let ((start ref)
- (arg "-b"))
- (string-match "^[^/]+/\\(.+\\)" ref)
- (setq ref (match-string 1 ref))
- (when (magit-branch-p ref)
- (if (yes-or-no-p
- (format "Branch %s already exists. Recreate it?" ref))
- (setq arg "-B")
- (user-error "Abort")))
- (magit-run-git "checkout" arg ref start))
- (magit-run-git "checkout" ref))
- (setcar magit-refresh-args ref)
- (magit-refresh))))
- ([commit * branchbuf]
- (call-interactively #'magit-show-commit)))
- (call-interactively #'magit-show-commit)))
-
-(defun magit-insert-local-branches ()
- "Insert sections showing all local branches."
- (magit-insert-section (local nil)
- (magit-insert-heading "Branches:")
- (let ((current (magit-get-current-branch))
- (branches (magit-list-local-branch-names)))
- (dolist (line (magit-git-lines "branch" "-vv"
- (cadr magit-refresh-args)))
- (string-match magit-refs-branch-line-re line)
- (magit-bind-match-strings
- (branch hash message upstream ahead behind gone) line
- (when (string-match-p "(HEAD detached" branch)
- (setq branch nil))
- (magit-insert-branch
- branch magit-refs-local-branch-format current branches
- 'magit-branch-local hash message upstream ahead behind gone))))
- (insert ?\n)))
-
-(defun magit-insert-remote-branches ()
- "Insert sections showing all remote-tracking branches."
- (dolist (remote (magit-list-remotes))
- (magit-insert-section (remote remote)
- (magit-insert-heading
- (let ((pull (magit-get "remote" remote "url"))
- (push (magit-get "remote" remote "pushurl")))
- (format "%s (%s):" (capitalize remote)
- (concat pull (and pull push ", ") push))))
- (let ((current (magit-get-current-branch))
- (branches (magit-list-local-branch-names)))
- (dolist (line (magit-git-lines "branch" "-vvr"
- (cadr magit-refresh-args)))
- (when (string-match magit-refs-branch-line-re line)
- (magit-bind-match-strings (branch hash message) line
- (when (string-match-p (format "^%s/" remote) branch)
- (magit-insert-branch
- branch magit-refs-remote-branch-format current branches
- 'magit-branch-remote hash message))))))
- (insert ?\n))))
-
-(defun magit-insert-branch (branch format &rest args)
- "For internal use, don't add to a hook."
- (unless magit-refs-show-commit-count
- (setq format (replace-regexp-in-string "%[0-9]\\([cC]\\)" "%1\\1" format t)))
- (if (equal branch "HEAD")
- (magit-insert-section it (commit (magit-rev-parse "HEAD") t)
- (apply #'magit-insert-branch-1 it nil format args))
- (magit-insert-section it (branch branch t)
- (apply #'magit-insert-branch-1 it branch format args))))
-
-(defun magit-insert-branch-1
- (section branch format current branches face
- &optional hash message upstream ahead behind gone)
- "For internal use, don't add to a hook."
- (let* ((head (or (car magit-refresh-args) current "HEAD"))
- (count (and branch
- (magit-refs-format-commit-count branch head format)))
- (mark (cond ((or (equal branch head)
- (and (not branch) (equal head "HEAD")))
- (if (equal branch current)
- (propertize "@" 'face 'magit-head)
- (propertize "#" 'face 'magit-tag)))
- ((equal branch current)
- (propertize "." 'face 'magit-head)))))
- (when upstream
- (setq upstream (propertize upstream 'face
- (if (member upstream branches)
- 'magit-branch-local
- 'magit-branch-remote))))
- (magit-insert-heading
- (format-spec
- format
- `((?a . ,(or ahead ""))
- (?b . ,(or behind ""))
- (?c . ,(or mark count ""))
- (?C . ,(or mark " "))
- (?h . ,(or (propertize hash 'face 'magit-hash) ""))
- (?m . ,(or message ""))
- (?n . ,(propertize (or branch "(detached)") 'face face))
- (?u . ,(or upstream ""))
- (?U . ,(if upstream
- (format (propertize "[%s%s] " 'face 'magit-dimmed)
- upstream
- (cond
- (gone
- (concat ": " (propertize gone 'face 'error)))
- ((or ahead behind)
- (concat ": "
- (and ahead (format "ahead %s" ahead))
- (and ahead behind ", ")
- (and behind (format "behind %s" behind))))
- (t "")))
- "")))))
- (when magit-show-margin
- (magit-refs-format-margin branch))
- (magit-refs-insert-cherry-commits head branch section)))
-
-(defvar magit-tag-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-visit-ref)
- (define-key map [remap magit-delete-thing] 'magit-tag-delete)
- map)
- "Keymap for `tag' sections.")
-
-(defun magit-insert-tags ()
- "Insert sections showing all tags."
- (-when-let (tags (magit-git-lines "tag" "-l" "-n"))
- (magit-insert-section (tags)
- (magit-insert-heading "Tags:")
- (let ((head (or (car magit-refresh-args)
- (magit-get-current-branch)
- "HEAD"))
- (format (if magit-refs-show-commit-count
- magit-refs-tags-format
- (replace-regexp-in-string
- "%[0-9]\\([cC]\\)" "%1\\1" magit-refs-tags-format t))))
- (dolist (tag (nreverse tags))
- (string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag)
- (let* ((message (match-string 2 tag))
- (tag (match-string 1 tag))
- (count (magit-refs-format-commit-count tag head format t))
- (mark (and (equal tag head)
- (propertize "#" 'face 'magit-tag))))
- (magit-insert-section section (tag tag t)
- (magit-insert-heading
- (format-spec format
- `((?n . ,(propertize tag 'face 'magit-tag))
- (?c . ,(or mark count ""))
- (?m . ,(or message "")))))
- (when (and magit-show-margin
- (eq magit-refs-show-margin 'all))
- (magit-refs-format-margin (concat tag "^{commit}")))
- (magit-refs-insert-cherry-commits head tag section)))))
- (insert ?\n))))
-
-(defun magit-refs-insert-cherry-commits (head ref section)
- (if (magit-section-hidden section)
- (setf (magit-section-washer section)
- (apply-partially #'magit-refs-insert-cherry-commits-1
- head ref section))
- (magit-refs-insert-cherry-commits-1 head ref section)))
-
-(defun magit-refs-insert-cherry-commits-1 (head ref section)
- (let ((start (point)))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" "--abbrev" head ref magit-refresh-args)
- (unless (= (point) start)
- (insert (propertize "\n" 'magit-section section)))))
-
-(defun magit-refs-format-commit-count (ref head format &optional tag-p)
- (and (string-match-p "%-?[0-9]+c" format)
- (if tag-p
- (eq magit-refs-show-commit-count 'all)
- magit-refs-show-commit-count)
- (let ((count (cadr (magit-rev-diff-count head ref))))
- (and (> count 0)
- (propertize (number-to-string count) 'face 'magit-dimmed)))))
-
-(defun magit-refs-format-margin (commit)
- (save-excursion
- (goto-char (line-beginning-position 0))
- (let ((line (magit-rev-format "%ct%cN" commit)))
- (magit-format-log-margin (substring line 10)
- (substring line 0 10)))))
-
-;;;; Files
-
-;;;###autoload
-(defun magit-find-file (rev file)
- "View FILE from REV.
-Switch to a buffer visiting blob REV:FILE,
-creating one if none already exists."
- (interactive (magit-find-file-read-args "Find file"))
- (switch-to-buffer (magit-find-file-noselect rev file)))
-
-;;;###autoload
-(defun magit-find-file-other-window (rev file)
- "View FILE from REV, in another window.
-Like `magit-find-file', but create a new window or reuse an
-existing one."
- (interactive (magit-find-file-read-args "Find file in other window"))
- (switch-to-buffer-other-window (magit-find-file-noselect rev file)))
-
-(defun magit-find-file-read-args (prompt)
- (let ((rev (magit-read-branch-or-commit "Find file from revision")))
- (list rev (magit-read-file-from-rev rev prompt))))
-
-(defvar magit-read-file-hist nil)
-
-(defun magit-read-file-from-rev (rev prompt &optional default)
- (let ((files (magit-revision-files rev)))
- (magit-completing-read
- prompt files nil t nil 'magit-read-file-hist
- (car (member (or default (magit-current-file)) files)))))
-
-(defun magit-read-changed-file (rev-or-range prompt &optional default)
- (magit-read-file-choice
- prompt
- (magit-changed-files rev-or-range)
- default
- (concat "No file changed in " rev-or-range)))
-
-(defun magit-get-revision-buffer (rev file &optional create)
- (funcall (if create 'get-buffer-create 'get-buffer)
- (format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev))))
-
-(defun magit-get-revision-buffer-create (rev file)
- (magit-get-revision-buffer rev file t))
-
-(defvar magit-find-file-hook nil)
-
-(defun magit-find-file-noselect (rev file)
- "Read FILE from REV into a buffer and return the buffer.
-FILE must be relative to the top directory of the repository."
- (let ((topdir (magit-toplevel)))
- (when (file-name-absolute-p file)
- (setq file (file-relative-name file topdir)))
- (or (magit-get-revision-buffer rev file)
- (with-current-buffer (magit-get-revision-buffer-create rev file)
- (let ((inhibit-read-only t))
- (erase-buffer)
- (magit-git-insert "cat-file" "-p" (concat rev ":" file)))
- (setq magit-buffer-revision (magit-rev-format "%H" rev)
- magit-buffer-refname rev
- magit-buffer-file-name (expand-file-name file topdir))
- (let ((buffer-file-name magit-buffer-file-name))
- (normal-mode t))
- (setq buffer-read-only t)
- (set-buffer-modified-p nil)
- (goto-char (point-min))
- (magit-blob-mode 1)
- (run-hooks 'magit-find-file-hook)
- (current-buffer)))))
-
-(defvar magit-find-index-hook nil)
-
-(defun magit-find-file-index-noselect (file &optional revert)
- "Read FILE from the index into a buffer and return the buffer.
-FILE must to be relative to the top directory of the repository."
- (let* ((bufname (concat file ".~{index}~"))
- (origbuf (get-buffer bufname))
- (default-directory (magit-toplevel)))
- (with-current-buffer (get-buffer-create bufname)
- (when (or (not origbuf) revert
- (y-or-n-p (format "%s already exists; revert it? " bufname)))
- (let ((inhibit-read-only t)
- (temp (car (split-string
- (or (magit-git-string "checkout-index" "--temp" file)
- (error "Error making temp file"))
- "\t"))))
- (erase-buffer)
- (insert-file-contents temp nil nil nil t)
- (delete-file temp)))
- (setq magit-buffer-revision "{index}"
- magit-buffer-refname "{index}"
- magit-buffer-file-name (expand-file-name file))
- (let ((buffer-file-name magit-buffer-file-name))
- (normal-mode t))
- (setq buffer-read-only t)
- (set-buffer-modified-p nil)
- (goto-char (point-min))
- (run-hooks 'magit-find-index-hook)
- (current-buffer))))
-
-(defun magit-update-index ()
- "Update the index with the contents of the current buffer.
-The current buffer has to be visiting a file in the index, which
-is done using `magit-find-index-noselect'."
- (interactive)
- (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)))
- (let ((index (make-temp-file "index"))
- (buffer (current-buffer)))
- (when magit-wip-before-change-mode
- (magit-wip-commit-before-change (list file) " before un-/stage"))
- (with-temp-file index
- (insert-buffer-substring buffer))
- (magit-call-git "update-index" "--cacheinfo"
- (substring (magit-git-string "ls-files" "-s" file) 0 6)
- (magit-git-string "hash-object" "-t" "blob" "-w"
- (concat "--path=" file)
- "--" index)
- file)
- (set-buffer-modified-p nil)
- (when magit-wip-after-apply-mode
- (magit-wip-commit-after-apply (list file) " after un-/stage")))
- (message "Abort")))
- (--when-let (magit-mode-get-buffer 'magit-status-mode)
- (with-current-buffer it (magit-refresh)))
- t)
-
-;;;###autoload
-(defun magit-dired-jump (&optional other-window)
- "Visit file at point using Dired.
-With a prefix argument, visit in other window. If there
-is no file at point then instead visit `default-directory'."
- (interactive "P")
- (dired-jump other-window (--if-let (magit-file-at-point)
- (expand-file-name it)
- default-directory)))
-
-;;;###autoload
-(defun magit-checkout-file (rev file)
- "Checkout FILE from REV."
- (interactive
- (let ((rev (magit-read-branch-or-commit
- "Checkout from revision" magit-buffer-revision)))
- (list rev (magit-read-file-from-rev rev "Checkout file"))))
- (magit-with-toplevel
- (magit-run-git "checkout" rev "--" file)))
-
-;;; Manipulate
-;;;; Init
-
-;;;###autoload
-(defun magit-init (directory)
- "Initialize a Git repository, then show its status.
-
-If the directory is below an existing repository, then the user
-has to confirm that a new one should be created inside. If the
-directory is the root of the existing repository, then the user
-has to confirm that it should be reinitialized.
-
-Non-interactively DIRECTORY is (re-)initialized unconditionally."
- (interactive
- (let ((directory (file-name-as-directory
- (expand-file-name
- (read-directory-name "Create repository in: ")))))
- (-when-let (toplevel (magit-toplevel directory))
- (setq toplevel (expand-file-name toplevel))
- (unless (y-or-n-p (if (string-equal toplevel directory)
- (format "Reinitialize existing repository %s? "
- directory)
- (format "%s is a repository. Create another in %s? "
- toplevel directory)))
- (user-error "Abort")))
- (list directory)))
- ;; `git init' does not understand the meaning of "~"!
- (magit-call-git "init" (magit-convert-git-filename
- (expand-file-name directory)))
- (magit-status-internal directory))
-
-;;;; Branch
-;;;;; Branch Popup
-
-;;;###autoload (autoload 'magit-branch-popup "magit" nil t)
-(magit-define-popup magit-branch-popup
- "Popup console for branch commands."
- 'magit-commands
- :man-page "git-branch"
- :variables '("Configure existing branches"
- (?d "branch.%s.description"
- magit-edit-branch*description
- magit-format-branch*description)
- (?u "branch.%s.merge"
- magit-set-branch*merge/remote
- magit-format-branch*merge/remote)
- (?r "branch.%s.rebase"
- magit-cycle-branch*rebase
- magit-format-branch*rebase)
- (?p "branch.%s.pushRemote"
- magit-cycle-branch*pushRemote
- magit-format-branch*pushRemote)
- "Configure repository defaults"
- (?\M-r "pull.rebase"
- magit-cycle-pull.rebase
- magit-format-pull.rebase)
- (?\M-p "remote.pushDefault"
- magit-cycle-remote.pushDefault
- magit-format-remote.pushDefault)
- "Configure branch creation"
- (?U "branch.autoSetupMerge"
- magit-cycle-branch*autoSetupMerge
- magit-format-branch*autoSetupMerge)
- (?R "branch.autoSetupRebase"
- magit-cycle-branch*autoSetupRebase
- magit-format-branch*autoSetupRebase))
- :actions '((?c "Create and checkout" magit-branch-and-checkout)
- (?b "Checkout" magit-checkout)
- (?n "Create" magit-branch)
- (?m "Rename" magit-branch-rename)
- (?s "Create spin-off" magit-branch-spinoff)
- (?x "Reset" magit-branch-reset) nil
- (?k "Delete" magit-branch-delete))
- :default-action 'magit-checkout
- :max-action-columns 2
- :setup-function 'magit-branch-popup-setup)
-
-(defun magit-branch-popup-setup (val def)
- (magit-popup-default-setup val def)
- (use-local-map (copy-keymap magit-popup-mode-map))
- (dolist (ev (-filter #'magit-popup-event-p (magit-popup-get :variables)))
- (local-set-key (vector (magit-popup-event-key ev))
- 'magit-invoke-popup-action)))
-
-;;;;; Branch Actions
-
-;;;###autoload
-(defun magit-checkout (revision)
- "Checkout REVISION, updating the index and the working tree.
-If REVISION is a local branch then that becomes the current
-branch. If it is something else then `HEAD' becomes detached.
-Checkout fails if the working tree or the staging area contain
-changes.
-\n(git checkout REVISION)."
- (interactive (list (magit-read-other-branch-or-commit "Checkout")))
- (magit-run-git "checkout" revision))
-
-;;;###autoload
-(defun magit-branch (branch start-point &optional args)
- "Create BRANCH at branch or revision START-POINT.
-\n(git branch [ARGS] BRANCH START-POINT)."
- (interactive (magit-branch-read-args "Create branch"))
- (magit-call-git "branch" args branch start-point)
- (--when-let (and (magit-get-upstream-branch branch)
- (magit-get-indirect-upstream-branch start-point))
- (magit-call-git "branch" (concat "--set-upstream-to=" it) branch))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-branch-and-checkout (branch start-point &optional args)
- "Create and checkout BRANCH at branch or revision START-POINT.
-\n(git checkout [ARGS] -b BRANCH START-POINT)."
- (interactive (magit-branch-read-args "Create and checkout branch"))
- (if (string-match-p "^stash@{[0-9]+}$" start-point)
- (magit-run-git "stash" "branch" branch start-point)
- (magit-call-git "checkout" args "-b" branch start-point)
- (--when-let (and (magit-get-upstream-branch branch)
- (magit-get-indirect-upstream-branch start-point))
- (magit-call-git "branch" (concat "--set-upstream-to=" it) branch))
- (magit-refresh)))
-
-(defun magit-branch-read-args (prompt)
- (let ((args (magit-branch-arguments)) start branch)
- (cond (magit-branch-read-upstream-first
- (setq start (magit-read-starting-point prompt))
- (setq branch (magit-read-string-ns
- "Branch name"
- (and (member start (magit-list-remote-branch-names))
- (mapconcat #'identity
- (cdr (split-string start "/"))
- "/")))))
- (t
- (setq branch (magit-read-string-ns "Branch name"))
- (setq start (magit-read-starting-point prompt))))
- (list branch start args)))
-
-;;;###autoload
-(defun magit-branch-spinoff (branch &rest args)
- "Create new branch from the unpushed commits.
-
-Create and checkout a new branch starting at and tracking the
-current branch. That branch in turn is reset to the last commit
-it shares with its upstream. If the current branch has no
-upstream or no unpushed commits, then the new branch is created
-anyway and the previously current branch is not touched.
-
-This is useful to create a feature branch after work has already
-began on the old branch (likely but not necessarily \"master\").
-
-If the current branch is a member of the value of option
-`magit-branch-prefer-remote-upstream' (which see), then the
-current branch will be used as the starting point as usual, but
-the upstream of the starting-point may be used as the upstream
-of the new branch, instead of the starting-point itself."
- (interactive (list (magit-read-string "Spin off branch")
- (magit-branch-arguments)))
- (when (magit-branch-p branch)
- (user-error "Branch %s already exists" branch))
- (-if-let (current (magit-get-current-branch))
- (let (tracked base)
- (magit-call-git "checkout" args "-b" branch current)
- (--when-let (magit-get-indirect-upstream-branch current)
- (magit-call-git "branch" "--set-upstream-to" it branch))
- (when (and (setq tracked (magit-get-upstream-branch current))
- (setq base (magit-git-string "merge-base" current tracked))
- (not (magit-rev-eq base current)))
- (magit-call-git "update-ref" "-m"
- (format "reset: moving to %s" base)
- (concat "refs/heads/" current) base))
- (magit-refresh))
- (magit-run-git "checkout" "-b" branch)))
-
-;;;###autoload
-(defun magit-branch-reset (branch to &optional args set-upstream)
- "Reset a branch to the tip of another branch or any other commit.
-
-When the branch being reset is the current branch, then do a
-hard reset. If there are any uncommitted changes, then the user
-has to confirming the reset because those changes would be lost.
-
-This is useful when you have started work on a feature branch but
-realize it's all crap and want to start over.
-
-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-branch-at-point))
- (branch (magit-read-local-branch "Reset branch" atpoint)))
- (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-branch-arguments)
- current-prefix-arg)))
- (unless (member "--force" args)
- (setq args (cons "--force" args)))
- (if (equal branch (magit-get-current-branch))
- (if (and (magit-anything-modified-p)
- (not (yes-or-no-p "Uncommitted changes will be lost. Proceed?")))
- (user-error "Abort")
- (magit-reset-hard to)
- (when (and set-upstream (magit-branch-p to))
- (magit-set-branch*merge/remote branch to)))
- (magit-branch branch to args)))
-
-;;;###autoload
-(defun magit-branch-delete (branches &optional force)
- "Delete one or multiple branches.
-If the region marks multiple branches, then offer to delete
-those, otherwise prompt for a single branch to be deleted,
-defaulting to the branch at point."
- (interactive
- (let ((branches (magit-region-values 'branch))
- (force current-prefix-arg))
- (if (if (> (length branches) 1)
- (magit-confirm t nil "Delete %i branches" branches)
- (setq branches
- (list (magit-read-branch (if current-prefix-arg
- "Force delete branch"
- "Delete branch")
- (magit-get-previous-branch)))))
- (unless force
- (--when-let (-intersection
- (-union (magit-list-unmerged-branches)
- (magit-list-unmerged-to-upstream-branches))
- branches)
- (if (magit-confirm 'delete-unmerged-branch
- "Delete unmerged branch %s"
- "Delete %i unmerged branches" it)
- (setq force t)
- (or (setq branches (-difference branches it))
- (user-error "Abort")))))
- (user-error "Abort"))
- (list branches force)))
- (let* ((refs (-map #'magit-ref-fullname branches))
- (ambiguous (--filter (not it) refs)))
- (when ambiguous
- (user-error
- "%s ambiguous. Please cleanup using git directly."
- (let ((len (length ambiguous)))
- (cond
- ((= len 1)
- (format "%s is" (--first (not (magit-ref-fullname it)) branches)))
- ((= len (length refs))
- (format "These %s names are" len))
- (t
- (format "%s of these names are" len))))))
- (cond
- ((string-match "^refs/remotes/\\([^/]+\\)" (car refs))
- (let* ((remote (match-string 1 (car refs)))
- (offset (1+ (length remote))))
- (magit-run-git-async
- "push" remote (--map (concat ":" (substring it offset)) branches))))
- ((> (length branches) 1)
- (magit-run-git "branch" (if force "-D" "-d")
- (delete (magit-get-current-branch) branches)))
- (t ; And now for something completely different.
- (let* ((branch (car branches))
- (prompt (format "Branch %s is checked out. " branch)))
- (when (equal branch (magit-get-current-branch))
- (pcase (if (or (equal branch "master")
- (not (magit-rev-verify "master")))
- (magit-read-char-case prompt nil
- (?d "[d]etach HEAD & delete" 'detach)
- (?a "[a]bort" 'abort))
- (magit-read-char-case prompt nil
- (?d "[d]etach HEAD & delete" 'detach)
- (?c "[c]heckout master & delete" 'master)
- (?a "[a]bort" 'abort)))
- (`detach (magit-call-git "checkout" "--detach"))
- (`master (magit-call-git "checkout" "master"))
- (`abort (user-error "Abort")))
- (setq force t))
- (magit-run-git "branch" (if force "-D" "-d") branch))))))
-
-(put 'magit-branch-delete 'interactive-only t)
-
-;;;###autoload
-(defun magit-branch-rename (old new &optional force)
- "Rename branch OLD to NEW.
-With prefix, forces the rename even if NEW already exists.
-\n(git branch -m|-M OLD NEW)."
- (interactive
- (let ((branch (magit-read-local-branch "Rename branch")))
- (list branch
- (magit-read-string-ns (format "Rename branch '%s' to" branch))
- current-prefix-arg)))
- (unless (string= old new)
- (magit-run-git "branch" (if force "-M" "-m") old new)))
-
-;;;;; Branch Variables
-
-;;;###autoload
-(defun magit-edit-branch*description (branch)
- "Edit the description of the current branch.
-With a prefix argument edit the description of another branch.
-
-The description for the branch named NAME is stored in the Git
-variable `branch.<name>.description'."
- (interactive
- (list (or (and (not current-prefix-arg)
- (magit-get-current-branch))
- (magit-read-local-branch "Edit branch description"))))
- (magit-run-git-with-editor "branch" "--edit-description" branch))
-
-(defun magit-edit-branch*description-check-buffers ()
- (and buffer-file-name
- (string-match-p "/BRANCH_DESCRIPTION\\'" buffer-file-name)
- (add-hook 'with-editor-post-finish-hook
- (lambda ()
- (when (derived-mode-p 'magit-popup-mode)
- (magit-refresh-popup-buffer)))
- nil t)))
-
-(add-hook 'find-file-hook 'magit-edit-branch*description-check-buffers)
-
-(defun magit-format-branch*description ()
- (let* ((branch (or (magit-get-current-branch) "<name>"))
- (width (+ (length branch) 19))
- (var (format "branch.%s.description" branch)))
- (concat var " " (make-string (- width (length var)) ?\s)
- (-if-let (value (magit-get var))
- (propertize value 'face 'magit-popup-option-value)
- (propertize "unset" 'face 'magit-popup-disabled-argument)))))
-
-;;;###autoload
-(defun magit-set-branch*merge/remote (branch upstream)
- "Set or unset the upstream of the current branch.
-With a prefix argument do so for another branch.
-
-When the branch in question already has an upstream then simply
-unsets it. Invoke this command again to set another upstream.
-
-Together the Git variables `branch.<name>.remote' and
-`branch.<name>.merge' define the upstream branch of the local
-branch named NAME. The value of `branch.<name>.remote' is the
-name of the upstream remote. The value of `branch.<name>.merge'
-is the full reference of the upstream branch, on the remote.
-
-Non-interactively, when UPSTREAM is non-nil, then always set it
-as the new upstream, regardless of whether another upstream was
-already set. When nil, then always unset."
- (interactive
- (let ((branch (or (and (not current-prefix-arg)
- (magit-get-current-branch))
- (magit-read-local-branch "Change upstream of branch"))))
- (list branch (and (not (magit-get-upstream-branch branch))
- (magit-read-upstream-branch)))))
- (if upstream
- (-let (((remote . merge) (magit-split-branch-name upstream))
- (branch (magit-get-current-branch)))
- (magit-call-git "config" (format "branch.%s.remote" branch) remote)
- (magit-call-git "config" (format "branch.%s.merge" branch)
- (concat "refs/heads/" merge)))
- (magit-call-git "branch" "--unset-upstream" branch))
- (when (called-interactively-p 'any)
- (magit-refresh)))
-
-(defun magit-format-branch*merge/remote ()
- (let* ((branch (or (magit-get-current-branch) "<name>"))
- (width (+ (length branch) 20))
- (varM (format "branch.%s.merge" branch))
- (varR (format "branch.%s.remote" branch))
- (face (if (equal (magit-get varR) ".")
- 'magit-branch-local
- 'magit-branch-remote)))
- (concat varM (make-string (- width (length varM)) ?\s)
- (-if-let (value (magit-get varM))
- (propertize value 'face face)
- (propertize "unset" 'face 'magit-popup-disabled-argument))
- "\n " varR (make-string (- width (length varR)) ?\s)
- (-if-let (value (magit-get varR))
- (propertize value 'face face)
- (propertize "unset" 'face 'magit-popup-disabled-argument)))))
-
-;;;###autoload
-(defun magit-cycle-branch*rebase (branch)
- "Cycle the value of `branch.<name>.rebase' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variables `branch.<name>.rebase' controls whether pulling
-into the branch named NAME is done by rebasing that branch onto
-the fetched branch or by merging that branch.
-
-When `true' then pulling is done by rebasing.
-When `false' then pulling is done by merging.
-
-When that variable is undefined then the value of `pull.rebase'
-is used instead. It defaults to `false'."
- (interactive
- (list (or (and (not current-prefix-arg)
- (magit-get-current-branch))
- (magit-read-local-branch "Cycle branch.<name>.rebase for"))))
- (magit-popup-set-variable (format "branch.%s.rebase" branch)
- '("true" "false")
- "false" "pull.rebase"))
-
-(defun magit-format-branch*rebase ()
- (let ((branch (or (magit-get-current-branch) "<name>")))
- (magit-popup-format-variable (format "branch.%s.rebase" branch)
- '("true" "false")
- "false" "pull.rebase"
- (+ (length branch) 20))))
-
-;;;###autoload
-(defun magit-cycle-branch*pushRemote (branch)
- "Cycle the value of `branch.<name>.pushRemote' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variable `branch.<name>.pushRemote' specifies the remote
-that the branch named NAME is usually pushed to. The value has
-to be the name of an existing remote.
-
-If that variable is undefined, then the value of the Git variable
-`remote.pushDefault' is used instead, provided that it is defined,
-which by default it is not."
- (interactive
- (list (or (and (not current-prefix-arg)
- (magit-get-current-branch))
- (magit-read-local-branch "Cycle branch.<name>.pushRemote for"))))
- (magit-popup-set-variable (format "branch.%s.pushRemote" branch)
- (magit-list-remotes)
- "remote.pushDefault"))
-
-(defun magit-format-branch*pushRemote ()
- (let ((branch (or (magit-get-current-branch) "<name>")))
- (magit-popup-format-variable (format "branch.%s.pushRemote" branch)
- (magit-list-remotes)
- nil "remote.pushDefault"
- (+ (length branch) 20))))
-
-;;;###autoload
-(defun magit-cycle-pull.rebase ()
- "Cycle the repository-local value of `pull.rebase'.
-
-The Git variable `pull.rebase' specifies whether pulling is done
-by rebasing or by merging. It can be overwritten using the Git
-variable `branch.<name>.rebase'.
-
-When `true' then pulling is done by rebasing.
-When `false' (the default) then pulling is done by merging."
- (interactive)
- (magit-popup-set-variable "pull.rebase" '("true" "false") "false"))
-
-(defun magit-format-pull.rebase ()
- (magit-popup-format-variable "pull.rebase" '("true" "false") "false" nil 19))
-
-;;;###autoload
-(defun magit-cycle-remote.pushDefault ()
- "Cycle the repository-local value of `remote.pushDefault'.
-
-The Git variable `remote.pushDefault' specifies the remote that
-local branches are usually pushed to. It can be overwritten
-using the Git variable `branch.<name>.pushRemote'."
- (interactive)
- (magit-popup-set-variable "remote.pushDefault" (magit-list-remotes)))
-
-(defun magit-format-remote.pushDefault ()
- (magit-popup-format-variable "remote.pushDefault"
- (magit-list-remotes) nil nil 19))
-
-;;;###autoload
-(defun magit-cycle-branch*autoSetupMerge ()
- "Cycle the repository-local value of `branch.autoSetupMerge'.
-
-The Git variable `branch.autoSetupMerge' under what circumstances
-creating a branch (named NAME) should result in the variables
-`branch.<name>.merge' and `branch.<name>.remote' being set
-according to the starting point used to create the branch. If
-the starting point isn't a branch, then these variables are never
-set.
-
-When `always' then the variables are set regardless of whether
-the starting point is a local or a remote branch.
-
-When `true' (the default) then the variable are set when the
-starting point is a remote branch, but not when it is a local
-branch.
-
-When `false' then the variables are never set."
- (interactive)
- (magit-popup-set-variable "branch.autoSetupMerge"
- '("always" "true" "false") "true"))
-
-(defun magit-format-branch*autoSetupMerge ()
- (magit-popup-format-variable "branch.autoSetupMerge"
- '("always" "true" "false") "true" nil 23))
-
-;;;###autoload
-(defun magit-cycle-branch*autoSetupRebase ()
- "Cycle the repository-local value of `branch.autoSetupRebase'.
-
-The Git variable `branch.autoSetupRebase' specifies whether
-creating a branch (named NAME) should result in the variable
-`branch.<name>.rebase' being set to `true'.
-
-When `always' then the variable is set regardless of whether the
-starting point is a local or a remote branch.
-
-When `local' then the variable are set when the starting point
-is a local branch, but not when it is a remote branch.
-
-When `remote' then the variable are set when the starting point
-is a remote branch, but not when it is a local branch.
-
-When `never' (the default) then the variable is never set."
- (interactive)
- (magit-popup-set-variable "branch.autoSetupRebase"
- '("always" "local" "remote" "never") "never"))
-
-(defun magit-format-branch*autoSetupRebase ()
- (magit-popup-format-variable "branch.autoSetupRebase"
- '("always" "local" "remote" "never")
- "never" nil 23))
-
-;;;; Merge
-
-;;;###autoload (autoload 'magit-merge-popup "magit" nil t)
-(magit-define-popup magit-merge-popup
- "Popup console for merge commands."
- 'magit-commands
- :man-page "git-merge"
- :switches '((?f "Fast-forward only" "--ff-only")
- (?n "No fast-forward" "--no-ff")
- (?s "Squash" "--squash"))
- :options '((?s "Strategy" "--strategy="))
- :actions '((?m "Merge" magit-merge)
- (?e "Merge and edit message" magit-merge-editmsg)
- (?p "Preview merge" magit-merge-preview)
- (?n "Merge but don't commit" magit-merge-nocommit))
- :sequence-actions '((?m "Commit merge" magit-commit)
- (?a "Abort merge" magit-merge-abort))
- :sequence-predicate 'magit-merge-state
- :default-action 'magit-merge
- :max-action-columns 2)
-
-;;;###autoload
-(defun magit-merge (rev &optional args nocommit)
- "Merge commit REV into the current branch; using default message.
-
-Unless there are conflicts or a prefix argument is used create a
-merge commit using a generic commit message and without letting
-the user inspect the result. With a prefix argument pretend the
-merge failed to give the user the opportunity to inspect the
-merge.
-
-\(git merge --no-edit|--no-commit [ARGS] REV)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)
- current-prefix-arg))
- (magit-merge-assert)
- (magit-run-git "merge" (if nocommit "--no-commit" "--no-edit") args rev))
-
-;;;###autoload
-(defun magit-merge-editmsg (rev &optional args)
- "Merge commit REV into the current branch; and edit message.
-Perform the merge and prepare a commit message but let the user
-edit it.
-\n(git merge --edit [ARGS] rev)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)))
- (magit-merge-assert)
- (with-editor "GIT_EDITOR"
- (let ((magit-process-popup-time -1))
- (magit-run-git-async "merge" "--edit" args rev))))
-
-;;;###autoload
-(defun magit-merge-nocommit (rev &optional args)
- "Merge commit REV into the current branch; pretending it failed.
-Pretend the merge failed to give the user the opportunity to
-inspect the merge and change the commit message.
-\n(git merge --no-commit [ARGS] rev)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)))
- (magit-merge-assert)
- (magit-run-git "merge" "--no-commit" args rev))
-
-;;;###autoload
-(defun magit-merge-preview (rev)
- "Preview result of merging REV into the current branch."
- (interactive (list (magit-read-other-branch-or-commit "Preview merge")))
- (magit-mode-setup #'magit-merge-preview-mode rev))
-
-(define-derived-mode magit-merge-preview-mode magit-diff-mode "Magit Merge"
- "Mode for previewing a merge."
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-merge-preview-refresh-buffer (rev)
- (let* ((branch (magit-get-current-branch))
- (head (or branch (magit-rev-verify "HEAD"))))
- (setq header-line-format
- (propertize (format "Preview merge of %s into %s"
- rev (or branch "HEAD"))
- 'face 'magit-header-line))
- (magit-insert-section (diffbuf)
- (magit-git-wash #'magit-diff-wash-diffs
- "merge-tree" (magit-git-string "merge-base" head rev) head rev))))
-
-;;;###autoload
-(defun magit-merge-abort ()
- "Abort the current merge operation.
-\n(git merge --abort)"
- (interactive)
- (if (file-exists-p (magit-git-dir "MERGE_HEAD"))
- (when (magit-confirm 'abort-merge)
- (magit-run-git-async "merge" "--abort"))
- (user-error "No merge in progress")))
-
-(defun magit-checkout-stage (file arg)
- "During a conflict checkout and stage side, or restore conflict."
- (interactive
- (let ((file (magit-completing-read "Checkout file"
- (magit-tracked-files) nil nil nil
- 'magit-read-file-hist
- (magit-current-file))))
- (cond ((member file (magit-unmerged-files))
- (list file (magit-checkout-read-stage file)))
- ((yes-or-no-p (format "Restore conflicts in %s? " file))
- (list file "--merge"))
- (t
- (user-error "Quit")))))
- (pcase (cons arg (cddr (car (magit-file-status file))))
- ((or `("--ours" ?D ,_)
- `("--theirs" ,_ ?D))
- (magit-run-git "rm" "--" file))
- (_ (if (equal arg "--merge")
- ;; This fails if the file was deleted on one
- ;; side. And we cannot do anything about it.
- (magit-run-git "checkout" "--merge" "--" file)
- (magit-call-git "checkout" arg "--" file)
- (magit-run-git "add" "-u" "--" file)))))
-
-(defun magit-merge-state ()
- (file-exists-p (magit-git-dir "MERGE_HEAD")))
-
-(defun magit-merge-assert ()
- (or (not (magit-anything-modified-p))
- (magit-confirm 'merge-dirty
- "Merging with dirty worktree is risky. Continue")
- (user-error "Abort")))
-
-(defun magit-checkout-read-stage (file)
- (magit-read-char-case (format "For %s checkout: " file) t
- (?o "[o]ur stage" "--ours")
- (?t "[t]heir stage" "--theirs")
- (?c "[c]onflict" "--merge")))
-
-(defun magit-insert-merge-log ()
- "Insert section for the on-going merge.
-Display the heads that are being merged.
-If no merge is in progress, do nothing."
- (-when-let (heads (mapcar 'magit-get-shortname
- (magit-file-lines (magit-git-dir "MERGE_HEAD"))))
- (magit-insert-section (commit (car heads))
- (magit-insert-heading
- (format "Merging %s:" (mapconcat 'identity heads ", ")))
- (magit-insert-log
- (concat (magit-git-string "merge-base" "--octopus" "HEAD" (car heads))
- ".." (car heads))
- (let ((args magit-log-section-arguments))
- (unless (member "--decorate=full" magit-log-section-arguments)
- (push "--decorate=full" args))
- args)))))
-
-;;;; Reset
-
-;;;###autoload
-(defun magit-reset-index (commit)
- "Reset the index to COMMIT.
-Keep the head and working tree as-is, so if COMMIT refers to the
-head this effectively unstages all changes.
-\n(git reset COMMIT)"
- (interactive (list (magit-read-branch-or-commit "Reset index to")))
- (magit-reset-internal nil commit "."))
-
-;;;###autoload
-(defun magit-reset (commit &optional hard)
- "Reset the head and index to COMMIT, but not the working tree.
-With a prefix argument also reset the working tree.
-\n(git reset --mixed|--hard COMMIT)"
- (interactive (list (magit-read-branch-or-commit
- (if current-prefix-arg
- "Hard reset to"
- "Reset head to"))
- current-prefix-arg))
- (magit-reset-internal (if hard "--hard" "--mixed") commit))
-
-;;;###autoload
-(defun magit-reset-head (commit)
- "Reset the head and index to COMMIT, but not the working tree.
-\n(git reset --mixed COMMIT)"
- (interactive (list (magit-read-branch-or-commit "Reset head to")))
- (magit-reset-internal "--mixed" commit))
-
-;;;###autoload
-(defun magit-reset-soft (commit)
- "Reset the head to COMMIT, but not the index and working tree.
-\n(git reset --soft REVISION)"
- (interactive (list (magit-read-branch-or-commit "Soft reset to")))
- (magit-reset-internal "--soft" commit))
-
-;;;###autoload
-(defun magit-reset-hard (commit)
- "Reset the head, index, and working tree to COMMIT.
-\n(git reset --hard REVISION)"
- (interactive (list (magit-read-branch-or-commit "Hard reset to")))
- (magit-reset-internal "--hard" commit))
-
-(defun magit-reset-internal (arg commit &optional path)
- (when (and (not (member arg '("--hard" nil)))
- (equal (magit-rev-parse commit)
- (magit-rev-parse "HEAD~")))
- (with-temp-buffer
- (magit-git-insert "show" "-s" "--format=%B" "HEAD")
- (when git-commit-major-mode
- (funcall git-commit-major-mode))
- (git-commit-setup-font-lock)
- (git-commit-save-message)))
- (let ((cmd (if (and (equal commit "HEAD") (not arg)) "unstage" "reset")))
- (magit-wip-commit-before-change nil (concat " before " cmd))
- (magit-run-git "reset" arg commit "--" path)
- (when (equal cmd "unstage")
- (magit-wip-commit-after-apply nil " after unstage"))))
-
-;;;; Files
-
-(defun magit-file-rename (file newname)
- "Rename the FILE to NEWNAME.
-If FILE isn't tracked in Git fallback to using `rename-file'."
- (interactive
- (let* ((file (magit-read-file "Rename file"))
- (newname (read-file-name (format "Rename %s to file: " file))))
- (list (expand-file-name file (magit-toplevel))
- (expand-file-name newname))))
- (if (magit-file-tracked-p file)
- (let ((oldbuf (get-file-buffer file)))
- (when (and oldbuf (buffer-modified-p oldbuf))
- (user-error "Save %s before moving it" file))
- (when (file-exists-p newname)
- (user-error "%s already exists" newname))
- (magit-run-git "mv" file newname)
- (when oldbuf
- (with-current-buffer oldbuf
- (let ((buffer-read-only buffer-read-only))
- (set-visited-file-name newname))
- (if (fboundp 'vc-refresh-state)
- (vc-refresh-state)
- (with-no-warnings
- (vc-find-file-hook))))))
- (rename-file file newname current-prefix-arg)
- (magit-refresh)))
-
-(defun magit-file-untrack (file)
- "Untrack FILE.
-Stop tracking FILE in Git but do not remove it from the working
-tree."
- (interactive (list (magit-read-tracked-file "Untrack file")))
- (magit-run-git "rm" "--cached" "--" file))
-
-(defun magit-file-delete (file &optional force)
- "Delete FILE.
-With a prefix argument FORCE do so even when FILE has uncommitted
-changes.
-
-If FILE isn't tracked in Git fallback to using `delete-file'."
- (interactive (list (magit-read-file "Delete file")))
- (if (magit-file-tracked-p file)
- (magit-run-git "rm" (and force "--force") "--" file)
- (delete-file (expand-file-name file (magit-toplevel)) t)
- (magit-refresh)))
-
-(defun magit-read-tracked-file (prompt)
- (magit-read-file prompt t))
-
-(defun magit-read-file (prompt &optional tracked-only)
- (let ((choices (nconc (magit-list-files)
- (unless tracked-only (magit-untracked-files)))))
- (magit-completing-read prompt choices nil t nil nil
- (car (member (or (magit-section-when (file))
- (magit-file-relative-name
- nil tracked-only))
- choices)))))
-
-(defun magit-read-files (prompt initial-contents)
- (mapconcat 'identity
- (completing-read-multiple (or prompt "File,s: ")
- (magit-list-files)
- nil nil initial-contents) ","))
-
-(defun magit-read-file-choice (prompt files &optional error default)
- "Read file from FILES.
-
-If FILES has only one member, return that instead of prompting.
-If FILES has no members, give a user error. ERROR can be given
-to provide a more informative error.
-
-If DEFAULT is non-nil, use this as the default value instead of
-`magit-current-file'."
- (pcase (length files)
- (0 (user-error (or error "No file choices")))
- (1 (car files))
- (_ (magit-completing-read
- prompt files nil t nil 'magit-read-file-hist
- (car (member (or default (magit-current-file)) files))))))
-
-;;; Miscellaneous
-;;;; Tag
-
-;;;###autoload (autoload 'magit-tag-popup "magit" nil t)
-(magit-define-popup magit-tag-popup
- "Popup console for tag commands."
- 'magit-commands
- :man-page "git-tag"
- :switches '((?a "Annotate" "--annotate")
- (?s "Sign" "--sign")
- (?f "Force" "--force"))
- :actions '((?t "Create" magit-tag)
- (?k "Delete" magit-tag-delete)
- (?p "Prune" magit-tag-prune))
- :default-action 'magit-tag)
-
-;;;###autoload
-(defun magit-tag (name rev &optional args)
- "Create a new tag with the given NAME at REV.
-With a prefix argument annotate the tag.
-\n(git tag [--annotate] NAME REV)"
- (interactive (list (magit-read-tag "Tag name")
- (magit-read-branch-or-commit "Place tag on")
- (let ((args (magit-tag-arguments)))
- (when current-prefix-arg
- (cl-pushnew "--annotate" args))
- args)))
- (magit-run-git-with-editor "tag" args name rev))
-
-;;;###autoload
-(defun magit-tag-delete (tags)
- "Delete one or more tags.
-If the region marks multiple tags (and nothing else), then offer
-to delete those, otherwise prompt for a single tag to be deleted,
-defaulting to the tag at point.
-\n(git tag -d TAGS)"
- (interactive (list (--if-let (magit-region-values 'tag)
- (magit-confirm t nil "Delete %i tags" it)
- (magit-read-tag "Delete tag" t))))
- (magit-run-git "tag" "-d" tags))
-
-(defun magit-tag-prune (tags remote-tags remote)
- "Offer to delete tags missing locally from REMOTE, and vice versa."
- (interactive
- (let* ((remote (magit-read-remote "Prune tags using remote"))
- (tags (magit-list-tags))
- (rtags (prog2 (message "Determining remote tags...")
- (magit-remote-list-tags remote)
- (message "Determining remote tags...done")))
- (ltags (-difference tags rtags))
- (rtags (-difference rtags tags)))
- (unless (or ltags rtags)
- (message "Same tags exist locally and remotely"))
- (unless (magit-confirm t "Delete %s locally"
- "Delete %i tags locally" ltags)
- (setq ltags nil))
- (unless (magit-confirm t "Delete %s from remote"
- "Delete %i tags from remote" rtags)
- (setq rtags nil))
- (list ltags rtags remote)))
- (when tags
- (magit-call-git "tag" "-d" tags))
- (when remote-tags
- (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags))))
-
-;;;; Notes
-
-;;;###autoload (autoload 'magit-notes-popup "magit" nil t)
-(magit-define-popup magit-notes-popup
- "Popup console for notes commands."
- 'magit-commands
- :man-page "git-tag"
- :switches '("Switch for prune"
- (?n "Dry run" "--dry-run"))
- :options '("Option for edit and remove"
- (?r "Manipulate ref" "--ref=" magit-notes-popup-read-ref)
- "Option for merge"
- (?s "Merge strategy" "--strategy="))
- :actions '((?T "Edit" magit-notes-edit)
- (?r "Remove" magit-notes-remove)
- (?m "Merge" magit-notes-merge)
- (?p "Prune" magit-notes-prune)
- (?s "Set ref" magit-notes-set-ref)
- (?S "Set display refs" magit-notes-set-display-refs))
- :sequence-actions '((?c "Commit merge" magit-notes-merge-commit)
- (?a "Abort merge" magit-notes-merge-abort))
- :sequence-predicate 'magit-notes-merging-p
- :default-action 'magit-notes-edit)
-
-(defun magit-notes-edit (commit &optional ref)
- "Edit the note attached to COMMIT.
-REF is the notes ref used to store the notes.
-
-Interactively or when optional REF is nil use the value of Git
-variable `core.notesRef' or \"refs/notes/commits\" if that is
-undefined."
- (interactive (magit-notes-read-args "Edit notes"))
- (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
- "edit" commit))
-
-(defun magit-notes-remove (commit &optional ref)
- "Remove the note attached to COMMIT.
-REF is the notes ref from which the note is removed.
-
-Interactively or when optional REF is nil use the value of Git
-variable `core.notesRef' or \"refs/notes/commits\" if that is
-undefined."
- (interactive (magit-notes-read-args "Remove notes"))
- (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
- "remove" commit))
-
-(defun magit-notes-merge (ref)
- "Merge the notes ref REF into the current notes ref.
-
-The current notes ref is the value of Git variable
-`core.notesRef' or \"refs/notes/commits\" if that is undefined.
-
-When there are conflict, then they have to resolved in the
-temporary worktree \".git/NOTES_MERGE_WORKTREE\". When
-done use `magit-notes-merge-commit' to finish. To abort
-use `magit-notes-merge-abort'."
- (interactive (list (magit-read-string-ns "Merge reference")))
- (magit-run-git-with-editor "notes" "merge" ref))
-
-(defun magit-notes-merge-commit ()
- "Commit the current notes ref merge.
-Also see `magit-notes-merge'."
- (interactive)
- (magit-run-git-with-editor "notes" "merge" "--commit"))
-
-(defun magit-notes-merge-abort ()
- "Abort the current notes ref merge.
-Also see `magit-notes-merge'."
- (interactive)
- (magit-run-git-with-editor "notes" "merge" "--abort"))
-
-(defun magit-notes-prune (&optional dry-run)
- "Remove notes about unreachable commits."
- (interactive (list (and (member "--dry-run" (magit-notes-arguments)) t)))
- (when dry-run
- (magit-process-buffer))
- (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run")))
-
-(defun magit-notes-set-ref (ref &optional global)
- "Set the current notes ref to REF.
-The ref is made current by setting the value of the Git variable
-`core.notesRef'. With a prefix argument GLOBAL change the global
-value, else the value in the current repository. When this is
-undefined, then \"refs/notes/commit\" is used.
-
-Other `magit-notes-*' commands, as well as the sub-commands
-of Git's `note' command, default to operate on that ref."
- (interactive
- (list (magit-completing-read "Set notes ref"
- (nconc (list "refs/" "refs/notes/")
- (magit-list-notes-refnames))
- nil nil
- (--when-let (magit-get "core.notesRef")
- (if (string-match "^refs/notes/\\(.+\\)" it)
- (match-string 1 it)
- it)))
- current-prefix-arg))
- (if ref
- (magit-run-git "config" (and global "--global") "core.notesRef"
- (if (string-prefix-p "refs/" ref)
- ref
- (concat "refs/notes/" ref)))
- (magit-run-git "config" (and global "--global")
- "--unset" "core.notesRef")))
-
-(defun magit-notes-set-display-refs (refs &optional global)
- "Set notes refs to be display in addition to \"core.notesRef\".
-REFS is a colon separated list of notes refs. The values are
-stored in the Git variable `notes.displayRef'. With a prefix
-argument GLOBAL change the global values, else the values in
-the current repository."
- (interactive
- (list (magit-completing-read "Set additional notes ref(s)"
- (nconc (list "refs/" "refs/notes/")
- (magit-list-notes-refnames))
- nil nil
- (mapconcat #'identity
- (magit-get-all "notes.displayRef")
- ":"))
- current-prefix-arg))
- (when (and refs (atom refs))
- (setq refs (split-string refs ":")))
- (when global
- (setq global "--global"))
- (magit-git-success "config" "--unset-all" global "notes.displayRef")
- (dolist (ref refs)
- (magit-call-git "config" "--add" global "notes.displayRef" ref))
- (magit-refresh))
-
-(defun magit-notes-read-args (prompt)
- (list (magit-read-branch-or-commit prompt)
- (--when-let (--first (string-match "^--ref=\\(.+\\)" it)
- (magit-notes-arguments))
- (match-string 1 it))))
-
-(defun magit-notes-popup-read-ref (prompt &optional initial-input)
- (magit-completing-read prompt (nconc (list "refs/" "refs/notes/")
- (magit-list-notes-refnames))
- nil nil initial-input))
-
-(defun magit-notes-merging-p ()
- (let ((dir (magit-git-dir "NOTES_MERGE_WORKTREE")))
- (and (file-directory-p dir)
- (directory-files dir nil "^[^.]"))))
-
-;;;; File Mode
-
-(defvar magit-file-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "\C-xg" 'magit-status)
- (define-key map "\C-x\M-g" 'magit-dispatch-popup)
- (define-key map "\C-c\M-g" 'magit-file-popup)
- map)
- "Keymap for `magit-file-mode'.")
-
-(magit-define-popup magit-file-popup
- "Popup console for Magit commands in file-visiting buffers."
- :actions '((?s "Stage" magit-stage-file)
- (?l "Log" magit-log-buffer-file)
- (?c "Commit" magit-commit-popup)
- (?u "Unstage" magit-unstage-file)
- (?b "Blame" magit-blame-popup) nil nil
- (?p "Find blob" magit-blob-previous))
- :max-action-columns 3)
-
-(defvar magit-file-mode-lighter "")
-
-(define-minor-mode magit-file-mode
- "Enable some Magit features in file-visiting buffers.
-
-Currently this only adds the following key bindings.
-\n\\{magit-file-mode-map}"
- :package-version '(magit . "2.2.0")
- :lighter magit-file-mode-lighter
- :keymap magit-file-mode-map)
-
-(defun magit-file-mode-turn-on ()
- (and buffer-file-name
- (ignore-errors (magit-inside-worktree-p))
- (magit-file-mode)))
-
-;;;###autoload
-(define-globalized-minor-mode global-magit-file-mode
- magit-file-mode magit-file-mode-turn-on
- :package-version '(magit . "2.2.0")
- :group 'magit-modes)
-
-;;;; Blob Mode
-
-(defvar magit-blob-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "n" 'magit-blob-next)
- (define-key map "p" 'magit-blob-previous)
- (define-key map "q" 'magit-kill-this-buffer)
- map)
- "Keymap for `magit-blob-mode'.")
-
-(define-minor-mode magit-blob-mode
- "Enable some Magit features in blob-visiting buffers.
-
-Currently this only adds the following key bindings.
-\n\\{magit-blob-mode-map}"
- :package-version '(magit . "2.3.0"))
-
-(defun magit-blob-next ()
- "Visit the next blob which modified the current file."
- (interactive)
- (if magit-buffer-file-name
- (magit-blob-visit (or (magit-blob-successor magit-buffer-revision
- magit-buffer-file-name)
- magit-buffer-file-name)
- (line-number-at-pos))
- (if (buffer-file-name (buffer-base-buffer))
- (user-error "You have reached the end of time")
- (user-error "Buffer isn't visiting a file or blob"))))
-
-(defun magit-blob-previous ()
- "Visit the previous blob which modified the current file."
- (interactive)
- (-if-let (file (or magit-buffer-file-name
- (buffer-file-name (buffer-base-buffer))))
- (--if-let (magit-blob-ancestor magit-buffer-revision file)
- (magit-blob-visit it (line-number-at-pos))
- (user-error "You have reached the beginning of time"))
- (user-error "Buffer isn't visiting a file or blob")))
-
-(defun magit-blob-visit (blob-or-file line)
- (if (stringp blob-or-file)
- (find-file blob-or-file)
- (-let [(rev file) blob-or-file]
- (magit-find-file rev file)
- (let ((str (magit-rev-format "%ct%s" rev)))
- (message "%s (%s ago)" (substring str 10)
- (magit-format-duration
- (abs (truncate (- (float-time)
- (string-to-number
- (substring str 0 10)))))
- magit-duration-spec)))))
- (goto-char (point-min))
- (forward-line (1- line)))
-
-(defun magit-blob-ancestor (rev file)
- (let ((lines (magit-with-toplevel
- (magit-git-lines "log" "-2" "--format=%H" "--name-only"
- "--follow" (or rev "HEAD") "--" file))))
- (if rev (cddr lines) (butlast lines 2))))
-
-(defun magit-blob-successor (rev file)
- (let ((lines (magit-with-toplevel
- (magit-git-lines "log" "--format=%H" "--name-only" "--follow"
- "HEAD" "--" file))))
- (catch 'found
- (while lines
- (if (equal (nth 2 lines) rev)
- (throw 'found (list (nth 0 lines) (nth 1 lines)))
- (setq lines (nthcdr 2 lines)))))))
-
-(defun magit-kill-this-buffer ()
- "Kill the current buffer."
- (interactive)
- (kill-buffer (current-buffer)))
-
-;;;; Dispatch Popup
-
-;;;###autoload (autoload 'magit-dispatch-popup "magit" nil t)
-(magit-define-popup magit-dispatch-popup
- "Popup console for dispatching other popups."
- 'magit-commands nil nil
- :actions '("Popup and dwim commands"
- (?A "Cherry-picking" magit-cherry-pick-popup)
- (?b "Branching" magit-branch-popup)
- (?B "Bisecting" magit-bisect-popup)
- (?c "Committing" magit-commit-popup)
- (?d "Diffing" magit-diff-popup)
- (?D "Change diffs" magit-diff-refresh-popup)
- (?e "Ediff dwimming" magit-ediff-dwim)
- (?E "Ediffing" magit-ediff-popup)
- (?f "Fetching" magit-fetch-popup)
- (?F "Pulling" magit-pull-popup)
- (?l "Logging" magit-log-popup)
- (?m "Merging" magit-merge-popup)
- (?M "Remoting" magit-remote-popup)
- (?o "Submodules" magit-submodule-popup)
- (?P "Pushing" magit-push-popup)
- (?r "Rebasing" magit-rebase-popup)
- (?t "Tagging" magit-tag-popup)
- (?T "Notes" magit-notes-popup)
- (?V "Reverting" magit-revert-popup)
- (?w "Apply patches" magit-am-popup)
- (?W "Format patches" magit-patch-popup)
- (?y "Show Refs" magit-show-refs-popup)
- (?z "Stashing" magit-stash-popup)
- (?! "Running" magit-run-popup)
- "Applying changes"
- (?a "Apply" magit-apply)
- (?s "Stage" magit-stage)
- (?u "Unstage" magit-unstage)
- nil
- (?v "Reverse" magit-reverse)
- (?S "Stage all" magit-stage-modified)
- (?U "Unstage all" magit-unstage-all)
- nil
- (?k "Discard" magit-discard)
- "\
- g refresh current buffer
- TAB toggle section at point
- RET visit thing at point
-
- C-h m show all key bindings" nil)
- :max-action-columns 4)
-
-;;;; Git Popup
-
-(defvar magit-git-command-history nil)
-
-;;;###autoload (autoload 'magit-run-popup "magit" nil t)
-(magit-define-popup magit-run-popup
- "Popup console for running raw Git commands."
- 'magit-commands nil nil
- :actions '((?! "Git Subcommand (in topdir)" magit-git-command-topdir)
- (?k "Gitk" magit-run-gitk)
- (?p "Git Subcommand (in pwd)" magit-git-command)
- (?a "Gitk --all" magit-run-gitk-all)
- (?s "Shell command (in topdir)" magit-shell-command-topdir)
- (?b "Gitk --branches" magit-run-gitk-branches)
- (?S "Shell command (in pwd)" magit-shell-command)
- (?g "Git Gui" magit-run-git-gui))
- :default-action 'magit-git-command
- :max-action-columns 2)
-
-;;;###autoload
-(defun magit-git-command (args directory)
- "Execute a Git subcommand asynchronously, displaying the output.
-With a prefix argument run Git in the root of the current
-repository, otherwise in `default-directory'."
- (interactive (magit-read-shell-command "Git subcommand (pwd: %s)"))
- (require 'eshell)
- (with-temp-buffer
- (insert args)
- (setq args (mapcar 'eval (eshell-parse-arguments (point-min)
- (point-max))))
- (setq default-directory directory)
- (let ((magit-git-global-arguments
- ;; A human will want globbing by default.
- (remove "--literal-pathspecs"
- magit-git-global-arguments)))
- (magit-run-git-async args)))
- (magit-process-buffer))
-
-;;;###autoload
-(defun magit-git-command-topdir (args directory)
- "Execute a Git subcommand asynchronously, displaying the output.
-Run Git in the top-level directory of the current repository.
-\n(fn)" ; arguments are for internal use
- (interactive (magit-read-shell-command "Git subcommand (pwd: %s)" t))
- (magit-git-command args directory))
-
-;;;###autoload
-(defun magit-shell-command (args directory)
- "Execute a shell command asynchronously, displaying the output.
-With a prefix argument run the command in the root of the current
-repository, otherwise in `default-directory'."
- (interactive (magit-read-shell-command "Shell command (pwd: %s)"))
- (require 'eshell)
- (with-temp-buffer
- (insert args)
- (setq args (mapcar 'eval (eshell-parse-arguments (point-min)
- (point-max))))
- (setq default-directory directory)
- (apply #'magit-start-process (car args) nil (cdr args)))
- (magit-process-buffer))
-
-;;;###autoload
-(defun magit-shell-command-topdir (args directory)
- "Execute a shell command asynchronously, displaying the output.
-Run the command in the top-level directory of the current repository.
-\n(fn)" ; arguments are for internal use
- (interactive (magit-read-shell-command "Shell command (pwd: %s)" t))
- (magit-shell-command args directory))
-
-(defun magit-read-shell-command (prompt &optional root)
- (let ((dir (if (or root current-prefix-arg)
- (or (magit-toplevel)
- (user-error "Not inside a Git repository"))
- default-directory)))
- (list (magit-read-string (format prompt (abbreviate-file-name dir))
- nil 'magit-git-command-history)
- dir)))
-
-;;;; Read Repository
-
-(defun magit-read-repository (&optional read-directory-name)
- "Read a Git repository in the minibuffer, with completion.
-
-The completion choices are the basenames of top-levels of
-repositories found in the directories specified by option
-`magit-repository-directories'. In case of name conflicts
-the basenames are prefixed with the name of the respective
-parent directories. The returned value is the actual path
-to the selected repository.
-
-With prefix argument simply read a directory name using
-`read-directory-name'."
- (if (and (not read-directory-name) magit-repository-directories)
- (let* ((repos (magit-list-repos-uniquify
- (--map (cons (file-name-nondirectory it) it)
- (magit-list-repos))))
- (reply (magit-completing-read "Git repository" repos)))
- (file-name-as-directory
- (or (cdr (assoc reply repos))
- (if (file-directory-p reply)
- (expand-file-name reply)
- (user-error "Not a repository or a directory: %s" reply)))))
- (file-name-as-directory
- (read-directory-name "Git repository: "
- (or (magit-toplevel) default-directory)))))
-
-(defun magit-list-repos ()
- (--mapcat (magit-list-repos-1 it magit-repository-directories-depth)
- magit-repository-directories))
-
-(defun magit-list-repos-1 (directory depth)
- (cond ((file-readable-p (expand-file-name ".git" directory))
- (list directory))
- ((and (> depth 0) (file-accessible-directory-p directory))
- (--mapcat (when (file-directory-p it)
- (magit-list-repos-1 it (1- depth)))
- (directory-files directory t "^[^.]" t)))))
-
-(defun magit-list-repos-uniquify (alist)
- (let (result (dict (make-hash-table :test 'equal)))
- (dolist (a (delete-dups alist))
- (puthash (car a) (cons (cdr a) (gethash (car a) dict)) dict))
- (maphash
- (lambda (key value)
- (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 (- (length key))))))
- it)
- value))))))
- dict)
- result))
-
-;;;; Revision Stack
-
-(defvar magit-revision-stack nil)
-
-(defcustom magit-pop-revision-stack-format
- '("[%N: %h] " "%N: %H\n %s\n" "\\[\\([0-9]+\\)[]:]")
- "Control how `magit-pop-revision-stack' inserts a revision.
-
-The command `magit-pop-revision-stack' inserts a representation
-of the revision last pushed to the `magit-revision-stack' into
-the current buffer. It inserts text at point and/or near the end
-of the buffer, and removes the consumed revision from the stack.
-
-The entries on the stack have the format (HASH TOPLEVEL) and this
-option has the format (POINT-FORMAT EOB-FORMAT INDEX-REGEXP), all
-of which may be nil or a string (though either one of EOB-FORMAT
-or POINT-FORMAT should be a string, and if INDEX-REGEXP is
-non-nil, then the two formats should be too).
-
-First INDEX-REGEXP is used to find the previously inserted entry,
-by searching backward from point. The first submatch must match
-the index number. That number is incremented by one, and becomes
-the index number of the entry to be inserted. If you don't want
-to number the inserted revisions, then use nil for INDEX-REGEXP.
-
-If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
-should contain \"%N\", which is replaced with the number that was
-determined in the previous step.
-
-Both formats, if non-nil and after removing %N, are then expanded
-using `git show --format=FORMAT ...' inside TOPLEVEL.
-
-The expansion of POINT-FORMAT is inserted at point, and the
-expansion of EOB-FORMAT is inserted at the end of the buffer (if
-the buffer ends with a comment, then it is inserted right before
-that)."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type '(list (choice (string :tag "Insert at point format")
- (cons (string :tag "Insert at point format")
- (repeat (string :tag "Argument to git show")))
- (const :tag "Don't insert at point" nil))
- (choice (string :tag "Insert at eob format")
- (cons (string :tag "Insert at eob format")
- (repeat (string :tag "Argument to git show")))
- (const :tag "Don't insert at eob" nil))
- (choice (regexp :tag "Find index regexp")
- (const :tag "Don't number entries" nil))))
-
-(defun magit-pop-revision-stack (rev toplevel)
- "Insert a representation of a revision into the current buffer.
-
-Pop a revision from the `magit-revision-stack' and insert it into
-the current buffer according to `magit-pop-revision-stack-format'.
-Revisions can be put on the stack using `magit-copy-section-value'
-and `magit-copy-buffer-revision'.
-
-If the stack is empty or with a prefix argument instead read a
-revision in the minibuffer. By using the minibuffer history this
-allows selecting an item which was popped earlier or to insert an
-arbitrary reference or revision without first pushing it onto the
-stack.
-
-When reading the revision from the minibuffer, then it might not
-be possible to guess the correct repository. When this command
-is called inside a repository (e.g. while composing a commit
-message), then that repository is used. Otherwise (e.g. while
-composing an email) then the repository recorded for the top
-element of the stack is used (even though we insert another
-revision). If not called inside a repository and with an empty
-stack, or with two prefix arguments, then read the repository in
-the minibuffer too."
- (interactive
- (if (or current-prefix-arg (not magit-revision-stack))
- (let ((default-directory
- (or (and (not (= (prefix-numeric-value current-prefix-arg) 16))
- (or (magit-toplevel)
- (cadr (car magit-revision-stack))))
- (magit-read-repository))))
- (list (magit-read-branch-or-commit "Insert revision")
- default-directory))
- (push (caar magit-revision-stack) magit-revision-history)
- (pop magit-revision-stack)))
- (if rev
- (-let [(pnt-format eob-format idx-format) magit-pop-revision-stack-format]
- (let ((default-directory toplevel)
- (idx (and idx-format
- (save-excursion
- (if (re-search-backward idx-format nil t)
- (number-to-string
- (1+ (string-to-number (match-string 1))))
- "1"))))
- pnt-args eob-args)
- (when (listp pnt-format)
- (setq pnt-args (cdr pnt-format)
- pnt-format (car pnt-format)))
- (when (listp eob-format)
- (setq eob-args (cdr eob-format)
- eob-format (car eob-format)))
- (when pnt-format
- (when idx-format
- (setq pnt-format
- (replace-regexp-in-string "%N" idx pnt-format t t)))
- (magit-rev-insert-format pnt-format rev pnt-args)
- (backward-delete-char 1))
- (when eob-format
- (when idx-format
- (setq eob-format
- (replace-regexp-in-string "%N" idx eob-format t t)))
- (save-excursion
- (goto-char (point-max))
- (skip-syntax-backward ">s-")
- (beginning-of-line)
- (if (and comment-start (looking-at comment-start))
- (while (looking-at comment-start)
- (forward-line -1))
- (forward-line)
- (unless (= (current-column) 0)
- (insert ?\n)))
- (insert ?\n)
- (magit-rev-insert-format eob-format rev eob-args)
- (backward-delete-char 1)))))
- (user-error "Revision stack is empty")))
-
-(define-key git-commit-mode-map
- (kbd "C-c C-w") 'magit-pop-revision-stack)
-
-(defun magit-copy-section-value ()
- "Save the value of the current section for later use.
-
-Save the section value to the `kill-ring', and, provided that
-the current section is a commit, branch, or tag section, push
-the (referenced) revision to the `magit-revision-stack' for use
-with `magit-pop-revision-stack'.
-
-When the current section is a branch or a tag, and a prefix
-argument is used, then save the revision at its tip to the
-`kill-ring' instead of the reference name.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above."
- (interactive)
- (if (region-active-p)
- (copy-region-as-kill (mark) (point) 'region)
- (-when-let* ((section (magit-current-section))
- (value (magit-section-value section)))
- (magit-section-case
- ((branch commit module-commit tag)
- (let ((default-directory default-directory) ref)
- (magit-section-case
- ((branch tag)
- (setq ref value))
- (module-commit
- (setq default-directory
- (file-name-as-directory
- (expand-file-name (magit-section-parent-value section)
- (magit-toplevel))))))
- (setq value (magit-rev-parse value))
- (push (list value default-directory) magit-revision-stack)
- (kill-new (message "%s" (or (and current-prefix-arg ref)
- value)))))
- (t (kill-new (message "%s" value)))))))
-
-(defun magit-copy-buffer-revision ()
- "Save the revision of the current buffer for later use.
-
-Save the revision shown in the current buffer to the `kill-ring'
-and push it to the `magit-revision-stack'.
-
-This command is mainly intended for use in `magit-revision-mode'
-buffers, the only buffers where it is always unambiguous exactly
-which revision should be saved.
-
-Most other Magit buffers usually show more than one revision, in
-some way or another, so this command has to select one of them,
-and that choice might not always be the one you think would have
-been the best pick.
-
-In such buffers it is often more useful to save the value of
-the current section instead, using `magit-copy-section-value'.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above."
- (interactive)
- (if (region-active-p)
- (copy-region-as-kill (mark) (point) 'region)
- (-when-let (rev (cond ((memq major-mode '(magit-cherry-mode
- magit-log-select-mode
- magit-reflog-mode
- magit-refs-mode
- magit-revision-mode
- magit-stash-mode
- magit-stashes-mode))
- (car magit-refresh-args))
- ((memq major-mode '(magit-diff-mode
- magit-log-mode))
- (let ((r (caar magit-refresh-args)))
- (if (string-match "\\.\\.\\.?\\(.+\\)" r)
- (match-string 1 r)
- r)))
- ((eq major-mode 'magit-status-mode) "HEAD")))
- (when (magit-rev-verify-commit rev)
- (setq rev (magit-rev-parse rev))
- (push (list rev default-directory) magit-revision-stack)
- (kill-new (message "%s" rev))))))
-
-;;; magit.el ends soon
-
-(defconst magit-font-lock-keywords
- (eval-when-compile
- `((,(concat "(\\(magit-define-section-jumper\\)\\_>"
- "[ \t'\(]*"
- "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
- (1 'font-lock-keyword-face)
- (2 'font-lock-function-name-face nil t))
- (,(concat "(" (regexp-opt '("magit-insert-section"
- "magit-section-case"
- "magit-section-when"
- "magit-bind-match-strings"
- "magit-with-temp-index"
- "magit-with-blob"
- "magit-with-toplevel") t)
- "\\_>")
- . 1))))
-
-(font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords)
-
-(defvar magit-version 'undefined
- "The version of Magit that you're using.
-Use the function by the same name instead of this variable.")
-
-;;;###autoload
-(defun magit-version ()
- "Return the version of Magit currently in use.
-When called interactive also show the used versions of Magit,
-Git, and Emacs in the echo area."
- (interactive)
- (let ((magit-git-global-arguments nil)
- (toplib (or load-file-name buffer-file-name))
- debug)
- (unless (and toplib
- (equal (file-name-nondirectory toplib) "magit.el"))
- (setq toplib (locate-library "magit.el")))
- (push toplib debug)
- (when toplib
- (let* ((topdir (file-name-directory toplib))
- (gitdir (expand-file-name
- ".git" (file-name-directory
- (directory-file-name topdir))))
- (static (expand-file-name "magit-version.el" topdir)))
- (or (progn
- (push 'repo debug)
- (when (and (file-exists-p gitdir)
- ;; It is a repo, but is it the Magit repo?
- (file-exists-p
- (expand-file-name "../lisp/magit.el" gitdir)))
- (push t debug)
- ;; Inside the repo the version file should only exist
- ;; while running make.
- (unless noninteractive
- (ignore-errors (delete-file static)))
- (setq magit-version
- (let ((default-directory topdir))
- (magit-git-string "describe" "--tags" "--dirty")))))
- (progn
- (push 'static debug)
- (when (file-exists-p static)
- (push t debug)
- (load-file static)
- magit-version))
- (when (featurep 'package)
- (push 'elpa debug)
- (ignore-errors
- (--when-let (assq 'magit package-alist)
- (push t debug)
- (setq magit-version
- (and (fboundp 'package-desc-version)
- (package-version-join
- (package-desc-version (cadr it)))))))))))
- (if (stringp magit-version)
- (when (called-interactively-p 'any)
- (message "Magit %s, Git %s, Emacs %s"
- (or magit-version "(unknown)")
- (or (magit-git-version t) "(unknown)")
- emacs-version))
- (setq debug (reverse debug))
- (setq magit-version 'error)
- (when magit-version
- (push magit-version debug))
- (message "Cannot determine Magit's version %S" debug))
- magit-version))
-
-(defun magit-startup-asserts ()
- (let ((version (magit-git-version)))
- (when (and version
- (version< version magit--minimal-git)
- (not (equal (getenv "TRAVIS") "true")))
- (display-warning 'magit (format "\
-Magit requires Git >= %s, you are using %s.
-
-If this comes as a surprise to you, because you do actually have
-a newer version installed, then that probably means that the
-older version happens to appear earlier on the `$PATH'. If you
-always start Emacs from a shell, then that can be fixed in the
-shell's init file. If you start Emacs by clicking on an icon,
-or using some sort of application launcher, then you probably
-have to adjust the environment as seen by graphical interface.
-For X11 something like ~/.xinitrc should work.
-
-If you use Tramp to work inside remote Git repositories, then you
-have to make sure a suitable Git is used on the remote machines
-too.\n" magit--minimal-git version) :error)))
- (when (version< emacs-version magit--minimal-emacs)
- (display-warning 'magit (format "\
-Magit requires Emacs >= %s, you are using %s.
-
-If this comes as a surprise to you, because you do actually have
-a newer version installed, then that probably means that the
-older version happens to appear earlier on the `$PATH'. If you
-always start Emacs from a shell, then that can be fixed in the
-shell's init file. If you start Emacs by clicking on an icon,
-or using some sort of application launcher, then you probably
-have to adjust the environment as seen by graphical interface.
-For X11 something like ~/.xinitrc should work.\n"
- magit--minimal-emacs emacs-version)
- :error))
- (--each '((magit-log-edit . git-commit)
- (git-commit-mode . git-commit)
- (git-rebase-mode . git-rebase))
- (when (or (featurep (car it)) (locate-library (symbol-name (car it))))
- (display-warning 'magit (format "%s has to be removed
-
-Magit is no longer compatible with the library `%s',
-which was used in earlier releases. Please remove it, so that
-Magit can use the successor `%s' without the obsolete
-library getting in the way. Then restart Emacs.\n"
- (car it) (car it) (cdr it)) :error))))
-
-(defvar magit--remotes-using-recent-git nil)
-
-(defun magit-tramp-asserts (directory)
- (-when-let (remote (file-remote-p directory))
- (unless (member remote magit--remotes-using-recent-git)
- (-if-let (version (let ((default-directory directory))
- (magit-git-version)))
- (if (version<= magit--minimal-git version)
- (push version magit--remotes-using-recent-git)
- (display-warning 'magit (format "\
-Magit requires Git >= %s, but on %s the version is %s.
-
-If multiple Git versions are installed on the host then the
-problem might be that TRAMP uses the wrong executable.
-
-First check the value of `magit-git-executable'. Its value is
-used when running git locally as well as when running it on a
-remote host. The default value is \"git\", except on Windows
-where an absolute path is used for performance reasons.
-
-If the value already is just \"git\" but TRAMP never-the-less
-doesn't use the correct executable, then consult the info node
-`(tramp)Remote programs'.\n" magit--minimal-git remote version) :error))
- (display-warning 'magit (format "\
-Magit cannot find Git on %s.
-
-First check the value of `magit-git-executable'. Its value is
-used when running git locally as well as when running it on a
-remote host. The default value is \"git\", except on Windows
-where an absolute path is used for performance reasons.
-
-If the value already is just \"git\" but TRAMP never-the-less
-doesn't find the executable, then consult the info node
-`(tramp)Remote programs'.\n" remote) :error)))))
-
-(define-obsolete-function-alias 'global-magit-file-buffer-mode
- 'global-magit-file-mode "Magit 2.3.0")
-
-(define-obsolete-function-alias 'magit-insert-head-header
- 'magit-insert-head-branch-header "Magit 2.4.0")
-
-(define-obsolete-function-alias 'magit-insert-upstream-header
- 'magit-insert-upstream-branch-header "Magit 2.4.0")
-
-(define-obsolete-function-alias 'magit-insert-pull-branch-header
- 'magit-insert-upstream-branch-header "Magit 2.4.0")
-
-(provide 'magit)
-
-(cl-eval-when (load eval)
- (require 'magit-sequence)
- (require 'magit-commit)
- (require 'magit-remote)
- (require 'magit-bisect)
- (require 'magit-stash)
- (require 'magit-blame)
- (unless (load "magit-autoloads" t t)
- (require 'magit-submodule)
- (require 'magit-ediff)
- (require 'magit-extras)
- (require 'git-rebase)))
-
-(if after-init-time
- (progn (magit-startup-asserts)
- (magit-version))
- (add-hook 'after-init-hook #'magit-startup-asserts t)
- (add-hook 'after-init-hook #'magit-version t))
-
-;; Local Variables:
-;; coding: utf-8
-;; indent-tabs-mode: nil
-;; End:
-;;; magit.el ends here
+++ /dev/null
-This is magit.info, produced by makeinfo version 5.2 from magit.texi.
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- You can redistribute this document and/or modify it under the terms
- of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- This document is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Magit: (magit). Using Git from Emacs with Magit.
-END-INFO-DIR-ENTRY
-
-\1f
-Indirect:
-magit.info-1: 1222
-magit.info-2: 314831
-\1f
-Tag Table:
-(Indirect)
-Node: Top\7f1222
-Node: Introduction\7f5928
-Node: Installation\7f10621
-Node: Updating from an older release\7f10996
-Node: Installing from an Elpa archive\7f12591
-Node: Installing from the Git repository\7f13930
-Node: Post-installation tasks\7f16726
-Node: Getting started\7f18115
-Node: Interface concepts\7f23850
-Node: Modes and Buffers\7f24124
-Node: Switching Buffers\7f25870
-Node: Naming Buffers\7f28934
-Node: Quitting Windows\7f31769
-Node: Automatic Refreshing of Magit Buffers\7f33401
-Node: Automatic Saving of File-Visiting Buffers\7f36169
-Node: Automatic Reverting of File-Visiting Buffers\7f37354
-Node: Risk of Reverting Automatically\7f42350
-Node: Sections\7f44733
-Node: Section movement\7f45674
-Node: Section visibility\7f49601
-Node: Section hooks\7f53192
-Node: Section types and values\7f55473
-Node: Section options\7f56743
-Node: Popup buffers and prefix commands\7f57215
-Node: Completion and confirmation\7f58529
-Node: Running Git\7f61435
-Node: Viewing Git output\7f61671
-Node: Running Git manually\7f62671
-Node: Git executable\7f64797
-Node: Global Git arguments\7f66804
-Node: Inspecting\7f67611
-Node: Status buffer\7f68738
-Node: Status sections\7f71261
-Node: Status header sections\7f76008
-Node: Status options\7f78567
-Node: Logging\7f79291
-Node: Refreshing logs\7f81820
-Node: Log Buffer\7f83205
-Node: Select from log\7f86294
-Node: Reflog\7f87234
-Node: Diffing\7f87712
-Node: Refreshing diffs\7f90524
-Node: Diff buffer\7f93505
-Node: Diff options\7f95407
-Node: Revision buffer\7f97039
-Node: Ediffing\7f97994
-Node: References buffer\7f101043
-Node: References sections\7f105753
-Node: Bisecting\7f106628
-Node: Visiting blobs\7f108124
-Node: Blaming\7f108633
-Node: Manipulating\7f111953
-Node: Repository setup\7f112245
-Node: Staging and unstaging\7f113285
-Node: Staging from file-visiting buffers\7f117180
-Node: Applying\7f118348
-Node: Committing\7f119991
-Node: Initiating a commit\7f120574
-Node: Editing commit messages\7f123886
-Node: Branching\7f134282
-Node: Merging\7f147096
-Node: Rebasing\7f149180
-Node: Editing rebase sequences\7f152128
-Node: Rebase sequence log\7f155162
-Node: Cherry picking\7f161906
-Node: Reverting\7f163512
-Node: Resetting\7f164875
-Node: Stashing\7f166385
-Node: Transferring\7f169530
-Node: Remotes\7f169768
-Node: Fetching\7f171054
-Node: Pulling\7f172148
-Node: Pushing\7f172994
-Node: Creating and sending patches\7f177443
-Node: Applying patches\7f178138
-Node: Miscellaneous\7f179136
-Node: Tagging\7f179427
-Node: Notes\7f180212
-Node: Submodules\7f182737
-Node: Common commands\7f184057
-Node: Wip modes\7f185805
-Node: Minor mode for buffers visiting files\7f192541
-Node: Minor mode for buffers visiting blobs\7f194684
-Node: Customizing\7f195489
-Node: Per-repository configuration\7f197161
-Node: Essential settings\7f198795
-Node: Safety\7f199119
-Node: Performance\7f200952
-Node: Plumbing\7f207181
-Node: Calling Git\7f207809
-Node: Getting a value from Git\7f209332
-Node: Calling Git for effect\7f212436
-Node: Section plumbing\7f218940
-Node: Creating sections\7f219168
-Node: Section selection\7f222971
-Node: Matching sections\7f224651
-Node: Refreshing buffers\7f229853
-Node: Conventions\7f232988
-Node: Confirmation and completion\7f233165
-Node: Theming Faces\7f234063
-Node: FAQ\7f242214
-Node: Magit is slow\7f243547
-Node: I changed several thousand files at once and now Magit is unusable\7f243748
-Node: I am having problems committing\7f244464
-Node: I don't understand how branching and pushing work\7f244922
-Node: I don't like the key binding in v24\7f245291
-Node: I cannot install the pre-requisites for Magit v2\7f245630
-Node: I am using an Emacs release older than v244\7f246095
-Node: I am using a Git release older than v194\7f247708
-Node: I am using MS Windows and cannot push with Magit\7f248695
-Node: How to install the gitman info manual?\7f249274
-Node: How can I show Git's output?\7f251802
-Node: Expanding a file to show the diff causes it to disappear\7f252614
-Node: Point is wrong in the COMMIT_EDITMSG buffer\7f253140
-Node: Can Magit be used as ediff-version-control-package?\7f254158
-Node: How to show diffs for gpg-encrypted files?\7f256182
-Node: Emacs 245 hangs when loading Magit\7f256773
-Node: Symbol's value as function is void --some\7f257342
-Node: Where is the branch manager\7f257662
-Node: Keystroke Index\7f257947
-Node: Command Index\7f285293
-Node: Function Index\7f314831
-Node: Variable Index\7f326614
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
+++ /dev/null
-This is magit.info, produced by makeinfo version 5.2 from magit.texi.
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- You can redistribute this document and/or modify it under the terms
- of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- This document is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Magit: (magit). Using Git from Emacs with Magit.
-END-INFO-DIR-ENTRY
-
-\1f
-File: magit.info, Node: Top, Next: Introduction, Up: (dir)
-
-Magit User Manual
-*****************
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- You can redistribute this document and/or modify it under the terms
- of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- This document is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
-* Menu:
-
-* Introduction::
-* Installation::
-* Getting started::
-* Interface concepts::
-* Inspecting::
-* Manipulating::
-* Transferring::
-* Miscellaneous::
-* Customizing::
-* Plumbing::
-* FAQ::
-* Keystroke Index::
-* Command Index::
-* Function Index::
-* Variable Index::
-
-— The Detailed Node Listing —
-
-Installation
-
-* Updating from an older release::
-* Installing from an Elpa archive::
-* Installing from the Git repository::
-* Post-installation tasks::
-
-Interface concepts
-
-* Modes and Buffers::
-* Sections::
-* Popup buffers and prefix commands::
-* Completion and confirmation::
-* Running Git::
-
-Modes and Buffers
-
-* Switching Buffers::
-* Naming Buffers::
-* Quitting Windows::
-* Automatic Refreshing of Magit Buffers::
-* Automatic Saving of File-Visiting Buffers::
-* Automatic Reverting of File-Visiting Buffers::
-
-Sections
-
-* Section movement::
-* Section visibility::
-* Section hooks::
-* Section types and values::
-* Section options::
-
-Running Git
-
-* Viewing Git output::
-* Running Git manually::
-* Git executable::
-* Global Git arguments::
-
-Inspecting
-
-* Status buffer::
-* Logging::
-* Diffing::
-* Ediffing::
-* References buffer::
-* Bisecting::
-* Visiting blobs::
-* Blaming::
-
-Status buffer
-
-* Status sections::
-* Status header sections::
-* Status options::
-
-Logging
-
-* Refreshing logs::
-* Log Buffer::
-* Select from log::
-* Reflog::
-
-Diffing
-
-* Refreshing diffs::
-* Diff buffer::
-* Diff options::
-* Revision buffer::
-
-References buffer
-
-* References sections::
-
-Manipulating
-
-* Repository setup::
-* Staging and unstaging::
-* Applying::
-* Committing::
-* Branching::
-* Merging::
-* Rebasing::
-* Cherry picking::
-* Resetting::
-* Stashing::
-
-Staging and unstaging
-
-* Staging from file-visiting buffers::
-
-Committing
-
-* Initiating a commit::
-* Editing commit messages::
-
-Rebasing
-
-* Editing rebase sequences::
-* Rebase sequence log::
-
-Cherry picking
-
-* Reverting::
-
-Transferring
-
-* Remotes::
-* Fetching::
-* Pulling::
-* Pushing::
-* Creating and sending patches::
-* Applying patches::
-
-Miscellaneous
-
-* Tagging::
-* Notes::
-* Submodules::
-* Common commands::
-* Wip modes::
-* Minor mode for buffers visiting files::
-* Minor mode for buffers visiting blobs::
-
-Customizing
-
-* Per-repository configuration::
-* Essential settings::
-
-Essential settings
-
-* Safety::
-* Performance::
-
-Plumbing
-
-* Calling Git::
-* Section plumbing::
-* Refreshing buffers::
-* Conventions::
-
-Calling Git
-
-* Getting a value from Git::
-* Calling Git for effect::
-
-Section plumbing
-
-* Creating sections::
-* Section selection::
-* Matching sections::
-
-Conventions
-
-* Confirmation and completion::
-* Theming Faces::
-
-FAQ
-
-* Magit is slow::
-* I changed several thousand files at once and now Magit is unusable::
-* I am having problems committing::
-* I don't understand how branching and pushing work::
-* I don’t like the key binding in v2.4: I don't like the key binding in v24.
-* I cannot install the pre-requisites for Magit v2::
-* I am using an Emacs release older than v24.4: I am using an Emacs release older than v244.
-* I am using a Git release older than v1.9.4: I am using a Git release older than v194.
-* I am using MS Windows and cannot push with Magit::
-* How to install the gitman info manual?::
-* How can I show Git's output?::
-* Expanding a file to show the diff causes it to disappear::
-* Point is wrong in the COMMIT_EDITMSG buffer::
-* Can Magit be used as ediff-version-control-package?::
-* How to show diffs for gpg-encrypted files?::
-* Emacs 24.5 hangs when loading Magit: Emacs 245 hangs when loading Magit.
-* Symbol's value as function is void --some::
-* Where is the branch manager::
-
-
-\1f
-File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
-
-1 Introduction
-**************
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Staging and otherwise applying changes is one of the most important
-features in a Git porcelain and here Magit outshines anything else,
-including Git itself. Git’s own staging interface (‘git add --patch’)
-is so cumbersome that many users only use it in exceptional cases. In
-Magit staging a hunk or even just part of a hunk is as trivial as
-staging all changes made to a file.
-
- The most visible part of Magit’s interface is the status buffer,
-which displays information about the current repository. Its content is
-created by running several Git commands and making their output
-actionable. Among other things, it displays information about the
-current branch, lists unpulled and unpushed changes and contains
-sections displaying the staged and unstaged changes. That might sound
-noisy, but, since sections are collapsible, it’s not.
-
- To stage or unstage a change one places the cursor on the change and
-then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the
-region is active (i.e. when there is a selection) several files or
-hunks, or even just part of a hunk. The change or changes that these
-commands - and many others - would act on are highlighted.
-
- Magit also implements several other "apply variants" in addition to
-staging and unstaging. One can discard or reverse a change, or apply it
-to the working tree. Git’s own porcelain only supports this for staging
-and unstaging and you would have to do something like ‘git diff ... |
-??? | git apply ...’ to discard, revert, or apply a single hunk on the
-command line. In fact that’s exactly what Magit does internally (which
-is what lead to the term "apply variants").
-
- Magit isn’t just for Git experts, but it does assume some prior
-experience with Git as well as Emacs. That being said, many users have
-reported that using Magit was what finally taught them what Git is
-capable of and how to use it to its fullest. Other users wished they
-had switched to Emacs sooner so that they would have gotten their hands
-on Magit earlier.
-
- While one has to know the basic features of Emacs to be able to make
-full use of Magit, acquiring just enough Emacs skills doesn’t take long
-and is worth it, even for users who prefer other editors. Vim users are
-advised to give Evil (https://bitbucket.org/lyro/evil/wiki/Home), the
-"Extensible VI Layer for Emacs", and Spacemacs
-(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused
-on Evil" a try.
-
- Magit provides a consistent and efficient Git porcelain. After a
-short learning period, you will be able to perform most of your daily
-version control tasks faster than you would on the command line. You
-will likely also start using features that seemed too daunting in the
-past.
-
- Magit fully embraces Git. It exposes many advanced features using a
-simple but flexible interface instead of only wrapping the trivial ones
-like many GUI clients do. Of course Magit supports logging, cloning,
-pushing, and other commands that usually don’t fail in spectacular ways;
-but it also supports tasks that often cannot be completed in a single
-step. Magit fully supports tasks such as merging, rebasing,
-cherry-picking, reverting, and blaming by not only providing a command
-to initiate these tasks but also by displaying context sensitive
-information along the way and providing commands that are useful for
-resolving conflicts and resuming the sequence after doing so.
-
- Magit wraps and in many cases improves upon at least the following
-Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’,
-‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’,
-‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’,
-‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’,
-‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’,
-‘submodule’, and ‘tag’. Many more Magit porcelain commands are
-implemented on top of Git plumbing commands.
-
-\1f
-File: magit.info, Node: Installation, Next: Getting started, Prev: Introduction, Up: Top
-
-2 Installation
-**************
-
-Magit can be installed using Emacs’ package manager or manually from its
-development repository.
-
-* Menu:
-
-* Updating from an older release::
-* Installing from an Elpa archive::
-* Installing from the Git repository::
-* Post-installation tasks::
-
-\1f
-File: magit.info, Node: Updating from an older release, Next: Installing from an Elpa archive, Up: Installation
-
-2.1 Updating from an older release
-==================================
-
-When updating from ‘1.2.*’ or ‘1.4.*’, you should first uninstall Magit
-and some of its dependencies and restart Emacs before installing the
-latest release.
-
- • The old Magit installation has to be removed because some macros
- have changed and using the old definitions when building the new
- release would lead to very strange results, including compile
- errors. This is due to a limitation in Emacs’ package manager or
- rather Emacs itself: it’s not possible to reliably unload a feature
- or even all features belonging to a package.
-
- • Furthermore the old dependencies ‘git-commit-mode’ and
- ‘git-rebase-mode’ have to be removed because they are no longer
- used by the ‘2.1.0’ release and later, and get in the way of their
- successors ‘git-commit’ and ‘git-rebase’.
-
- So please uninstall the packages ‘magit’, ‘git-commit-mode’, and
-‘git-rebase-mode’. Then quit Emacs and start a new instance. Only then
-follow the instructions in either one of the next two sections.
-
- Also note that starting with the ‘2.1.0’ release, Magit requires at
-least Emacs ‘24.4’ and Git ‘1.9.4’. You should make sure you have at
-least these releases installed before updating Magit. And if you
-connect to remote hosts using Tramp, then you should also make sure to
-install a recent enough Git version on these hosts.
-
-\1f
-File: magit.info, Node: Installing from an Elpa archive, Next: Installing from the Git repository, Prev: Updating from an older release, Up: Installation
-
-2.2 Installing from an Elpa archive
-===================================
-
-If you are updating from a release older than ‘2.1.0’, then you have to
-first uninstall the old version. See *note Updating from an older
-release: Updating from an older release.
-
- Magit is available from Melpa and Melpa-Stable. If you haven’t used
-Emacs’ package manager before, then it is high time you familiarize
-yourself with it by reading the documentation in the Emacs manual, see
-*note (emacs)Packages::. Then add one of the archives to
-‘package-archives’:
-
- • To use Melpa:
-
- (require 'package)
- (add-to-list 'package-archives
- '("melpa" . "http://melpa.org/packages/") t)
-
- • To use Melpa-Stable:
-
- (require 'package)
- (add-to-list 'package-archives
- '("melpa-stable" . "http://stable.melpa.org/packages/") t)
-
- Once you have added your preferred archive, you need to update the
-local package list using:
-
- M-x package-refresh-contents RET
-
- Once you have done that, you can install Magit and its dependencies
-using:
-
- M-x package-install RET magit RET
-
- Now see *note Post-installation tasks: Post-installation tasks.
-
-\1f
-File: magit.info, Node: Installing from the Git repository, Next: Post-installation tasks, Prev: Installing from an Elpa archive, Up: Installation
-
-2.3 Installing from the Git repository
-======================================
-
-If you are updating from a release older than ‘2.1.0’, then you have to
-first uninstall the old version. See *note Updating from an older
-release: Updating from an older release.
-
- Magit depends on the ‘dash’ and ‘with-editor’ library which are
-available from Melpa and Melpa-Stable. Install them using ‘M-x
-package-install RET <package> RET’. Of course you may also install them
-manually from their development repository, but I won’t cover that here.
-
- (An older release of Magit is also available from Marmalade, but no
-new versions will be uploaded in the future. Marmalade’s maintainer has
-stopped responding to requests from package maintainers who are having
-difficulties or require him to create an account so that they can upload
-their packages in the first place.)
-
- Then clone the Magit repository:
-
- $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit
- $ cd ~/.emacs.d/site-lisp/magit
-
- Then compile the libraries and generate the info manuals:
-
- $ make
-
- If you haven’t installed ‘dash’ and ‘with-editor’ using Elpa or at
-‘/path/to/magit/../<package>’, then you have to tell ‘make’ where to
-find them. To do so create ‘/path/to/magit/config.mk’ with the
-following content before running ‘make’:
-
- LOAD_PATH = -L /path/to/magit/lisp
- LOAD_PATH += -L /path/to/dash
- LOAD_PATH += -L /path/to/with-editor
-
- Finally add this to your init file:
-
- (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp")
- (require 'magit)
-
- (with-eval-after-load 'info
- (info-initialize)
- (add-to-list 'Info-directory-list
- "~/.emacs.d/site-lisp/magit/Documentation/"))
-
- Note that you have to add the ‘lisp’ subdirectory to the ‘load-path’,
-not the top-level of the repository, and that elements of ‘load-path’
-should not end with a slash, while those of ‘Info-directory-list’
-should.
-
- Instead of requiring the feature ‘magit’, you could load just the
-autoload definitions, by loading the file ‘magit-autoloads.el’.
-
- Instead of running Magit directly from the repository by adding that
-to the ‘load-path’, you might want to instead install it in some other
-directory using ‘sudo make install’ and setting ‘load-path’ accordingly.
-
- To update Magit use:
-
- $ git pull
- $ make
-
- At times it might be necessary to run ‘make clean all’ instead.
-
- To view all available targets use ‘make help’.
-
- Now see *note Post-installation tasks: Post-installation tasks.
-
-\1f
-File: magit.info, Node: Post-installation tasks, Prev: Installing from the Git repository, Up: Installation
-
-2.4 Post-installation tasks
-===========================
-
-After installing Magit you should verify that you are indeed using the
-Magit, Git, and Emacs releases you think you are using. It’s best to
-restart Emacs before doing so, to make sure you are not using an
-outdated value for ‘load-path’.
-
- M-x magit-version RET
-
- should display something like
-
- Magit 2.4.0, Git 2.7.0, Emacs 24.5.1
-
- Then you might also want to read about options that many users likely
-want to customize. See *note Essential settings: Essential settings.
-
- To be able to follow cross references to Git manpages found in this
-manual, you might also have to manually install the ‘gitman’ info
-manual, or advice ‘Info-follow-nearest-node’ to instead open the actual
-manpage. See *note How to install the gitman info manual?: How to
-install the gitman info manual?.
-
- If you are completely new to Magit then see *note Getting started:
-Getting started.
-
- If you have used an older Magit release before, then you should have
-a look at the release notes <https://github.com/magit/magit/releases>.
-
- And last but not least please consider making a donation, to ensure
-that I can keep working on Magit. See <http://magit.vc/donations.html>
-for various donation options.
-
-\1f
-File: magit.info, Node: Getting started, Next: Interface concepts, Prev: Installation, Up: Top
-
-3 Getting started
-*****************
-
-This section describes the most essential features that many Magitians
-use on a daily basis. It only scratches the surface but should be
-enough to get you started.
-
- (You might want to create a repository just for this walk-through,
-e.g. by cloning an existing repository. If you don’t use a separate
-repository then make sure you create a snapshot as described below).
-
- To display information about the current Git repository, type ‘M-x
-magit-status’. You will be doing that so often that it is best to bind
-this command globally:
-
- (global-set-key (kbd "C-x g") 'magit-status)
-
- Most Magit commands are commonly invoked from this buffer. It should
-be considered the primary interface to interact with Git using Magit.
-There are many other Magit buffers, but they are usually created from
-this buffer.
-
- Depending on what state your repository is in, this buffer will
-contain sections titled "Staged changes", "Unstaged changes", "Unpulled
-commits", "Unpushed commits", and/or some others.
-
- If some staged and/or unstaged changes exist, you should back them up
-now. Type ‘z’ to show the stashing popup buffer featuring various stash
-variants and arguments that can be passed to these commands. Do not
-worry about those for now, just type ‘Z’ (uppercase) to create a stash
-while also keeping the index and work tree intact. The status buffer
-should now also contain a section titled "Stashes".
-
- Otherwise, if there are no uncommitted changes, you should create
-some now by editing and saving some of the tracked files. Then go back
-to the status buffer, while at the same time refreshing it, by typing
-‘C-x g’. (When the status buffer, or any Magit buffer for that matter,
-is the current buffer, then you can also use just ‘g’ to refresh it).
-
- Move between sections using ‘p’ and ‘n’. Note that the bodies of
-some sections are hidden. Type ‘TAB’ to expand or collapse the section
-at point. You can also use ‘C-tab’ to cycle the visibility of the
-current section and its children. Move to a file section inside the
-section named "Unstaged changes" and type ‘s’ to stage the changes you
-have made to that file. That file now appears under "Staged changes".
-
- Magit can stage and unstage individual hunks, not just complete
-files. Move to the file you have just staged, expand it using ‘TAB’,
-move to one of the hunks using ‘n’, and unstage just that by typing ‘u’.
-Note how the staging (‘s’) and unstaging (‘u’) commands operate on the
-change at point. Many other commands behave the same way.
-
- You can also un-/stage just part of a hunk. Inside the body of a
-hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and
-move down until some added and removed lines fall inside the region but
-not all of them. Again type ‘s’ to stage.
-
- It’s also possible to un-/stage multiple files at once. Move to a
-file section, type ‘C-SPC’, move to the next file using ‘n’, and then
-‘s’ to stage both files. Note that both the mark and point have to be
-on the headings of sibling sections for this to work. If the region
-looks like it does in other buffers, then it doesn’t select Magit
-sections that can be acted on as a unit.
-
- And then of course you want to commit your changes. Type ‘c’. This
-shows the committing popup buffer featuring various commit variants and
-arguments that can be passed to ‘git commit’. Do not worry about those
-for now. We want to create a "normal" commit, which is done by typing
-‘c’ again.
-
- Now two new buffers appear. One is for writing the commit message,
-the other shows a diff with the changes that are about to committed.
-Write a message and then type ‘C-c C-c’ to actually create the commit.
-
- You probably don’t want to push the commit you just created because
-you just committed some random changes, but if that is not the case you
-could push it by typing ‘P’ to bring up the push popup and then ‘P’
-again to push to the configured upstream. (If the upstream is not
-configured, then you would be prompted for the push target instead.)
-
- Instead we are going to undo the changes made so far. Bring up the
-log for the current branch by typing ‘l l’, move to the last commit
-created before starting with this walk through using ‘n’, and do a hard
-reset using ‘C-u x’. *WARNING*: this discards all uncommitted changes.
-If you did not follow the advice about using a separate repository for
-these experiments and did not create a snapshot of uncommitted changes
-before starting to try out Magit, then don’t do this.
-
- So far we have mentioned the commit, push, and log popups. These are
-probably among the popups you will be using the most, but many others
-exist. To show a popup with all other popups (as well as the various
-apply commands), type ‘h’. Try a few.
-
- The key bindings in that popup correspond to the bindings in Magit
-buffers, including but not limited to the status buffer. So you could
-type ‘h d’ to bring up the diff popup, but once you remember that "d"
-stands for "diff", you would usually do so by just typing ‘d’. But the
-"popup of popups" is useful even once you have memorized all the
-bindings, as it can provide easy access to Magit commands from non-Magit
-buffers. So you should bind this globally too:
-
- (global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
-
- You might also want to enable ‘global-magit-file-mode’ (see *note
-Minor mode for buffers visiting files: Minor mode for buffers visiting
-files.).
-
-\1f
-File: magit.info, Node: Interface concepts, Next: Inspecting, Prev: Getting started, Up: Top
-
-4 Interface concepts
-********************
-
-* Menu:
-
-* Modes and Buffers::
-* Sections::
-* Popup buffers and prefix commands::
-* Completion and confirmation::
-* Running Git::
-
-\1f
-File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface concepts
-
-4.1 Modes and Buffers
-=====================
-
-Magit provides several major-modes. For each of these modes there
-usually exists only one buffer per repository. Separate modes and thus
-buffers exist for commits, diffs, logs, and some other things.
-
- Besides these special purpose buffers, there also exists an overview
-buffer, called the *status buffer*. Its usually from this buffer that
-the user invokes Git commands, or creates or visits other buffers.
-
- In this manual we often speak about "Magit buffers". By that we mean
-buffers whose major-modes derive from ‘magit-mode’.
-
-‘M-x magit-toggle-buffer-lock’ (‘magit-toggle-buffer-lock’)
-
- This command locks the current buffer to its value or if the buffer
- is already locked, then it unlocks it.
-
- Locking a buffer to its value, prevents it from being reused to
- display another value. The name of a locked buffer contains its
- value, which allows telling it apart from other locked buffers and
- the unlocked buffer.
-
- Not all Magit buffers can be locked to their values, for example it
- wouldn’t make sense to lock a status buffer.
-
- There can only be a single unlocked buffer using a certain
- major-mode per repository. So when a buffer is being unlocked and
- another unlocked buffer already exists for that mode and
- repository, then the former buffer is instead deleted and the
- latter is displayed in its place.
-
-* Menu:
-
-* Switching Buffers::
-* Naming Buffers::
-* Quitting Windows::
-* Automatic Refreshing of Magit Buffers::
-* Automatic Saving of File-Visiting Buffers::
-* Automatic Reverting of File-Visiting Buffers::
-
-\1f
-File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers
-
-4.1.1 Switching Buffers
------------------------
-
- -- Function: magit-display-buffer buffer
-
- This function is a wrapper around ‘display-buffer’ and is used to
- display any Magit buffer. It displays BUFFER in some window and,
- unlike ‘display-buffer’, also selects that window, provided
- ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks
- mentioned below.
-
- -- Variable: magit-display-buffer-noselect
-
- When this is non-nil, then ‘magit-display-buffer’ only displays the
- buffer but forgoes also selecting the window. This variable should
- not be set globally, it is only intended to be let-bound, by code
- that automatically updates "the other window". This is used for
- example when the revision buffer is updated when you move inside
- the log buffer.
-
- -- User Option: magit-display-buffer-function
-
- The function specified here is called by ‘magit-display-buffer’
- with one argument, a buffer, to actually display that buffer. This
- function should call ‘display-buffer’ with that buffer as first and
- a list of display actions as second argument.
-
- Instead of using a wrapper around ‘display-buffer’, that function
- itself can be used here, in which case the display actions have to
- be specified by adding them to ‘display-buffer-alist’ instead.
-
- To learn about display actions, see *note (elisp)Choosing a Window
- for Display::.
-
- -- Function: magit-display-buffer-traditional buffer
-
- This function is the current default value of the option
- ‘magit-display-buffer-function’. Before that option and this
- function were added, the behavior was hard-coded in many places all
- over the code base but now all the rules are contained in this one
- function (except for the "noselect" special case mentioned above).
-
- If you want to use different rules, then a good way of doing that
- is to start with a copy of this function and then adjust it to your
- needs. More functions to choose from will be added in the future,
- and eventually the default will change.
-
- -- User Option: magit-pre-display-buffer-hook
-
- This hook is run by ‘magit-display-buffer’ before displaying the
- buffer.
-
- -- Function: magit-save-window-configuration
-
- This function saves the current window configuration. Later when
- the buffer is buried, it may be restored by
- ‘magit-restore-window-configuration’.
-
- -- User Option: magit-post-display-buffer-hook
-
- This hook is run by ‘magit-display-buffer’ after displaying the
- buffer.
-
- -- Function: magit-maybe-set-dedicated
-
- This function remembers if a new window had to be created to
- display the buffer, or whether an existing window was reused. This
- information is later used by ‘magit-mode-quit-window’, to determine
- whether the window should be deleted when its last Magit buffer is
- buried.
-
-\1f
-File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers
-
-4.1.2 Naming Buffers
---------------------
-
- -- User Option: magit-generate-buffer-name-function
-
- The function used to generate the names of Magit buffers.
-
- Such a function should take the options
- ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’
- into account. If it doesn’t, then should be clearly stated in the
- doc-string. And if it supports %-sequences beyond those mentioned
- in the doc-string of the option ‘magit-buffer-name-format’, then
- its own doc-string should describe the additions.
-
- -- Function: magit-generate-buffer-name-default-function mode
-
- This function returns a buffer name suitable for a buffer whose
- major-mode is MODE and which shows information about the repository
- in which ‘default-directory’ is located.
-
- This function uses ‘magit-buffer-name-format’ and supporting all of
- the %-sequences mentioned the documentation of that option. It
- also respects the option ‘magit-uniquify-buffer-names’.
-
- -- User Option: magit-buffer-name-format
-
- The format string used to name Magit buffers.
-
- At least the following %-sequences are supported:
-
- • ‘%m’
-
- The name of the major-mode, but with the ‘-mode’ suffix
- removed.
-
- • ‘%M’
-
- Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’.
-
- • ‘%v’
-
- The value the buffer is locked to, in parentheses, or an empty
- string if the buffer is not locked to a value.
-
- • ‘%V’
-
- Like ‘%v’, but the string is prefixed with a space, unless it
- is an empty string.
-
- • ‘%t’
-
- The top-level directory of the working tree of the repository,
- or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation
- of that.
- The value should always contain either ‘%m’ or ‘%M’, ‘%v’ or ‘%V’,
- and ‘%t’. If ‘magit-uniquify-buffer-names’ is non-nil, then the
- value must end with ‘%t’.
-
- -- User Option: magit-uniquify-buffer-names
-
- This option controls whether the names of Magit buffers are
- uniquified. If the names are not being uniquified, then they
- contain the full path of the top-level of the working tree of the
- corresponding repository. If they are being uniquified, then they
- end with the basename of the top-level, or if that would conflict
- with the name used for other buffers, then the names of all these
- buffers are adjusted until they no longer conflict.
-
- This is done using the ‘uniquify’ package; customize its options to
- control how buffer names are uniquified.
-
-\1f
-File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers
-
-4.1.3 Quitting Windows
-----------------------
-
-‘q’ (‘magit-mode-bury-buffer’)
-
- This command buries the current Magit buffer. With a prefix
- argument, it instead kills the buffer.
-
- -- User Option: magit-bury-buffer-function
-
- The function used to actually bury or kill the current buffer.
-
- ‘magit-mode-bury-buffer’ calls this function with one argument. If
- the argument is non-nil, then the function has to kill the current
- buffer. Otherwise it has to bury it alive. The default value
- currently is ‘magit-restore-window-configuration’.
-
- -- Function: magit-restore-window-configuration kill-buffer
-
- Bury or kill the current buffer using ‘quit-window’, which is
- called with KILL-BUFFER as first and the selected window as second
- argument.
-
- Then restore the window configuration that existed right before the
- current buffer was displayed in the selected frame. Unfortunately
- that also means that point gets adjusted in all the buffers, which
- are being displayed in the selected frame.
-
- -- Function: magit-mode-quit-window kill-buffer
-
- Bury or kill the current buffer using ‘quit-window’, which is
- called with KILL-BUFFER as first and the selected window as second
- argument.
-
- Then, if the window was originally created to display a Magit
- buffer and the buried buffer was the last remaining Magit buffer
- that was ever displayed in the window, then that is deleted.
-
-\1f
-File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers
-
-4.1.4 Automatic Refreshing of Magit Buffers
--------------------------------------------
-
-After running a command which may change the state of the current
-repository, the current Magit buffer and the corresponding status buffer
-are refreshed. The status buffer may optionally be automatically
-refreshed whenever a buffer is saved to a file inside the respective
-repository.
-
- Automatically refreshing Magit buffers ensures that the displayed
-information is up-to-date most of the time but can lead to a noticeable
-delay in big repositories. Other Magit buffers are not refreshed to
-keep the delay to a minimum and also because doing so can sometimes be
-undesirable.
-
- Buffers can also be refreshed explicitly, which is useful in buffers
-that weren’t current during the last refresh and after changes were made
-to the repository outside of Magit.
-
-‘g’ (‘magit-refresh’)
-
- This command refreshes the current buffer if its major mode derives
- from ‘magit-mode’ as well as the corresponding status buffer.
-
- If the option ‘magit-revert-buffers’ calls for it, then it also
- reverts all unmodified buffers that visit files being tracked in
- the current repository.
-
-‘G’ (‘magit-refresh-all’)
-
- This command refreshes all Magit buffers belonging to the current
- repository and also reverts all unmodified buffers that visit files
- being tracked in the current repository.
-
- The file-visiting buffers are always reverted, even if
- ‘magit-revert-buffers’ is nil.
-
- -- User Option: magit-refresh-buffer-hook
-
- This hook is run in each Magit buffer that was refreshed during the
- current refresh - normally the current buffer and the status
- buffer.
-
- -- User Option: magit-refresh-status-buffer
-
- When this option is non-nil, then the status buffer is
- automatically refreshed after running git for side-effects, in
- addition to the current Magit buffer, which is always refreshed
- automatically.
-
- Only set this to nil after exhausting all other options to improve
- performance.
-
- -- Function: magit-after-save-refresh-status
-
- This function is intended to be added to ‘after-save-hook’. After
- doing that the corresponding status buffer is refreshed whenever a
- buffer is saved to a file inside a repository.
-
- 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.
-
-\1f
-File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers
-
-4.1.5 Automatic Saving of File-Visiting Buffers
------------------------------------------------
-
-File-visiting buffers are by default saved at certain points in time.
-This doesn’t guarantee that Magit buffers are always up-to-date, but,
-provided one only edits files by editing them in Emacs and uses only
-Magit to interact with Git, one can be fairly confident. When in doubt
-or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh
-explicitly.
-
- -- User Option: magit-save-repository-buffers
-
- This option controls whether file-visiting buffers are saved before
- certain events.
-
- If this is non-nil then all modified file-visiting buffers
- belonging to the current repository may be saved before running
- commands, before creating new Magit buffers, and before explicitly
- refreshing such buffers. If this is ‘dontask’ then this is done
- without user intervention. If it is ‘t’ then the user has to
- confirm each save.
-
-\1f
-File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers
-
-4.1.6 Automatic Reverting of File-Visiting Buffers
---------------------------------------------------
-
-By default Magit automatically reverts buffers that are visiting files
-that are being tracked in a Git repository, after they have changed on
-disk. When using Magit one often changes files on disk by running git,
-i.e. "outside Emacs", making this a rather important feature.
-
- For example, if you discard a change in the status buffer, then that
-is done by running ‘git apply --reverse ...’, and Emacs considers the
-file to have "changed on disk". If Magit did not automatically revert
-the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in
-the visiting buffer before you could continue making changes.
-
- -- User Option: magit-auto-revert-mode
-
- When this mode is enabled, then buffers that visit tracked files,
- are automatically reverted after the visited files changed on disk.
-
- -- User Option: global-auto-revert-mode
-
- When this mode is enabled, then any file-visiting buffer is
- automatically reverted after the visited file changed on disk.
-
- If you like buffers that visit tracked files to be automatically
- reverted, then you might also like any buffer to be reverted, not
- just those visiting tracked files. If that is the case, then
- enable this mode _instead of_ ‘magit-auto-revert-mode’.
-
- -- User Option: magit-auto-revert-immediately
-
- This option controls whether Magit reverts buffers immediately.
-
- If this is non-nil and either ‘global-auto-revert-mode’ or
- ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts
- buffers by explicitly calling ‘auto-revert-buffers’ after running
- git for side-effects.
-
- If ‘auto-revert-use-notify’ is non-nil (and file notifications are
- actually supported), then ‘magit-auto-revert-immediately’ does not
- have to be non-nil, because the reverts happen immediately anyway.
-
- If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are
- both ‘nil’, then reverts happen after ‘auto-revert-interval’
- seconds of user inactivity. That is not desirable.
-
- -- User Option: auto-revert-use-notify
-
- This option controls whether file notification functions should be
- used. Note that this variable unfortunately defaults to ‘t’ even
- on systems on which file notifications cannot be used.
-
- -- User Option: magit-auto-revert-tracked-only
-
- This option controls whether ‘magit-auto-revert-mode’ only reverts
- tracked files or all files that are located inside Git
- repositories, including untracked files and files located inside
- Git’s control directory.
-
- -- Command: auto-revert-mode
-
- The global mode ‘magit-auto-revert-mode’ works by turning on this
- local mode in the appropriate buffers (but
- ‘global-auto-revert-mode’ is implemented differently). You can
- also turn it on or off manually, which might be necessary if Magit
- does not notice that a previously untracked file now is being
- tracked or vice-versa.
-
- -- User Option: auto-revert-stop-on-user-input
-
- This option controls whether the arrival of user input suspends the
- automatic reverts for ‘auto-revert-interval’ seconds.
-
- -- User Option: auto-revert-interval
-
- This option controls for how many seconds Emacs waits before
- resuming suspended reverts.
-
- -- User Option: auto-revert-buffer-list-filter
-
- This option specifies an additional filter used by
- ‘auto-revert-buffers’ to determine whether a buffer should be
- reverted or not.
-
- This option is provided by ‘magit’, which also redefines
- ‘auto-revert-buffers’ to respect it. Magit users who do not turn
- on the local mode ‘auto-revert-mode’ themselves, are best served by
- setting the value to ‘magit-auto-revert-repository-buffers-p’.
-
- However the default is nil, to not disturb users who do use the
- local mode directly. If you experience delays when running Magit
- commands, then you should consider using one of the predicates
- provided by Magit - especially if you also use Tramp.
-
- Users who do turn on ‘auto-revert-mode’ in buffers in which Magit
- doesn’t do that for them, should likely not use any filter. Users
- who turn on ‘global-auto-revert-mode’, do not have to worry about
- this option, because it is disregarded if the global mode is
- enabled.
-
- -- User Option: auto-revert-verbose
-
- This option controls whether Emacs reports when a buffer has been
- reverted.
-
- The options with the ‘auto-revert-’ prefix are located in the Custom
-group named ‘auto-revert’. The other, magit-specific, options are
-located in the ‘magit’ group.
-
-* Menu:
-
-* Risk of Reverting Automatically::
-
-\1f
-File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers
-
-Risk of Reverting Automatically
-...............................
-
-For the vast majority users automatically reverting file-visiting
-buffers after they have changed on disk is harmless.
-
- If a buffer is modified (i.e. it contains changes that haven’t been
-saved yet), then Emacs would refuse to automatically revert it. If you
-save a previously modified buffer, then that results in what is seen by
-Git as an uncommitted change. Git would then refuse to carry out any
-commands that would cause these changes to be lost. In other words, if
-there is anything that could be lost, then either Git or Emacs would
-refuse to discard the changes.
-
- However if you do use file-visiting buffers as a sort of ad hoc
-"staging area", then the automatic reverts could potentially cause data
-loss. So far I have only heard from one user who uses such a workflow.
-
- An example: You visit some file in a buffer, edit it, and save the
-changes. Then, outside of Emacs (or at least not using Magit or by
-saving the buffer) you change the file on disk again. At this point the
-buffer is the only place where the intermediate version still exists.
-You have saved the changes to disk, but that has since been overwritten.
-Meanwhile Emacs considers the buffer to be unmodified (because you have
-not made any changes to it since you last saved it to the visited file)
-and therefore would not object to it being automatically reverted. At
-this point an Auto-Revert mode would kick in. It would check whether
-the buffer is modified and since that is not the case it would revert
-it. The intermediate version would be lost. (Actually you could still
-get it back using the ‘undo’ command.)
-
- If your workflow depends on Emacs preserving the intermediate version
-in the buffer, then you have to disable all Auto-Revert modes. But
-please consider that such a workflow would be dangerous even without
-using an Auto-Revert mode, and should therefore be avoided. If Emacs
-crashed or if you quit Emacs by mistake, then you would also lose the
-buffer content. There would be no autosave file still containing the
-intermediate version (because that was deleted when you saved the
-buffer) and you would not be asked whether you want to safe the buffer
-(because it isn’t modified).
-
-\1f
-File: magit.info, Node: Sections, Next: Popup buffers and prefix commands, Prev: Modes and Buffers, Up: Interface concepts
-
-4.2 Sections
-============
-
-Magit buffers are organized into nested sections, which can be collapsed
-and expanded, similar to how sections are handled in Org mode. Each
-section also has a type, and some sections also have a value. For each
-section type there can also be a local keymap, shared by all sections of
-that type.
-
- Taking advantage of the section value and type, many commands operate
-on the current section, or when the region is active and selects
-sections of the same type, all of the selected sections. Commands that
-only make sense for a particular section type (as opposed to just
-behaving differently depending on the type) are usually bound in section
-type keymaps.
-
-* Menu:
-
-* Section movement::
-* Section visibility::
-* Section hooks::
-* Section types and values::
-* Section options::
-
-\1f
-File: magit.info, Node: Section movement, Next: Section visibility, Up: Sections
-
-4.2.1 Section movement
-----------------------
-
-To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’
-etc), whose global bindings are not shadowed. To move to another
-section use the following commands.
-
-‘p’ (‘magit-section-backward’)
-
- When not at the beginning of a section, then move to the beginning
- of the current section. At the beginning of a section, instead
- move to the beginning of the previous visible section.
-
-‘n’ (‘magit-section-forward’)
-
- Move to the beginning of the next visible section.
-
-‘M-p’ (‘magit-section-backward-siblings’)
-
- Move to the beginning of the previous sibling section. If there is
- no previous sibling section, then move to the parent section
- instead.
-
-‘M-n’ (‘magit-section-forward-siblings’)
-
- Move to the beginning of the next sibling section. If there is no
- next sibling section, then move to the parent section instead.
-
-‘^’ (‘magit-section-up’)
-
- Move to the beginning of the parent of the current section.
-
- The above commands all call the hook ‘magit-section-movement-hook’.
-And, except for the second, the below functions are all members of that
-hook’s default value.
-
- -- Variable: magit-section-movement-hook
-
- This hook is run by all of the above movement commands, after
- arriving at the destination.
-
- -- Function: magit-hunk-set-window-start
-
- This hook function ensures that the beginning of the current
- section is visible, provided it is a ‘hunk’ section. Otherwise, it
- does nothing.
-
- -- Function: magit-section-set-window-start
-
- This hook function ensures that the beginning of the current
- section is visible, regardless of the section’s type. If you add
- this to ‘magit-section-movement-hook’, then you must remove the
- hunk-only variant in turn.
-
- -- Function: magit-log-maybe-show-more-commits
-
- This hook function only has an effect in log buffers, and ‘point’
- is on the "show more" section. If that is the case, then it
- doubles the number of commits that are being shown.
-
- -- Function: magit-log-maybe-update-revision-buffer
-
- When moving inside a log buffer, then this function updates the
- revision buffer, provided it is already being displayed in another
- window of the same frame.
-
- -- Function: magit-log-maybe-update-blob-buffer
-
- When moving inside a log buffer and another window of the same
- frame displays a blob buffer, then this function instead displays
- the blob buffer for the commit at point in that window.
-
- -- Function: magit-status-maybe-update-revision-buffer
-
- When moving inside a status buffer, then this function updates the
- revision buffer, provided it is already being displayed in another
- window of the same frame.
-
- -- Function: magit-status-maybe-update-blob-buffer
-
- When moving inside a status buffer and another window of the same
- frame displays a blob buffer, then this function instead displays
- the blob buffer for the commit at point in that window.
-
- -- User Option: magit-update-other-window-delay
-
- Delay before automatically updating the other window.
-
- When moving around in certain buffers certain other buffers, which
- are being displayed in another window, may optionally be updated to
- display information about the section at point.
-
- When holding down a key to move by more than just one section, then
- that would update that buffer for each section on the way. To
- prevent that, updating the revision buffer is delayed, and this
- option controls for how long. For optimal experience you might
- have to adjust this delay and/or the keyboard repeat rate and delay
- of your graphical environment or operating system.
-
-\1f
-File: magit.info, Node: Section visibility, Next: Section hooks, Prev: Section movement, Up: Sections
-
-4.2.2 Section visibility
-------------------------
-
-Magit provides many commands for changing the visibility of sections,
-but all you need to get started are the next two.
-
-‘TAB’ (‘magit-section-toggle’)
-
- Toggle the visibility of the body of the current section.
-
-‘C-<tab>’ (‘magit-section-cycle’)
-
- Cycle the visibility of current section and its children.
-
-‘M-<tab>’ (‘magit-section-cycle-diffs’)
-
- Cycle the visibility of diff-related sections in the current
- buffer.
-
-‘s-<tab>’ (‘magit-section-cycle-global’)
-
- Cycle the visibility of all sections in the current buffer.
-
- -- Command: magit-section-show-level-1
- -- Command: magit-section-show-level-2
- -- Command: magit-section-show-level-3
- -- Command: magit-section-show-level-4
-
- To show sections surrounding the current section, up to level N,
- press the respective number key (‘1’, ‘2’, ‘3’, or ‘4’).
-
- -- Command: magit-section-show-level-1-all
- -- Command: magit-section-show-level-2-all
- -- Command: magit-section-show-level-3-all
- -- Command: magit-section-show-level-4-all
-
- To show all sections up to level N, press the respective number key
- and meta (‘M-1’, ‘M-2’, ‘M-3’, or ‘M-4’).
-
- Some functions, which are used to implement the above commands, are
-also exposed as commands themselves. By default no keys are bound to
-these commands, as they are generally perceived to be much less useful.
-But your mileage may vary.
-
- -- Command: magit-section-show
-
- Show the body of the current section.
-
- -- Command: magit-section-hide
-
- Hide the body of the current section.
-
- -- Command: magit-section-show-headings
-
- Recursively show headings of children of the current section. Only
- show the headings. Previously shown text-only bodies are hidden.
-
- -- Command: magit-section-show-children
-
- Recursively show the bodies of children of the current section.
- With a prefix argument show children down to the level of the
- current section, and hide deeper children.
-
- -- Command: magit-section-hide-children
-
- Recursively hide the bodies of children of the current section.
-
- -- Command: magit-section-toggle-children
-
- Toggle visibility of bodies of children of the current section.
-
- When a buffer is first created then some sections are shown expanded
-while others are not. This is hard coded. When a buffer is refreshed
-then the previous visibility is preserved. The initial visibility of
-certain sections can also be overwritten using the hook
-‘magit-section-set-visibility-hook’.
-
- -- Variable: magit-section-set-visibility-hook
-
- This hook is run when first creating a buffer and also when
- refreshing an existing buffer, and is used to determine the
- visibility of the section currently being inserted.
-
- Each function is called with one argument, the section being
- inserted. It should return ‘hide’ or ‘show’, or to leave the
- visibility undefined ‘nil’. If no function decides on the
- visibility and the buffer is being refreshed, then the visibility
- is preserved; or if the buffer is being created, then the hard
- coded default is used.
-
- Usually this should only be used to set the initial visibility but
- not during refreshes. If ‘magit-insert-section--oldroot’ is
- non-nil, then the buffer is being refreshed and these functions
- should immediately return ‘nil’.
-
-\1f
-File: magit.info, Node: Section hooks, Next: Section types and values, Prev: Section visibility, Up: Sections
-
-4.2.3 Section hooks
--------------------
-
-Which sections are inserted into certain buffers is controlled with
-hooks. This includes the status and the refs buffers. For other
-buffers, e.g. log, diff, and revision buffers, this is not possible.
-
- For buffers whose sections can be customized by the user, a hook
-variable called ‘magit-TYPE-sections-hook’ exists. This hook should be
-changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the
-Custom interface.
-
- The various available section hook variables are described later in
-this manual along with the appropriate "section inserter functions".
-
- -- Function: magit-add-section-hook hook function &optional at append
- local
-
- Add the function FUNCTION to the value of section hook HOOK.
-
- Add FUNCTION at the beginning of the hook list unless optional
- APPEND is non-nil, in which case FUNCTION is added at the end. If
- FUNCTION already is a member then move it to the new location.
-
- If optional AT is non-nil and a member of the hook list, then add
- FUNCTION next to that instead. Add before or after AT, or replace
- AT with FUNCTION depending on APPEND. If APPEND is the symbol
- ‘replace’, then replace AT with FUNCTION. For any other non-nil
- value place FUNCTION right after AT. If nil, then place FUNCTION
- right before AT. If FUNCTION already is a member of the list but AT
- is not, then leave FUNCTION where ever it already is.
-
- If optional LOCAL is non-nil, then modify the hook’s buffer-local
- value rather than its global value. This makes the hook local by
- copying the default value. That copy is then modified.
-
- HOOK should be a symbol. If HOOK is void, it is first set to nil.
- HOOK’s value must not be a single hook function. FUNCTION should
- be a function that takes no arguments and inserts one or multiple
- sections at point, moving point forward. FUNCTION may choose not
- to insert its section(s), when doing so would not make sense. It
- should not be abused for other side-effects.
-
- To remove a function from a section hook, use ‘remove-hook’.
-
-\1f
-File: magit.info, Node: Section types and values, Next: Section options, Prev: Section hooks, Up: Sections
-
-4.2.4 Section types and values
-------------------------------
-
-Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’.
-Instances of certain section types also have a value. The value of a
-section of type ‘file’, for example, is a file name.
-
- Users usually do not have to worry about a section’s type and value,
-but knowing them can be handy at times.
-
-‘M-x magit-describe-section’ (‘magit-describe-section’)
-
- Show information about the section at point in the echo area, as
- "VALUE [TYPE PARENT-TYPE…] BEGINNING-END".
-
- Many commands behave differently depending on the type of the section
-at point and/or somehow consume the value of that section. But that is
-only one of the reasons why the same key may do something different,
-depending on what section is current.
-
- Additionally for each section type a keymap *might* be defined, named
-‘magit-TYPE-section-map’. That keymap is used as text property keymap
-of all text belonging to any section of the respective type. If such a
-map does not exist for a certain type, then you can define it yourself,
-and it will automatically be used.
-
-\1f
-File: magit.info, Node: Section options, Prev: Section types and values, Up: Sections
-
-4.2.5 Section options
----------------------
-
-This section describes options that have an effect on more than just a
-certain type of sections. As you can see there are not many of those.
-
- -- User Option: magit-section-show-child-count
-
- Whether to append the number of children to section headings. This
- only affects sections that could benefit from this information.
-
-\1f
-File: magit.info, Node: Popup buffers and prefix commands, Next: Completion and confirmation, Prev: Sections, Up: Interface concepts
-
-4.3 Popup buffers and prefix commands
-=====================================
-
-Many Magit commands are implemented using *popup buffers*. First the
-user invokes a *popup* or *prefix* command, which causes a popup buffer
-with the available *infix* arguments and *suffix* commands to be
-displayed. The user then optionally toggles/sets some arguments and
-finally invokes one of the suffix commands.
-
- This is implemented in the library ‘magit-popup’. Earlier releases
-used the library ‘magit-key-mode’. A future release will switch to a
-yet-to-be-written successor, which will likely be named ‘transient’.
-
- Because ‘magit-popup’ can also be used by other packages without
-having to depend on all of Magit, it is documented in its own manual.
-See *note (magit-popup)Top::.
-
-‘C-c C-c’ (‘magit-dispatch-popup’)
-
- This popup command shows a buffer featuring all other Magit popup
- commands as well as some other commands that are not popup commands
- themselves.
-
- This command is also, or especially, useful outside Magit buffers, so
-you should setup a global binding:
-
- (global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
-
-\1f
-File: magit.info, Node: Completion and confirmation, Next: Running Git, Prev: Popup buffers and prefix commands, Up: Interface concepts
-
-4.4 Completion and confirmation
-===============================
-
-Many commands read a value from the user. By default this is done using
-the built-in function ‘completing-read’, but Magit can instead use
-another completion framework.
-
- -- User Option: magit-completing-read-function
-
- The value of this variable is the function used to perform
- completion. Because functions _intended_ to replace
- ‘completing-read’ often are not fully compatible drop-in
- replacements, and also because Magit expects them to add the
- default choice to the prompt themselves, such functions should not
- be used directly. Instead a wrapper function has to be used.
-
- Currently only the real ‘completing-read’ and Ido
-(http://www.emacswiki.org/emacs/InteractivelyDoThings) are fully
-supported. More frameworks will be supported in the future.
-
- -- Function: magit-builtin-completing-read prompt choices &optional
- predicate require-match initial-input hist def
-
- Perform completion using ‘completion-read’.
-
- -- Function: magit-ido-completing-read prompt choices &optional
- predicate require-match initial-input hist def
-
- Perform completion using ‘ido-completing-read+’ from the package by
- the same name (which you have to explicitly install). Ido itself
- comes with a supposed drop-in replacement ‘ido-completing-read’,
- but that has too many deficits to serve our needs.
-
- By default many commands that could potentially lead to data loss
-have to be confirmed. This includes many very common commands, so this
-can become annoying quickly. Many of these actions can be undone,
-provided ‘magit-wip-before-change-mode’ is turned on (which it is not by
-default, due to performance concerns).
-
- -- User Option: magit-no-confirm
-
- The value of this option is a list of symbols, representing
- commands which do not have to be confirmed by the user before being
- carried out.
-
- When the global mode ‘magit-wip-before-change-mode’ is enabled then
- many commands can be undone. If that mode is enabled then adding
- ‘safe-with-wip’ to this list has the same effect as adding
- ‘discard’, ‘reverse’, ‘stage-all-changes’, and
- ‘unstage-all-changes’.
-
- (add-to-list 'magit-no-confirm 'safe-with-wip)
-
- For a list of all symbols that can be added to the value of this
- variable, see the doc-string.
-
- Note that there are commands that ignore this option and always
-require confirmation, or which can be told not to do so using another
-dedicated option. Also most commands, when acting on multiple sections
-at once always, require confirmation, even when they do respect this
-option when acting on a single section.
-
-\1f
-File: magit.info, Node: Running Git, Prev: Completion and confirmation, Up: Interface concepts
-
-4.5 Running Git
-===============
-
-* Menu:
-
-* Viewing Git output::
-* Running Git manually::
-* Git executable::
-* Global Git arguments::
-
-\1f
-File: magit.info, Node: Viewing Git output, Next: Running Git manually, Up: Running Git
-
-4.5.1 Viewing Git output
-------------------------
-
-Magit runs Git either for side-effects (e.g. when pushing) or to get
-some value (e.g. the name of the current branch). When Git is run for
-side-effects then the output goes into a per-repository log buffer,
-which can be consulted when things don’t go as expected.
-
-‘$’ (‘magit-process’)
-
- This commands displays the process buffer for the current
- repository.
-
- Inside that buffer, the usual key bindings for navigating and showing
-sections are available. There is one additional command.
-
-‘k’ (‘magit-process-kill’)
-
- This command kills the process represented by the section at point.
-
- -- User Option: magit-git-debug
-
- When this is non-nil then the output of all calls to git are logged
- in the process buffer. This is useful when debugging, otherwise it
- just negatively affects performance.
-
-\1f
-File: magit.info, Node: Running Git manually, Next: Git executable, Prev: Viewing Git output, Up: Running Git
-
-4.5.2 Running Git manually
---------------------------
-
-While Magit provides many Emacs commands to interact with Git, it does
-not cover everything. In those cases your existing Git knowledge will
-come in handy. Magit provides some commands for running arbitrary Git
-commands by typing them into the minibuffer, instead of having to switch
-to a shell.
-
-‘!’ (‘magit-run-popup’)
-
- Shows the popup buffer featuring the below suffix commands.
-
- These suffix commands run a Git subcommand. The user input has to
-begin with the subcommand, "git" is assumed.
-
-‘! !’ (‘magit-git-command-topdir’)
-
- This command reads a Git subcommand from the user and executes it
- in the top-level directory of the current repository.
-
-‘! p’ (‘magit-git-command’)
-
- This command reads a Git subcommand from the user and executes it
- in ‘default-directory’. With a prefix argument the command is
- executed in the top-level directory of the current repository
- instead.
-
- These suffix commands run arbitrary shell commands.
-
-‘! s’ (‘magit-shell-command-topdir’)
-
- This command reads a shell command from the user and executes it in
- the top-level directory of the current repository.
-
-‘! S’ (‘magit-shell-command’)
-
- This command reads a shell command from the user and executes it in
- ‘default-directory’. With a prefix argument the command is
- executed in the top-level directory of the current repository
- instead.
-
- These suffix commands start external gui tools.
-
-‘! k’ (‘magit-run-gitk’)
-
- This command runs ‘gitk’ in the current repository.
-
-‘! a’ (‘magit-run-gitk-all’)
-
- This command runs ‘gitk --all’ in the current repository.
-
-‘! b’ (‘magit-run-gitk-branches’)
-
- This command runs ‘gitk --branches’ in the current repository.
-
-‘! g’ (‘magit-run-git-gui’)
-
- This command runs ‘git gui’ in the current repository.
-
-\1f
-File: magit.info, Node: Git executable, Next: Global Git arguments, Prev: Running Git manually, Up: Running Git
-
-4.5.3 Git executable
---------------------
-
-Except on MS Windows, Magit defaults to running Git without specifying
-the path to the git executable. Instead the first executable found by
-Emacs on ‘exec-path’ is used (whose value in turn is set based on the
-value of the environment variable ‘$PATH’ when Emacs was started).
-
- This has the advantage that it continues to work even when using
-Tramp to connect to a remote machine on which the executable is found in
-a different place. The downside is that if you have multiple versions
-of Git installed, then you might end up using another version than the
-one you think you are using.
-
-‘M-x magit-version’ (‘magit-version’)
-
- Shows the currently used versions of Magit, Git, and Emacs in the
- echo area. Non-interactively this just returns the Magit version.
-
- When the ‘system-type’ is ‘windows-nt’, then ‘magit-git-executable’
-is set to an absolute path when Magit is first loaded. This is
-necessary because Git on that platform comes with several wrapper
-scripts for the actual git binary, which are also placed on ‘$PATH’, and
-using one of these wrappers instead of the binary would degrade
-performance horribly.
-
- If Magit doesn’t find the correct executable then you *can* work
-around that by setting ‘magit-git-executable’ to an absolute path. But
-note that doing so is a kludge. It is better to make sure the order in
-the environment variable ‘$PATH’ is correct, and that Emacs is started
-with that environment in effect. If you have to connect from Windows to
-a non-Windows machine, then you must change the value to "git".
-
- -- User Option: magit-git-executable
-
- The git executable used by Magit, either the full path to the
- executable or the string "git" to let Emacs find the executable
- itself, using the standard mechanism for doing such things.
-
-\1f
-File: magit.info, Node: Global Git arguments, Prev: Git executable, Up: Running Git
-
-4.5.4 Global Git arguments
---------------------------
-
- -- User Option: magit-git-global-arguments
-
- The arguments set here are used every time the git executable is
- run as a subprocess. They are placed right after the executable
- itself and before the git command - as in ‘git HERE... COMMAND
- REST’. For valid arguments see *note (gitman)git:: .
-
- Be careful what you add here, especially if you are using Tramp to
- connect to servers with ancient Git versions. Never remove
- anything that is part of the default value, unless you really know
- what you are doing. And think very hard before adding something;
- it will be used every time Magit runs Git for any purpose.
-
-\1f
-File: magit.info, Node: Inspecting, Next: Manipulating, Prev: Interface concepts, Up: Top
-
-5 Inspecting
-************
-
-The functionality provided by Magit can be roughly divided into three
-groups: inspecting existing data, manipulating existing data or adding
-new data, and transferring data. Of course that is a rather crude
-distinction that often falls short, but it’s more useful than no
-distinction at all. This section is concerned with inspecting data, the
-next two with manipulating and transferring it. Then follows a section
-about miscellaneous functionality, which cannot easily be fit into this
-distinction.
-
- Of course other distinctions make sense too, e.g. Git’s distinction
-between porcelain and plumbing commands, which for the most part is
-equivalent to Emacs’ distinction between interactive commands and
-non-interactive functions. All of the sections mentioned before are
-mainly concerned with the porcelain – Magit’s plumbing layer is
-described later.
-
-* Menu:
-
-* Status buffer::
-* Logging::
-* Diffing::
-* Ediffing::
-* References buffer::
-* Bisecting::
-* Visiting blobs::
-* Blaming::
-
-\1f
-File: magit.info, Node: Status buffer, Next: Logging, Up: Inspecting
-
-5.1 Status buffer
-=================
-
-While other Magit buffers contain e.g. one particular diff or one
-particular log, the status buffer contains the diffs for staged and
-unstaged changes, logs for unpushed and unpulled commits, lists of
-stashes and untracked files, and information related to the current
-branch.
-
- During certain incomplete operations – for example when a merge
-resulted in a conflict – additional information is displayed that helps
-proceeding with or aborting the operation.
-
- The command ‘magit-status’ displays the status buffer belonging to
-the current repository in another window. This command is used so often
-that it should be bound globally. We recommend using ‘C-x g’:
-
- (global-set-key (kbd "C-x g") 'magit-status)
-
-‘C-x g’ (‘magit-status’)
-
- Show the status of the current Git repository in a buffer. With a
- prefix argument prompt for a repository to be shown. With two
- prefix arguments prompt for an arbitrary directory. If that
- directory isn’t the root of an existing repository, then offer to
- initialize it as a new repository.
-
- -- User Option: magit-repository-directories
-
- Directories containing Git repositories. Magit checks these
- directories for Git repositories and offers them as choices when
- ‘magit-status’ is used with a prefix argument.
-
- -- User Option: magit-repository-directories-depth
-
- The maximum depth to look for Git repositories. When looking for a
- Git repository below the directories in
- ‘magit-repository-directories’, only descend this many levels deep.
-
- -- Command: ido-enter-magit-status
-
- From an Ido prompt used to open a file, instead drop into
- ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which,
- despite its name, usually causes a Dired buffer to be created.
-
- To make this command available, use something like:
-
- (add-hook 'ido-setup-hook
- (lambda ()
- (define-key ido-completion-map
- (kbd \"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:
-
- (define-key ido-common-completion-map
- (kbd \"C-x g\") 'ido-enter-magit-status)
-
-* Menu:
-
-* Status sections::
-* Status header sections::
-* Status options::
-
-\1f
-File: magit.info, Node: Status sections, Next: Status header sections, Up: Status buffer
-
-5.1.1 Status sections
----------------------
-
-The contents of status buffers is controlled using the hook
-‘magit-status-sections-hook’. See *note Section hooks: Section hooks.
-to learn about such hooks and how to customize them.
-
- -- User Option: magit-status-sections-hook
-
- Hook run to insert sections into a status buffer.
-
- The first function on that hook by default is
-‘magit-insert-status-headers’; it is described in the next section. By
-default the following functions are also members of that hook:
-
- -- Function: magit-insert-merge-log
-
- Insert section for the on-going merge. Display the heads that are
- being merged. If no merge is in progress, do nothing.
-
- -- Function: magit-insert-rebase-sequence
-
- Insert section for the on-going rebase sequence. If no such
- sequence is in progress, do nothing.
-
- -- Function: magit-insert-am-sequence
-
- Insert section for the on-going patch applying sequence. If no
- such sequence is in progress, do nothing.
-
- -- Function: magit-insert-sequencer-sequence
-
- Insert section for the on-going cherry-pick or revert sequence. If
- no such sequence is in progress, do nothing.
-
- -- Function: magit-insert-bisect-output
-
- While bisecting, insert section with output from ‘git bisect’.
-
- -- Function: magit-insert-bisect-rest
-
- While bisecting, insert section visualizing the bisect state.
-
- -- Function: magit-insert-bisect-log
-
- While bisecting, insert section logging bisect progress.
-
- -- Function: magit-insert-untracked-files
-
- Maybe insert a list or tree of untracked files. Do so depending on
- the value of ‘status.showUntrackedFiles’.
-
- -- Function: magit-insert-unstaged-changes
-
- Insert section showing unstaged changes.
-
- -- Function: magit-insert-staged-changes
-
- Insert section showing staged changes.
-
- -- Function: magit-insert-stashes &optional ref heading
-
- Insert the ‘stashes’ section showing reflog for "refs/stash". If
- optional REF is non-nil show reflog for that instead. If optional
- HEADING is non-nil use that as section heading instead of
- "Stashes:".
-
- -- Function: magit-insert-unpulled-from-upstream
-
- Insert section showing commits that haven’t been pulled from the
- upstream branch yet.
-
- -- Function: magit-insert-unpulled-from-pushremote
-
- Insert section showing commits that haven’t been pulled from the
- push-remote branch yet.
-
- -- Function: magit-insert-unpushed-to-upstream
-
- Insert section showing commits that haven’t been pushed to the
- upstream yet.
-
- -- Function: magit-insert-unpushed-to-pushremote
-
- Insert section showing commits that haven’t been pushed to the
- push-remote yet.
-
- The following functions can also be added to the above hook:
-
- -- Function: magit-insert-tracked-files
-
- Insert a tree of tracked files.
-
- -- Function: magit-insert-unpulled-or-recent-commits
-
- Insert section showing unpulled or recent commits. If an upstream
- is configured for the current branch and it is ahead of the current
- branch, then show the missing commits. Otherwise, show the last
- ‘magit-log-section-commit-count’ commits.
-
- -- Function: magit-insert-recent-commits
-
- Insert section showing the last ‘magit-log-section-commit-count’
- commits.
-
- -- User Option: magit-log-section-commit-count
-
- How many recent commits ‘magit-insert-recent-commits’ and
- ‘magit-insert-unpulled-or-recent-commits’ (provided there are no
- unpulled commits) show.
-
- -- Function: magit-insert-unpulled-cherries
-
- Insert section showing unpulled commits. Like
- ‘magit-insert-unpulled-commits’ but prefix each commit that has not
- been applied yet (i.e. a commit with a patch-id not shared with
- any local commit) with "+", and all others with "-".
-
- -- Function: magit-insert-unpulled-module-commits
-
- Insert sections for all submodules with unpulled commits. These
- sections can be expanded to show the respective commits.
-
- -- Function: magit-insert-unpushed-cherries
-
- Insert section showing unpushed commits. Like
- ‘magit-insert-unpushed-commits’ but prefix each commit which has
- not been applied to upstream yet (i.e. a commit with a patch-id
- not shared with any upstream commit) with "+" and all others with
- "-".
-
- -- Function: magit-insert-unpushed-module-commits
-
- Insert sections for all submodules with unpushed commits. These
- sections can be expanded to show the respective commits.
-
- See *note References buffer: References buffer. for some more section
-inserters, which could be used here.
-
-\1f
-File: magit.info, Node: Status header sections, Next: Status options, Prev: Status sections, Up: Status buffer
-
-5.1.2 Status header sections
-----------------------------
-
-The contents of status buffers is controlled using the hook
-‘magit-status-sections-hook’, as described in the previous section. By
-default ‘magit-insert-status-headers’ is the first member of that hook
-variable.
-
- -- Function: magit-insert-status-headers
-
- Insert headers sections appropriate for ‘magit-status-mode’
- buffers. The sections are inserted by running the functions on the
- hook ‘magit-status-headers-hook’.
-
- -- User Option: magit-status-headers-hook
-
- Hook run to insert headers sections into the status buffer.
-
- This hook is run by ‘magit-insert-status-headers’, which in turn
- has to be a member of ‘magit-insert-status-sections’ to be used at
- all.
-
- By default the following functions are members of the above hook:
-
- -- Function: magit-insert-error-header
-
- Insert a header line showing the message about the Git error that
- just occurred.
-
- This function is only aware of the last error that occur when Git
- was run for side-effects. If, for example, an error occurs while
- generating a diff, then that error won’t be inserted. Refreshing
- the status buffer causes this section to disappear again.
-
- -- Function: magit-insert-diff-filter-header
-
- Insert a header line showing the effective diff filters.
-
- -- Function: magit-insert-head-branch-header
-
- Insert a header line about the current branch or detached ‘HEAD’.
-
- -- Function: magit-insert-upstream-branch-header
-
- Insert a header line about the branch that is usually pulled into
- the current branch.
-
- -- Function: magit-insert-push-branch-header
-
- Insert a header line about the branch that the current branch is
- usually pushed to.
-
- -- Function: magit-insert-tags-header
-
- Insert a header line about the current and/or next tag.
-
- The following functions can also be added to the above hook:
-
- -- Function: magit-insert-repo-header
-
- Insert a header line showing the path to the repository top-level.
-
- -- Function: magit-insert-remote-header
-
- Insert a header line about the remote of the current branch.
-
- If no remote is configured for the current branch, then fall back
- showing the "origin" remote, or if that does not exist the first
- remote in alphabetic order.
-
- -- Function: magit-insert-user-header
-
- Insert a header line about the current user.
-
-\1f
-File: magit.info, Node: Status options, Prev: Status header sections, Up: Status buffer
-
-5.1.3 Status options
---------------------
-
- -- User Option: magit-status-refresh-hook
-
- Hook run after a status buffer has been refreshed.
-
- -- User Option: magit-log-section-args
-
- Additional Git arguments used when creating log sections. Only
- ‘--graph’, ‘--decorate’, and ‘--show-signature’ are supported.
- This option is only a temporary kludge and will be removed.
-
- Note that due to an issue in Git the use of ‘--graph’ is very slow
- with long histories, so you probably don’t want to add this here.
-
- Also see the proceeding section for more options concerning status
-buffers.
-
-\1f
-File: magit.info, Node: Logging, Next: Diffing, Prev: Status buffer, Up: Inspecting
-
-5.2 Logging
-===========
-
-The status buffer contains logs for the unpushed and unpulled commits,
-but that obviously isn’t enough. The prefix command ‘magit-log-popup’,
-on ‘l’, features several suffix commands, which show a specific log in a
-separate log buffer.
-
- Like other popups, the log popup also features several arguments that
-can be changed before invoking one of the suffix commands. However in
-case of the log popup these arguments correspond to those currently in
-use in the current repository’s log buffer. When the log popup is
-invoked while no log buffer exists for the current repository yet, then
-the default value of ‘magit-log-arguments’ is used instead.
-
- For information about the various arguments, see *note
-(gitman)git-log:: . The switch ‘++order=VALUE’ is converted to one of
-‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being
-passed to ‘git log’.
-
- The log popup also features several reflog commands. See *note
-Reflog: Reflog.
-
-‘l’ (‘magit-log-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘l l’ (‘magit-log-current’)
-
- Show log for the current branch. When ‘HEAD’ is detached or with a
- prefix argument, show log for one or more revs read from the
- minibuffer.
-
-‘l o’ (‘magit-log’)
-
- Show log for one or more revs read from the minibuffer. The user
- can input any revision or revisions separated by a space, or even
- ranges, but only branches, tags, and a representation of the commit
- at point are available as completion candidates.
-
-‘l h’ (‘magit-log-head’)
-
- Show log for ‘HEAD’.
-
-‘l L’ (‘magit-log-branches’)
-
- Show log for all local branches and ‘HEAD’.
-
-‘l b’ (‘magit-log-all-branches’)
-
- Show log for all local and remote branches and ‘HEAD’.
-
-‘l a’ (‘magit-log-all’)
-
- Show log for all references and ‘HEAD’.
-
- The following related commands are not available from the popup.
-
-‘Y’ (‘magit-cherry’)
-
- Show commits in a branch that are not merged in the upstream
- branch.
-
-‘M-x magit-log-buffer-file’ (‘magit-log-buffer-file’)
-
- Show log for the file visited in the current buffer.
-
-* Menu:
-
-* Refreshing logs::
-* Log Buffer::
-* Select from log::
-* Reflog::
-
-\1f
-File: magit.info, Node: Refreshing logs, Next: Log Buffer, Up: Logging
-
-5.2.1 Refreshing logs
----------------------
-
-The prefix command ‘magit-log-refresh-popup’, on ‘L’, can be used to
-change the log arguments used in the current buffer, without changing
-which log is shown. This works in dedicated log buffers, but also in
-the status buffer.
-
-‘L’ (‘magit-log-refresh-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘L g’ (‘magit-log-refresh’)
-
- This suffix command sets the local log arguments for the current
- buffer.
-
-‘L s’ (‘magit-log-set-default-arguments’)
-
- This suffix command sets the default log arguments for buffers of
- the same type as that of the current buffer. Other existing
- buffers of the same type are not affected because their local
- values have already been initialized.
-
-‘L w’ (‘magit-log-save-default-arguments’)
-
- This suffix command sets the default log arguments for buffers of
- the same type as that of the current buffer, and saves the value
- for future sessions. Other existing buffers of the same type are
- not affected because their local values have already been
- initialized.
-
-‘L t’ (‘magit-toggle-margin’)
-
- Show or hide the margin.
-
-\1f
-File: magit.info, Node: Log Buffer, Next: Select from log, Prev: Refreshing logs, Up: Logging
-
-5.2.2 Log Buffer
-----------------
-
-‘L’ (‘magit-log-refresh-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer. See *note
- Refreshing logs: Refreshing logs.
-
-‘q’ (‘magit-log-bury-buffer’)
-
- Bury the current buffer or the revision buffer in the same frame.
- Like ‘magit-mode-bury-buffer’ (which see) but with a negative
- prefix argument instead bury the revision buffer, provided it is
- displayed in the current frame.
-
-‘C-c C-b’ (‘magit-go-backward’)
-
- Move backward in current buffer’s history.
-
-‘C-c C-f’ (‘magit-go-forward’)
-
- Move forward in current buffer’s history.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer up. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer down. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘=’ (‘magit-log-toggle-commit-limit’)
-
- Toggle the number of commits the current log buffer is limited to.
- If the number of commits is currently limited, then remove that
- limit. Otherwise set it to 256.
-
-‘+’ (‘magit-log-double-commit-limit’)
-
- Double the number of commits the current log buffer is limited to.
-
-‘=’ (‘magit-log-half-commit-limit’)
-
- Half the number of commits the current log buffer is limited to.
-
- -- User Option: magit-log-auto-more
-
- Insert more log entries automatically when moving past the last
- entry. Only considered when moving past the last entry with
- ‘magit-goto-*-section’ commands.
-
- -- User Option: magit-log-show-margin
-
- Whether to initially show the margin in log buffers.
-
- When non-nil the author name and date are initially displayed in
- the margin of log buffers. The margin can be shown or hidden in
- the current buffer using the command ‘magit-toggle-margin’.
-
- When a log buffer contains a verbose log, then the margin is never
- displayed. In status buffers this option is ignored, but it is
- possible to show the margin using the mentioned command.
-
- -- User Option: magit-log-show-refname-after-summary
-
- Whether to show the refnames after the commit summaries. This is
- useful if you use really long branch names.
-
-\1f
-File: magit.info, Node: Select from log, Next: Reflog, Prev: Log Buffer, Up: Logging
-
-5.2.3 Select from log
----------------------
-
-When the user has to select a recent commit that is reachable from
-‘HEAD’, using regular completion would be inconvenient (because most
-humans cannot remember hashes or "HEAD~5", at least not without double
-checking). Instead a log buffer is used to select the commit, which has
-the advantage that commits are presented in order and with the commit
-message. The following additional key bindings are available when a log
-is used for selection:
-
-‘C-c C-c’ (‘magit-log-select-pick’)
-
- Select the commit at point and act on it. Call
- ‘magit-log-select-pick-function’ with the selected commit as
- argument.
-
-‘C-c C-k’ (‘magit-log-select-quit’)
-
- Abort selecting a commit, don’t act on any commit.
-
- This feature is used by rebase and squash commands.
-
-\1f
-File: magit.info, Node: Reflog, Prev: Select from log, Up: Logging
-
-5.2.4 Reflog
-------------
-
-Also see *note (gitman)git-reflog:: .
-
- These reflog commands are available from the log popup. See *note
-Logging: Logging.
-
-‘l r’ (‘magit-reflog-current’)
-
- Display the reflog of the current branch.
-
-‘l O’ (‘magit-reflog-other’)
-
- Display the reflog of a branch.
-
-‘l H’ (‘magit-reflog-head’)
-
- Display the ‘HEAD’ reflog.
-
-\1f
-File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting
-
-5.3 Diffing
-===========
-
-The status buffer contains diffs for the staged and unstaged commits,
-but that obviously isn’t enough. The prefix command ‘magit-diff-popup’,
-on ‘d’, features several suffix commands, which show a specific diff in
-a separate diff buffer.
-
- Like other popups, the diff popup also features several arguments
-that can be changed before invoking one of the suffix commands. However
-in case of the diff popup these arguments correspond to those currently
-in use in the current repository’s diff buffer. When the diff popup is
-invoked while no diff buffer exists for the current repository yet, then
-the default value of ‘magit-diff-arguments’ is used instead.
-
- Also see *note (gitman)git-diff:: .
-
-‘d’ (‘magit-diff-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘d d’ (‘magit-diff-dwim’)
-
- Show changes for the thing at point.
-
-‘d r’ (‘magit-diff’)
-
- Show differences between two commits.
-
- RANGE should be a range (A..B or A…B) but can also be a single
- commit. If one side of the range is omitted, then it defaults to
- HEAD. If just a commit is given, then changes in the working tree
- relative to that commit are shown.
-
- If the region is active, use the revisions on the first and last
- line of the region. With a prefix argument, instead of diffing the
- revisions, choose a revision to view changes along, starting at the
- common ancestor of both revisions (i.e., use a "…" range).
-
-‘d w’ (‘magit-diff-worktree’)
-
- Show changes between the current working tree and the ‘HEAD’
- commit. With a prefix argument show changes between the working
- tree and a commit read from the minibuffer.
-
-‘d s’ (‘magit-diff-staged’)
-
- Show changes between the index and the ‘HEAD’ commit. With a
- prefix argument show changes between the index and a commit read
- from the minibuffer.
-
-‘d u’ (‘magit-diff-unstaged’)
-
- Show changes between the working tree and the index.
-
-‘d p’ (‘magit-diff-paths’)
-
- Show changes between any two files on disk.
-
- All of the above suffix commands update the repository’s diff buffer.
-The diff popup also features two commands which show differences in
-another buffer:
-
-‘d c’ (‘magit-show-commit’)
-
- Show the commit at point. If there is no commit at point or with a
- prefix argument, prompt for a commit.
-
-‘d t’ (‘magit-stash-show’)
-
- Show all diffs of a stash in a buffer.
-
-* Menu:
-
-* Refreshing diffs::
-* Diff buffer::
-* Diff options::
-* Revision buffer::
-
-\1f
-File: magit.info, Node: Refreshing diffs, Next: Diff buffer, Up: Diffing
-
-5.3.1 Refreshing diffs
-----------------------
-
-The prefix command ‘magit-diff-refresh-popup’, on ‘D’, can be used to
-change the diff arguments used in the current buffer, without changing
-which diff is shown. This works in dedicated diff buffers, but also in
-the status buffer.
-
-‘D’ (‘magit-diff-refresh-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘D g’ (‘magit-diff-refresh’)
-
- This suffix command sets the local diff arguments for the current
- buffer.
-
-‘D s’ (‘magit-diff-set-default-arguments’)
-
- This suffix command sets the default diff arguments for buffers of
- the same type as that of the current buffer. Other existing
- buffers of the same type are not affected because their local
- values have already been initialized.
-
-‘D w’ (‘magit-diff-save-default-arguments’)
-
- This suffix command sets the default diff arguments for buffers of
- the same type as that of the current buffer, and saves the value
- for future sessions. Other existing buffers of the same type are
- not affected because their local values have already been
- initialized.
-
-‘D t’ (‘magit-diff-toggle-refine-hunk’)
-
- This command toggles hunk refinement on or off.
-
-‘D r’ (‘magit-diff-switch-range-type’)
-
- This command converts the diff range type from "revA..revB" to
- "revB…revA", or vice versa.
-
-‘D f’ (‘magit-diff-flip-revs’)
-
- This command swaps revisions in the diff range from "revA..revB" to
- "revB..revA", or vice versa.
-
- In addition to the above popup, which allows changing any of the
-supported arguments, there also exist some commands which change a
-particular argument.
-
-‘-’ (‘magit-diff-less-context’)
-
- This command decreases the context for diff hunks by COUNT lines.
-
-‘+’ (‘magit-diff-more-context’)
-
- This command increases the context for diff hunks by COUNT lines.
-
-‘0’ (‘magit-diff-default-context’)
-
- This command resets the context for diff hunks to the default
- height.
-
- The following commands quickly change what diff is being displayed
-without having to using one of the diff popups.
-
-‘C-c C-d’ (‘magit-diff-while-committing’)
-
- While committing, this command shows the changes that are about to
- be committed. While amending, invoking the command again toggles
- between showing just the new changes or all the changes that will
- be committed.
-
- This binding is available in the diff buffer as well as the commit
- message buffer.
-
-‘C-c C-b’ (‘magit-go-backward’)
-
- This command moves backward in current buffer’s history.
-
-‘C-c C-f’ (‘magit-go-forward’)
-
- This command moves forward in current buffer’s history.
-
-\1f
-File: magit.info, Node: Diff buffer, Next: Diff options, Prev: Refreshing diffs, Up: Diffing
-
-5.3.2 Diff buffer
------------------
-
-‘RET’ (‘magit-diff-visit-file’)
-
- From a diff, visit the corresponding file at the appropriate
- position.
-
- When the file is already being displayed in another window of the
- same frame, then just select that window and adjust point. With a
- prefix argument also display in another window.
-
- If the diff shows changes in the worktree, the index, or ‘HEAD’,
- then visit the actual file. Otherwise when the diff is about an
- older commit, then visit the respective blob using
- ‘magit-find-file’. Also see ‘magit-diff-visit-file-worktree’,
- which, as the name suggests, always visits the actual file.
-
-‘C-<return>’ (‘magit-diff-visit-file-worktree’)
-
- From a diff, visit the corresponding file at the appropriate
- position.
-
- When the file is already being displayed in another window of the
- same frame, then just select that window and adjust point. With a
- prefix argument also display in another window.
-
- The actual file in the worktree is visited. The positions in the
- hunk headers get less useful the "older" the changes are, and as a
- result, jumping to the appropriate position gets less reliable.
-
- Also see ‘magit-diff-visit-file-worktree’, which visits the
- respective blob, unless the diff shows changes in the worktree, the
- index, or ‘HEAD’.
-
-‘j’ (‘magit-jump-to-diffstat-or-diff’)
-
- Jump to the diffstat or diff. When point is on a file inside the
- diffstat section, then jump to the respective diff section.
- Otherwise, jump to the diffstat section or a child thereof.
-
-‘SPC’ (‘scroll-up’)
-
- Scroll text upward.
-
-‘DEL’ (‘scroll-down’)
-
- Scroll text downward.
-
-\1f
-File: magit.info, Node: Diff options, Next: Revision buffer, Prev: Diff buffer, Up: Diffing
-
-5.3.3 Diff options
-------------------
-
- -- User Option: magit-diff-refine-hunk
-
- Whether to show word-granularity differences within diff hunks.
-
- • ‘nil’ never show fine differences.
-
- • ‘t’ show fine differences for the current diff hunk only.
-
- • ‘all’ show fine differences for all displayed diff hunks.
-
- -- User Option: magit-diff-paint-whitespace
-
- Specify where to highlight whitespace errors.
-
- See ‘magit-highlight-trailing-whitespace’,
- ‘magit-highlight-indentation’. The symbol ‘t’ means in all diffs,
- ‘status’ means only in the status buffer, and nil means nowhere.
-
- -- User Option: magit-diff-highlight-trailing
-
- Whether to highlight whitespace at the end of a line in diffs.
- Used only when ‘magit-diff-paint-whitespace’ is non-nil.
-
- -- User Option: magit-diff-highlight-indentation
-
- Highlight the "wrong" indentation style. Used only when
- ‘magit-diff-paint-whitespace’ is non-nil.
-
- The value is a list of cons cells. The car is a regular
- expression, and the cdr is the value that applies to repositories
- whose directory matches the regular expression. If more than one
- element matches, then the *last* element in the list applies. The
- default value should therefore come first in the list.
-
- If the value is ‘tabs’, highlight indentation with tabs. If the
- value is an integer, highlight indentation with at least that many
- spaces. Otherwise, highlight neither.
-
-\1f
-File: magit.info, Node: Revision buffer, Prev: Diff options, Up: Diffing
-
-5.3.4 Revision buffer
----------------------
-
- -- User Option: magit-revision-insert-related-refs
-
- Whether to show related refs in revision buffers.
-
- -- User Option: magit-revision-show-gravatar
-
- Whether to show gravatar images in revision buffers.
-
- If non-nil, then the value has to be a cons-cell which specifies
- where the gravatar images for the author and/or the committer are
- inserted inside the text that was previously inserted according to
- ‘magit-revision-header-format’.
-
- Both cells are regular expressions. The car specifies where to
- insert the author gravatar image. The top halve of the image is
- inserted right after the matched text, the bottom halve on the next
- line at the same offset. The cdr specifies where to insert the
- committer image, accordingly. Either the car or the cdr may be
- nil.
-
-\1f
-File: magit.info, Node: Ediffing, Next: References buffer, Prev: Diffing, Up: Inspecting
-
-5.4 Ediffing
-============
-
-‘e’ (‘magit-ediff-dwim’)
-
- Compare, stage, or resolve using Ediff.
-
- This command tries to guess what file, and what commit or range the
- user wants to compare, stage, or resolve using Ediff. It might
- only be able to guess either the file, or range/commit, in which
- case the user is asked about the other. It might not always guess
- right, in which case the appropriate ‘magit-ediff-*’ command has to
- be used explicitly. If it cannot read the user’s mind at all, then
- it asks the user for a command to run.
-
-‘E’ (‘magit-ediff-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer.
-
-‘E r’ (‘magit-ediff-compare’)
-
- Compare two revisions of a file using Ediff.
-
- If the region is active, use the revisions on the first and last
- line of the region. With a prefix argument, instead of diffing the
- revisions, choose a revision to view changes along, starting at the
- common ancestor of both revisions (i.e., use a "…" range).
-
-‘E m’ (‘magit-ediff-resolve’)
-
- Resolve outstanding conflicts in a file using Ediff, defaulting to
- the file at point.
-
- Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you
- can view the file’s merge-base revision using ‘/’ in the Ediff
- control buffer.
-
- In the rare event that you want to manually resolve all conflicts,
- including those already resolved by Git, use
- ‘ediff-merge-revisions-with-ancestor’.
-
-‘E s’ (‘magit-ediff-stage’)
-
- Stage and unstage changes to a file using Ediff, defaulting to the
- file at point.
-
-‘E u’ (‘magit-ediff-show-unstaged’)
-
- Show unstaged changes to a file using Ediff.
-
-‘E i’ (‘magit-ediff-show-staged’)
-
- Show staged changes to a file using Ediff.
-
-‘E w’ (‘magit-ediff-show-working-tree’)
-
- Show changes in a file between HEAD and working tree using Ediff.
-
-‘E c’ (‘magit-ediff-show-commit’)
-
- Show changes to a file introduced by a commit using Ediff.
-
- -- User Option: magit-ediff-dwim-show-on-hunks
-
- This option controls what command ‘magit-ediff-dwim’ calls when
- point is on uncommitted hunks. When nil, always run
- ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and
- ‘magit-ediff-show-unstaged’ to show staged and unstaged changes,
- respectively.
-
- -- User Option: magit-ediff-quit-hook
-
- This hook is run after quitting an Ediff session that was created
- using a Magit command. The hook functions are run inside the Ediff
- control buffer, and should not change the current buffer.
-
- This is similar to ‘ediff-quit-hook’ but takes the needs of Magit
- into account. The regular ‘ediff-quit-hook’ is ignored by Ediff
- sessions that were created using a Magit command.
-
-\1f
-File: magit.info, Node: References buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting
-
-5.5 References buffer
-=====================
-
-‘y’ (‘magit-show-refs-popup’)
-
- List and compare references in a dedicated buffer. By default all
- refs are compared with ‘HEAD’, but with a prefix argument this
- command instead acts as a prefix command and shows the following
- suffix commands along with the appropriate infix arguments in a
- popup buffer.
-
-‘y y’ (‘magit-show-refs-head’)
-
- List and compare references in a dedicated buffer. Refs are
- compared with ‘HEAD’.
-
-‘y c’ (‘magit-show-refs-current’)
-
- List and compare references in a dedicated buffer. Refs are
- compared with the current branch or ‘HEAD’ if it is detached.
-
-‘y o’ (‘magit-show-refs’)
-
- List and compare references in a dedicated buffer. Refs are
- compared with a branch read from the user.
-
- -- User Option: magit-refs-show-commit-count
-
- Whether to show commit counts in Magit-Refs mode buffers.
-
- • ‘all’ Show counts for branches and tags.
-
- • ‘branch’ Show counts for branches only.
-
- • ‘nil’ Never show counts.
- The default is ‘nil’ because anything else can be very expensive.
-
- -- User Option: magit-refs-show-margin
-
- Whether to initially show the margin in refs buffers.
-
- When non-nil the committer name and date are initially displayed in
- the margin of refs buffers. The margin can be shown or hidden in
- the current buffer using the command ‘magit-toggle-margin’.
-
- The following variables control how individual refs are displayed.
-If you change one of these variables (especially the "%c" part), then
-you should also change the others to keep things aligned. The following
-%-sequences are supported:
-
- • ‘%a’ Number of commits this ref has over the one we compare to.
-
- • ‘%b’ Number of commits the ref we compare to has over this one.
-
- • ‘%c’ Number of commits this ref has over the one we compare to.
- For the ref which all other refs are compared this is instead "@",
- if it is the current branch, or "#" otherwise.
-
- • ‘%C’ For the ref which all other refs are compared this is "@", if
- it is the current branch, or "#" otherwise. For all other refs "
- ".
-
- • ‘%h’ Hash of this ref’s tip.
-
- • ‘%m’ Commit summary of the tip of this ref.
-
- • ‘%n’ Name of this ref.
-
- • ‘%u’ Upstream of this local branch and additional local vs.
- upstream information.
-
- • ‘%U’ Upstream of this local branch.
-
- -- Variable: magit-refs-local-branch-format
-
- Format used for local branches in refs buffers.
-
- -- Variable: magit-refs-remote-branch-format
-
- Format used for remote branches in refs buffers.
-
- -- Variable: magit-refs-tags-format
-
- Format used for tags in refs buffers.
-
- -- Variable: magit-refs-indent-cherry-lines
-
- Indentation of cherries in refs buffers. This should be N-1 where
- N is taken from "%Nc" in the above format strings.
-
- Everywhere in Magit ‘RET’ visits the thing represented by the section
-at point. In almost all cases visiting is done by showing some
-information in another buffer and *not* doing anything else. In refs
-buffers ‘RET’ behaves differently, and because many users have grown
-accustomed to that inconsistency we are keeping it that way.
-
-‘RET’ (‘magit-visit-ref’)
-
- Everywhere except in refs buffers this command behaves exactly like
- ‘magit-show-commit’; it shows the commit at point in another
- buffer.
-
- In refs buffers, when there is a local branch at point, then this
- command instead checks out that branch. When there is a remote
- branch or a tag at point then the respective commit is checked out
- causing ‘HEAD’ to be detached.
-
- When a prefix argument it used, then this command only *focuses* on
- the reference at point, i.e. the commit counts and cherries are
- updated to be relative to that reference, but nothing is checked
- out.
-
- -- User Option: magit-visit-ref-create
-
- When this is non-nil and ‘magit-visit-ref’ is called inside a refs
- buffer, then it "visits" the remote branch at point by creating a
- new local branch which tracks that remote branch and then checking
- out the newly created branch.
-
- This is not enabled by default because one has to use an extremely
- loose definition of the verb "to visit" to be able to argue that
- creating and then checking out a new local branch is a form of
- visiting a remote branch.
-
-* Menu:
-
-* References sections::
-
-\1f
-File: magit.info, Node: References sections, Up: References buffer
-
-5.5.1 References sections
--------------------------
-
-The contents of references buffers is controlled using the hook
-‘magit-refs-sections-hook’. See *note Section hooks: Section hooks. to
-learn about such hooks and how to customize them. All of the below
-functions are members of the default value. Note that it makes much
-less sense to customize this hook than it does for the respective hook
-used for the status buffer.
-
- -- User Option: magit-refs-sections-hook
-
- Hook run to insert sections into a references buffer.
-
- -- Function: magit-insert-local-branches
-
- Insert sections showing all local branches.
-
- -- Function: magit-insert-remote-branches
-
- Insert sections showing all remote-tracking branches.
-
- -- Function: magit-insert-tags
-
- Insert sections showing all tags.
-
-\1f
-File: magit.info, Node: Bisecting, Next: Visiting blobs, Prev: References buffer, Up: Inspecting
-
-5.6 Bisecting
-=============
-
-Also see *note (gitman)git-bisect:: .
-
-‘B’ (‘magit-bisect-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer.
-
- When bisecting is not in progress, then the popup buffer features the
-following commands.
-
-‘B s’ (‘magit-bisect-start’)
-
- Start a bisect session.
-
- Bisecting a bug means to find the commit that introduced it. This
- command starts such a bisect session by asking for a known good and
- a bad commit.
-
-‘B u’ (‘magit-bisect-run’)
-
- Bisect automatically by running commands after each step.
-
- When bisecting is in progress, then the popup buffer features these
-commands instead.
-
-‘B b’ (‘magit-bisect-bad’)
-
- Mark the current commit as bad. Use this after you have asserted
- that the commit does contain the bug in question.
-
-‘B g’ (‘magit-bisect-good’)
-
- Mark the current commit as good. Use this after you have asserted
- that the commit does not contain the bug in question.
-
-‘B k’ (‘magit-bisect-skip’)
-
- Skip the current commit. Use this if for some reason the current
- commit is not a good one to test. This command lets Git choose a
- different one.
-
-‘B r’ (‘magit-bisect-reset’)
-
- After bisecting, cleanup bisection state and return to original
- ‘HEAD’.
-
-\1f
-File: magit.info, Node: Visiting blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting
-
-5.7 Visiting blobs
-==================
-
-‘M-x magit-find-file’ (‘magit-find-file’)
-
- View FILE from REV. Switch to a buffer visiting blob REV:FILE,
- creating one if none already exists.
-
-‘M-x magit-find-file-other-window’ (‘magit-find-file-other-window’)
-
- View FILE from REV, in another window. Like ‘magit-find-file’, but
- create a new window or reuse an existing one.
-
-\1f
-File: magit.info, Node: Blaming, Prev: Visiting blobs, Up: Inspecting
-
-5.8 Blaming
-===========
-
-Also see *note (gitman)git-blame:: .
-
-‘M-x magit-blame’ (‘magit-blame’)
-
- Display edit history of FILE up to REVISION.
-
- Interactively blame the file being visited in the current buffer.
- If the buffer visits a revision of that file, then blame up to that
- revision. Otherwise, blame the file’s full history, including
- uncommitted changes.
-
- If Magit-Blame mode is already turned on then blame recursively, by
- visiting REVISION:FILE (using ‘magit-find-file’), where revision is
- the revision before the revision that added the lines at point.
-
- ARGS is a list of additional arguments to pass to ‘git blame’; only
- arguments available from ‘magit-blame-popup’ should be used.
-
-‘M-x magit-blame-popup’ (‘magit-blame-popup’)
-
- This prefix command shows the above suffix command along with the
- appropriate infix arguments in a popup buffer.
-
-‘RET’ (‘magit-show-commit’)
-
- Show the commit at point. If there is no commit at point or with a
- prefix argument, prompt for a commit.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer up. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer down. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘n’ (‘magit-blame-next-chunk’)
-
- Move to the next chunk.
-
-‘N’ (‘magit-blame-next-chunk-same-commit’)
-
- Move to the next chunk from the same commit.
-
-‘p’ (‘magit-blame-previous-chunk’)
-
- Move to the previous chunk.
-
-‘P’ (‘magit-blame-previous-chunk-same-commit’)
-
- Move to the previous chunk from the same commit.
-
-‘q’ (‘magit-blame-quit’)
-
- Turn off Magit-Blame mode. If the buffer was created during a
- recursive blame, then also kill the buffer.
-
-‘M-w’ (‘magit-blame-copy-hash’)
-
- Save the hash of the current chunk’s commit to the kill ring.
-
-‘t’ (‘magit-blame-toggle-headings’)
-
- Show or hide blame chunk headings.
-
- -- User Option: magit-blame-heading-format
-
- Format string used for blame headings.
-
- -- User Option: magit-blame-time-format
-
- Format string used for time strings in blame headings.
-
- -- User Option: magit-blame-show-headings
-
- Whether to initially show blame block headings. The headings can
- also be toggled locally using command
- ‘magit-blame-toggle-headings’.
-
- -- User Option: magit-blame-goto-chunk-hook
-
- Hook run by ‘magit-blame-next-chunk’ and
- ‘magit-blame-previous-chunk’.
-
-\1f
-File: magit.info, Node: Manipulating, Next: Transferring, Prev: Inspecting, Up: Top
-
-6 Manipulating
-**************
-
-* Menu:
-
-* Repository setup::
-* Staging and unstaging::
-* Applying::
-* Committing::
-* Branching::
-* Merging::
-* Rebasing::
-* Cherry picking::
-* Resetting::
-* Stashing::
-
-\1f
-File: magit.info, Node: Repository setup, Next: Staging and unstaging, Up: Manipulating
-
-6.1 Repository setup
-====================
-
-‘M-x magit-init’ (‘magit-init’)
-
- This command initializes a repository and then shows the status
- buffer for the new repository.
-
- If the directory is below an existing repository, then the user has
- to confirm that a new one should be created inside. If the
- directory is the root of the existing repository, then the user has
- to confirm that it should be reinitialized.
-
-‘M-x magit-clone’ (‘magit-clone’)
-
- This command clones a repository and then shows the status buffer
- for the new repository.
-
- The user is queried for a remote url and a local directory.
-
- -- User Option: magit-clone-set-remote.pushDefault
-
- Whether to set the value of ‘remote.pushDefault’ after cloning.
-
- If ‘t’, then set without asking. If ‘nil’, then don’t set. If
- ‘ask’, then ask the user every time she clones a repository.
-
-\1f
-File: magit.info, Node: Staging and unstaging, Next: Applying, Prev: Repository setup, Up: Manipulating
-
-6.2 Staging and unstaging
-=========================
-
-Like Git, Magit can of course stage and unstage complete files. Unlike
-Git, it also allows users to gracefully un-/stage individual hunks and
-even just part of a hunk. To stage individual hunks and parts of hunks
-using Git directly, one has to use the very modal and rather clumsy
-interface of a ‘git add --interactive’ session.
-
- With Magit, on the other hand, one can un-/stage individual hunks by
-just moving point into the respective section inside a diff displayed in
-the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To
-operate on just parts of a hunk, mark the changes that should be
-un-/staged using the region and then press the same key that would be
-used to un-/stage. To stage multiple files or hunks at once use a
-region that starts inside the heading of such a section and ends inside
-the heading of a sibling section of the same type.
-
- Besides staging and unstaging, Magit also provides several other
-"apply variants" that can also operate on a file, multiple files at
-once, a hunk, multiple hunks at once, and on parts of a hunk. These
-apply variants are described in the next section.
-
- You can also use Ediff to stage and unstage. See *note Ediffing:
-Ediffing.
-
-‘s’ (‘magit-stage’)
-
- Add the change at point to the staging area.
-
-‘S’ (‘magit-stage-modified’)
-
- Stage all changes to files modified in the worktree. Stage all new
- content of tracked files and remove tracked files that no longer
- exist in the working tree from the index also. With a prefix
- argument also stage previously untracked (but not ignored) files.
-
-‘u’ (‘magit-unstage’)
-
- Remove the change at point from the staging area.
-
- Only staged changes can be unstaged. But by default this command
- performs an action that is somewhat similar to unstaging, when it
- is called on a committed change: it reverses the change in the
- index but not in the working tree.
-
-‘U’ (‘magit-unstage-all’)
-
- Remove all changes from the staging area.
-
- -- User Option: magit-unstage-committed
-
- This option controls whether ‘magit-unstage’ "unstages" committed
- changes by reversing them in the index but not the working tree.
- The alternative is to raise an error.
-
-‘M-x magit-reverse-in-index’ (‘magit-reverse-in-index’)
-
- This command reverses the committed change at point in the index
- but not the working tree. By default no key is bound directly to
- this command, but it is indirectly called when ‘u’
- (‘magit-unstage’) is pressed on a committed change.
-
- This allows extracting a change from ‘HEAD’, while leaving it in
- the working tree, so that it can later be committed using a
- separate commit. A typical workflow would be:
-
- • Optionally make sure that there are no uncommitted changes.
-
- • Visit the ‘HEAD’ commit and navigate to the change that should
- not have been included in that commit.
-
- • Type ‘u’ (‘magit-unstage’) to reverse it in the index. This
- assumes that ‘magit-unstage-committed-changes’ is non-nil.
-
- • Type ‘c e’ to extend ‘HEAD’ with the staged changes, including
- those that were already staged before.
-
- • Optionally stage the remaining changes using ‘s’ or ‘S’ and
- then type ‘c c’ to create a new commit.
-
-‘M-x magit-reset-index’ (‘magit-reset-index’)
-
- Reset the index to some commit. The commit is read from the user
- and defaults to the commit at point. If there is no commit at
- point, then it defaults to ‘HEAD’.
-
-* Menu:
-
-* Staging from file-visiting buffers::
-
-\1f
-File: magit.info, Node: Staging from file-visiting buffers, Up: Staging and unstaging
-
-6.2.1 Staging from file-visiting buffers
-----------------------------------------
-
-Fine-grained un-/staging has to be done from the status or a diff
-buffer, but it’s also possible to un-/stage all changes made to the file
-visited in the current buffer right from inside that buffer.
-
-‘M-x magit-stage-file’ (‘magit-stage-file’)
-
- When invoked inside a file-visiting buffer, then stage all changes
- to that file. In a Magit buffer, stage the file at point if any.
- Otherwise prompt for a file to be staged. With a prefix argument
- always prompt the user for a file, even in a file-visiting buffer
- or when there is a file section at point.
-
-‘M-x magit-unstage-file’ (‘magit-unstage-file’)
-
- When invoked inside a file-visiting buffer, then unstage all
- changes to that file. In a Magit buffer, unstage the file at point
- if any. Otherwise prompt for a file to be unstaged. With a prefix
- argument always prompt the user for a file, even in a file-visiting
- buffer or when there is a file section at point.
-
-\1f
-File: magit.info, Node: Applying, Next: Committing, Prev: Staging and unstaging, Up: Manipulating
-
-6.3 Applying
-============
-
-Magit provides several "apply variants": stage, unstage, discard,
-reverse, and "regular apply". At least when operating on a hunk they
-are all implemented using ‘git apply’, which is why they are called
-"apply variants".
-
- • Stage. Apply a change from the working tree to the index. The
- change also remains in the working tree.
-
- • Unstage. Remove a change from the index. The change remains in
- the working tree.
-
- • Discard. On a staged change, remove it from the working tree and
- the index. On an unstaged change, remove it from the working tree
- only.
-
- • Reverse. Reverse a change in the working tree. Both committed and
- staged changes can be reversed. Unstaged changes cannot be
- reversed. Discard them instead.
-
- • Apply. Apply a change to the working tree. Both committed and
- staged changes can be applied. Unstaged changes cannot be applied
- - as they already have been applied.
-
- The previous section described the staging and unstaging commands.
-What follows are the commands which implement the remaining apply
-variants.
-
-‘a’ (‘magit-apply’)
-
- Apply the change at point to the working tree.
-
-‘k’ (‘magit-discard’)
-
- Remove the change at point from the working tree.
-
-‘v’ (‘magit-reverse’)
-
- Reverse the change at point in the working tree.
-
- With a prefix argument all apply variants attempt a 3-way merge when
-appropriate (i.e. when ‘git apply’ is used internally).
-
-\1f
-File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating
-
-6.4 Committing
-==============
-
-When the user initiates a commit, Magit calls ‘git commit’ without any
-arguments, so Git has to get it from the user. It creates the file
-‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit
-arranges for that editor to be the Emacsclient. Once the user finishes
-the editing session, the Emacsclient exits and Git creates the commit
-using the file’s content as message.
-
-* Menu:
-
-* Initiating a commit::
-* Editing commit messages::
-
-\1f
-File: magit.info, Node: Initiating a commit, Next: Editing commit messages, Up: Committing
-
-6.4.1 Initiating a commit
--------------------------
-
-Also see *note (gitman)git-commit:: .
-
-‘c’ (‘magit-commit-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘c c’ (‘magit-commit’)
-
- Create a new commit on ‘HEAD’. With a prefix argument amend to the
- commit at ‘HEAD’ instead.
-
-‘c a’ (‘magit-commit-amend’)
-
- Amend the last commit.
-
-‘c e’ (‘magit-commit-extend’)
-
- Amend the last commit, without editing the 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.
-
- Non-interactively respect the optional OVERRIDE-DATE argument and
- ignore the option.
-
-‘c w’ (‘magit-commit-reword’)
-
- Reword the last commit, ignoring staged changes. 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.
-
-‘c f’ (‘magit-commit-fixup’)
-
- Create a fixup commit.
-
- 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’.
-
-‘c F’ (‘magit-commit-instant-fixup’)
-
- Create a fixup commit and instantly rebase.
-
-‘c s’ (‘magit-commit-squash’)
-
- Create a squash commit, without editing the squash 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’.
-
-‘c S’ (‘magit-commit-instant-squash’)
-
- Create a squash commit and instantly rebase.
-
-‘c A’ (‘magit-commit-augment’)
-
- Create a squash commit, editing the squash 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’.
-
- -- User Option: magit-commit-ask-to-stage
-
- Whether to ask to stage everything when committing and nothing is
- staged.
-
- -- User Option: magit-commit-extend-override-date
-
- Whether using ‘magit-commit-extend’ changes the committer date.
-
- -- User Option: magit-commit-reword-override-date
-
- Whether using ‘magit-commit-reword’ changes the committer date.
-
- -- User Option: magit-commit-squash-confirm
-
- Whether the commit targeted by squash and fixup has to be
- confirmed. When non-nil then the commit at point (if any) is used
- as default choice. Otherwise it has to be confirmed. This option
- only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The
- "instant" variants always require confirmation because making an
- error while using those is harder to recover from.
-
-\1f
-File: magit.info, Node: Editing commit messages, Prev: Initiating a commit, Up: Committing
-
-6.4.2 Editing commit messages
------------------------------
-
-After initiating a commit as described in the previous section, two new
-buffers appear. One shows the changes that are about to committed,
-while the other is used to write the message. All regular editing
-commands are available in the commit message buffer. This section only
-describes the additional commands.
-
- Commit messages are edited in an edit session - in the background Git
-is waiting for the editor, in our case the Emacsclient, to save the
-commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then
-return. If the Emacsclient returns with a non-zero exit status then Git
-does not create the commit. So the most important commands are those
-for finishing and aborting the commit.
-
-‘C-c C-c’ (‘with-editor-finish’)
-
- Finish the current editing session by returning with exit code 0.
- Git then creates the commit using the message it finds in the file.
-
-‘C-c C-k’ (‘with-editor-cancel’)
-
- Cancel the current editing session by returning with exit code 1.
- Git then cancels the commit, but leaves the file untouched.
-
- In addition to being used by Git, these messages may also be stored
-in a ring that persists until Emacs is closed. By default the message
-is stored at the beginning and the end of an edit session (regardless of
-whether the session is finished successfully or was canceled). It is
-sometimes useful to bring back messages from that ring.
-
-‘C-s M-s’ (‘git-commit-save-message’)
-
- Save the current buffer content to the commit message ring.
-
-‘M-p’ (‘git-commit-prev-message’)
-
- Cycle backward through the commit message ring, after saving the
- current message to the ring. With a numeric prefix ARG, go back
- ARG comments.
-
-‘M-n’ (‘git-commit-next-message’)
-
- Cycle forward through the commit message ring, after saving the
- current message to the ring. With a numeric prefix ARG, go back
- ARG comments.
-
- By default the diff for the changes that are about to be committed
-are automatically shown when invoking the commit. When amending to an
-existing commit it may be useful to show either the changes that are
-about to be added to that commit or to show those changes together with
-those that are already committed.
-
-‘C-c C-d’ (‘magit-diff-while-committing’)
-
- While committing, show the changes that are about to be committed.
- While amending, invoking the command again toggles between showing
- just the new changes or all the changes that will be committed.
-
-‘C-c C-w’ (‘magit-pop-revision-stack’)
-
- This command inserts a representation of a revision into the
- current buffer. It can be used inside buffers used to write commit
- messages but also in other buffers such as buffers used to edit
- emails or ChangeLog files.
-
- By default this command pops the revision which was last added to
- the ‘magit-revision-stack’ and inserts it into the current buffer
- according to ‘magit-pop-revision-stack-format’. Revisions can be
- put on the stack using ‘magit-copy-section-value’ and
- ‘magit-copy-buffer-revision’.
-
- If the stack is empty or with a prefix argument it instead reads a
- revision in the minibuffer. By using the minibuffer history this
- allows selecting an item which was popped earlier or to insert an
- arbitrary reference or revision without first pushing it onto the
- stack.
-
- When reading the revision from the minibuffer, then it might not be
- possible to guess the correct repository. When this command is
- called inside a repository (e.g. while composing a commit
- message), then that repository is used. Otherwise (e.g. while
- composing an email) then the repository recorded for the top
- element of the stack is used (even though we insert another
- revision). If not called inside a repository and with an empty
- stack, or with two prefix arguments, then read the repository in
- the minibuffer too.
-
- -- User Option: magit-pop-revision-stack-format
-
- This option controls how the command ‘magit-pop-revision-stack’
- inserts a revision into the current buffer.
-
- The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this
- option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all
- of which may be nil or a string (though either one of EOB-FORMAT or
- POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil,
- then the two formats should be too).
-
- First INDEX-REGEXP is used to find the previously inserted entry,
- by searching backward from point. The first submatch must match
- the index number. That number is incremented by one, and becomes
- the index number of the entry to be inserted. If you don’t want to
- number the inserted revisions, then use nil for INDEX-REGEXP.
-
- If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
- should contain \"%N\", which is replaced with the number that was
- determined in the previous step.
-
- Both formats, if non-nil and after removing %N, are then expanded
- using ‘git show –format=FORMAT …’ inside TOPLEVEL.
-
- The expansion of POINT-FORMAT is inserted at point, and the
- expansion of EOB-FORMAT is inserted at the end of the buffer (if
- the buffer ends with a comment, then it is inserted right before
- that).
-
- Some projects use pseudo headers in commit messages. Magit colorizes
-such headers and provides some commands to insert such headers.
-
- -- User Option: git-commit-known-pseudo-headers
-
- A list of Git pseudo headers to be highlighted.
-
-‘C-c C-a’ (‘git-commit-ack’)
-
- Insert a header acknowledging that you have looked at the commit.
-
-‘C-c C-r’ (‘git-commit-review’)
-
- Insert a header acknowledging that you have reviewed the commit.
-
-‘C-c C-s’ (‘git-commit-signoff’)
-
- Insert a header to sign off the commit.
-
-‘C-c C-t’ (‘git-commit-test’)
-
- Insert a header acknowledging that you have tested the commit.
-
-‘C-c C-o’ (‘git-commit-cc’)
-
- Insert a header mentioning someone who might be interested.
-
-‘C-c C-p’ (‘git-commit-reported’)
-
- Insert a header mentioning the person who reported the issue being
- fixed by the commit.
-
-‘C-c C-i’ (‘git-commit-suggested’)
-
- Insert a header mentioning the person who suggested the change.
-
- ‘git-commit-mode’ is a minor mode that is only used to establish the
-above key bindings. This allows using an arbitrary major mode when
-editing the commit message. It’s even possible to use a different major
-mode in different repositories, which is useful when different projects
-impose different commit message conventions.
-
- -- User Option: git-commit-major-mode
-
- The value of this option is the major mode used to edit Git commit
- messages.
-
- Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook
-to setup the buffer, except for the key bindings. All other setup
-happens in the function ‘git-commit-setup’, which among other things
-runs the hook ‘git-commit-setup-hook’. The following functions are
-suitable for that hook.
-
- -- User Option: git-commit-setup-hook
-
- Hook run at the end of ‘git-commit-setup’.
-
- -- Function: magit-revert-buffers &optional force
-
- Revert unmodified file-visiting buffers of the current repository.
-
- If either ‘magit-revert-buffers’ is non-nil and
- ‘inhibit-magit-revert’ is nil, or if optional FORCE is non-nil,
- then revert all unmodified buffers that visit files being tracked
- in the current repository.
-
- -- Function: git-commit-save-message
-
- Save the current buffer content to the commit message ring.
-
- -- Function: git-commit-setup-changelog-support
-
- After this function is called, ChangeLog entries are treated as
- paragraphs.
-
- -- Function: git-commit-turn-on-auto-fill
-
- Turn on ‘auto-fill-mode’ and set ‘fill-column’ to the value of
- ‘git-commit-fill-column’.
-
- -- Function: git-commit-turn-on-flyspell
-
- Turn on Flyspell mode. Also prevent comments from being checked
- and finally check current non-comment text.
-
- -- Function: git-commit-propertize-diff
-
- Propertize the diff shown inside the commit message buffer. Git
- inserts such diffs into the commit message template when the
- ‘--verbose’ argument is used. Magit’s commit popup by default does
- not offer that argument because the diff that is shown in a
- separate buffer is more useful. But some users disagree, which is
- why this function exists.
-
- -- Function: with-editor-usage-message
-
- Show usage information in the echo area.
-
- Magit also helps with writing *good* commit messages by complaining
-when certain rules are violated.
-
- -- User Option: git-commit-summary-max-length
-
- The intended maximal length of the summary line of commit messages.
- Characters beyond this column are colorized to indicate that this
- preference has been violated.
-
- -- User Option: git-commit-fill-column
-
- Column beyond which automatic line-wrapping should happen in commit
- message buffers.
-
- -- User Option: git-commit-finish-query-functions
-
- List of functions called to query before performing commit.
-
- The commit message buffer is current while the functions are
- called. If any of them returns nil, then the commit is not
- performed and the buffer is not killed. The user should then fix
- the issue and try again.
-
- The functions are called with one argument. If it is non-nil then
- that indicates that the user used a prefix argument to force
- finishing the session despite issues. Functions should usually
- honor this wish and return non-nil.
-
- -- Function: git-commit-check-style-conventions
-
- Check for violations of certain basic style conventions. For each
- violation ask the user if she wants to proceed anyway. This makes
- sure the summary line isn’t too long and that the second line is
- empty.
-
- To show no diff while committing remove ‘magit-commit-diff’ from
-‘server-switch-hook’.
-
-\1f
-File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating
-
-6.5 Branching
-=============
-
-The upstream branch of some local branch is the branch into which the
-commits on that local branch should eventually be merged, usually
-something like ‘origin/master’. For the ‘master’ branch itself the
-upstream branch and the branch it is being pushed to, are usually the
-same remote branch. But for a feature branch the upstream branch and
-the branch it is being pushed to should differ.
-
- Feature branches too should _eventually_ end up in a remote branch
-such as ‘origin/master’ or ‘origin/maint’. Such a branch should
-therefore be used as the upstream. But feature branches shouldn’t be
-pushed directly to such branches. Instead a feature branch ‘my-feature’
-is usually pushed to ‘my-fork/my-feature’ or ‘origin/my-feature’. After
-the new feature has been reviewed, the maintainer merges the feature
-into ‘master’. And finally ‘master’ (not ‘my-feature’ itself) is pushed
-to ‘origin/master’.
-
- But new features seldom are perfect on the first try, and so feature
-branches usually have to be improved and re-pushed many times. Pushing
-should therefore be easy to do, and for that reason some users have
-concluded that the remote branch to which a feature branch is being
-pushed should be set as the upstream. Luckily Git has long ago gained
-support for a push-remote which can be configured separately from the
-upstream branch, using the variables ‘branch.<name>.pushRemote’ and
-‘remote.pushDefault’, so we no longer have to choose which of the two
-remotes should be used as "the remote".
-
- Each of the fetching, pulling, and pushing popups features three
-commands which act on the current branch and some other branch. Of
-these, ‘p’ is bound to a command which acts on the push-remote, ‘u’ is
-bound to a command which acts on the upstream, and ‘e’ is bound to a
-command which acts on any other branch. The status buffer shows
-unpushed and unpulled for both the push-remote and the upstream.
-
- It’s fairly simple to configure these two remotes. The values of all
-the variables that are related to fetching, pulling, and pushing (as
-well as some other branch-related variables) can be inspected and
-changed in the branching popup. It is also possible to set the
-push-remote and/or upstream while pushing (see *note Pushing: Pushing.).
-
-‘b’ (‘magit-branch-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer. It also displays the values of the following variables and
- allows changing their values.
-
- The following variables are used to configure a specific branch. The
-values are being displayed for the current branch (if any). To change
-the value for another branch use a prefix argument.
-
- -- Variable: branch.NAME.merge
-
- Together with ‘branch.NAME.remote’ this variable defines the
- upstream branch of the local branch named NAME. The value of this
- variable is the full reference of the upstream _branch_.
-
- -- Variable: branch.NAME.remote
-
- Together with ‘branch.NAME.merge’ this variable defines the
- upstream branch of the local branch named NAME. The value of this
- variable is the name of the upstream _remote_.
-
- -- Variable: branch.NAME.rebase
-
- This variable controls whether pulling into the branch named NAME
- is done by rebasing or by merging the fetched branch.
-
- • When ‘true’ then pulling is done by rebasing.
-
- • When ‘false’ then pulling is done by merging.
-
- • When undefined then the value of ‘pull.rebase’ is used. The
- default of that variable is ‘false’.
-
- -- Variable: branch.NAME.pushRemote
-
- This variable specifies the remote that the branch named NAME is
- usually pushed to. The value has to be the name of an existing
- remote.
-
- It is not possible to specify the name of _branch_ to push the
- local branch to. The name of the remote branch is always the same
- as the name of the local branch.
-
- If this variable is undefined but ‘remote.pushDefault’ is defined,
- then the value of the latter is used. By default
- ‘remote.pushDefault’ is undefined.
-
- -- Variable: branch.NAME.description
-
- This variable can be used to describe the branch named NAME. That
- description is used e.g. when turning the branch into a series of
- patches.
-
- The following variables specify defaults which are used if the above
-branch-specific variables are not set.
-
- -- Variable: pull.rebase
-
- This variable specifies whether pulling is done by rebasing or by
- merging. It can be overwritten using ‘branch.NAME.rebase’.
-
- • When ‘true’ then pulling is done by rebasing.
-
- • When ‘false’ (the default) then pulling is done by merging.
- Since it is never a good idea to merge the upstream branch into a
- feature or hotfix branch and most branches are such branches, you
- should consider setting this to ‘true’, and ‘branch.master.rebase’
- to ‘false’.
-
- -- Variable: remote.pushDefault
-
- This variable specifies what remote the local branches are usually
- pushed to. This can be overwritten per branch using
- ‘branch.NAME.pushRemote’.
-
- The following variables are used during the creation of a branch and
-control whether the various branch-specific variables are automatically
-set at this time.
-
- -- Variable: branch.autoSetupMerge
-
- This variable specifies under what circumstances creating a branch
- NAME should result in the variables ‘branch.NAME.merge’ and
- ‘branch.NAME.remote’ being set according to the starting point used
- to create the branch. If the starting point isn’t a branch, then
- these variables are never set.
-
- • When ‘always’ then the variables are set regardless of whether
- the starting point is a local or a remote branch.
-
- • When ‘true’ (the default) then the variables are set when the
- starting point is a remote branch, but not when it is a local
- branch.
-
- • When ‘false’ then the variables are never set.
-
- -- Variable: branch.autoSetupRebase
-
- This variable specifies whether creating a branch NAME should
- result in the variable ‘branch.NAME.rebase’ being set to ‘true’.
-
- • When ‘always’ then the variable is set regardless of whether
- the starting point is a local or a remote branch.
-
- • When ‘local’ then the variable are set when the starting point
- is a local branch, but not when it is a remote branch.
-
- • When ‘remote’ then the variable are set when the starting
- point is a remote branch, but not when it is a local branch.
-
- • When ‘never’ (the default) then the variable is never set.
-
- Note that the respective commands always change the repository-local
-values. If you want to change the global value, which is used when the
-local value is undefined, then you have to do so on the command line,
-e.g.:
-
- git config --global remote.autoSetupMerge always
-
- For more information about these variables you should also see
-
- *note (gitman)git-config:: . Also see *note (gitman)git-branch:: ,
-
- *note (gitman)git-checkout:: , and *note Pushing: Pushing.
-
- -- User Option: magit-prefer-remote-upstream
-
- This option controls whether commands that read a branch from the
- user and then set it as the upstream branch, offer a local or a
- remote branch as default completion candidate, when they have the
- choice.
-
- This affects all commands that use ‘magit-read-upstream-branch’ or
- ‘magit-read-starting-point’, which includes all commands that
- change the upstream and many which create new branches.
-
-‘b b’ (‘magit-checkout’)
-
- Checkout a revision read in the minibuffer and defaulting to the
- branch or arbitrary revision at point. If the revision is a local
- branch then that becomes the current branch. If it is something
- else then ‘HEAD’ becomes detached. Checkout fails if the working
- tree or the staging area contain changes.
-
-‘b n’ (‘magit-branch’)
-
- Create a new branch. The user is asked for a branch or arbitrary
- revision to use as the starting point of the new branch. When a
- branch name is provided, then that becomes the upstream branch of
- the new branch. The name of the new branch is also read in the
- minibuffer.
-
- Also see option ‘magit-branch-prefer-remote-upstream’.
-
-‘b c’ (‘magit-branch-and-checkout’)
-
- This command creates a new branch like ‘magit-branch’, but then
- also checks it out.
-
- Also see option ‘magit-branch-prefer-remote-upstream’.
-
-‘b s’ (‘magit-branch-spinoff’)
-
- This command creates and checks out a new branch starting at and
- tracking the current branch. That branch in turn is reset to the
- last commit it shares with its upstream. If the current branch has
- no upstream or no unpushed commits, then the new branch is created
- anyway and the previously current branch is not touched.
-
- This is useful to create a feature branch after work has already
- began on the old branch (likely but not necessarily "master").
-
- If the current branch is a member of the value of option
- ‘magit-branch-prefer-remote-upstream’ (which see), then the current
- branch will be used as the starting point as usual, but the
- upstream of the starting-point may be used as the upstream of the
- new branch, instead of the starting-point itself.
-
-‘b x’ (‘magit-branch-reset’)
-
- This command resets a branch, defaulting to the branch at point, to
- the tip of another branch or any other commit.
-
- When the branch being reset is the current branch, then a hard
- reset is performed. If there are any uncommitted changes, then the
- user has to confirming the reset because those changes would be
- lost.
-
- This is useful when you have started work on a feature branch but
- realize it’s all crap and want to start over.
-
- When resetting to another branch and a prefix argument is used,
- then the target branch is set as the upstream of the branch that is
- being reset.
-
-‘b d’ (‘magit-branch-delete’)
-
- Delete one or multiple branches. If the region marks multiple
- branches, then offer to delete those. Otherwise, prompt for a
- single branch to be deleted, defaulting to the branch at point.
-
-‘b r’ (‘magit-branch-rename’)
-
- Rename a branch. The branch and the new name are read in the
- minibuffer. With prefix argument the branch is renamed even if
- that name conflicts with an existing branch.
-
- -- User Option: magit-branch-read-upstream-first
-
- When creating a branch, whether to read the upstream branch before
- the name of the branch that is to be created. The default is
- ‘nil’, and I recommend you leave it at that.
-
- -- User Option: magit-branch-prefer-remote-upstream
-
- This option specifies whether remote upstreams are favored over
- local upstreams when creating new branches.
-
- When a new branch is created, Magit offers the branch, commit, or
- stash as the default starting point of the new branch. If there is
- no such thing at point, then it falls back to offer the current
- branch as starting-point. The user may then accept that default or
- pick something else.
-
- If the chosen starting-point is a branch, then it may also be set
- as the upstream of the new branch, depending on the value of the
- Git variable ‘branch.autoSetupMerge’. By default this is done for
- remote branches, but not for local branches.
-
- You might prefer to always use some remote branch as upstream. If
- the chosen starting-point is (1) a local branch, (2) whose name is
- a member of the value of this option, (3) the upstream of that
- local branch is a remote branch with the same name, and (4) that
- remote branch can be fast-forwarded to the local branch, then the
- chosen branch is used as starting-point, but its own upstream is
- used as the upstream of the new branch.
-
- Assuming the chosen branch matches these conditions you would end
- up with with e.g.:
-
- feature --upstream--> origin/master
-
- instead of
-
- feature --upstream--> master --upstream--> origin/master
-
- Which you prefer is a matter of personal preference. If you do
- prefer the former, then you should add branches such as ‘master’,
- ‘next’, and ‘maint’ to the value of this options.
-
-\1f
-File: magit.info, Node: Merging, Next: Rebasing, Prev: Branching, Up: Manipulating
-
-6.6 Merging
-===========
-
-Also see *note (gitman)git-merge:: .
-
-‘m’ (‘magit-merge-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no merge is in progress, then the popup buffer features the
-following commands.
-
-‘m m’ (‘magit-merge’)
-
- Merge another branch or an arbitrary revision into the current
- branch. The branch or revision to be merged is read in the
- minibuffer and defaults to the one at point.
-
- Unless there are conflicts or a prefix argument is used, the
- resulting merge commit uses a generic commit message, and the user
- does not get a chance to inspect or change it before the commit is
- created. With a prefix argument this does not actually create the
- merge commit, which makes it possible to inspect how conflicts were
- resolved and to adjust the commit message.
-
-‘m e’ (‘magit-merge-editmsg’)
-
- Merge another branch or an arbitrary revision into the current
- branch and open a commit message buffer, so that the user can make
- adjustments. The commit is not actually created until the user
- finishes with ‘C-c C-c’.
-
-‘m n’ (‘magit-merge-nocommit’)
-
- Merge another branch or an arbitrary revision into the current
- branch, but do not actually create the commit. The user can then
- further adjust the merge, even when automatic conflict resolution
- succeeded and/or adjust the commit message.
-
-‘m p’ (‘magit-merge-preview’)
-
- Preview result of merging another branch or an arbitrary revision
- into the current branch.
-
- When a merge is in progress, then the popup buffer features these
-commands instead.
-
-‘m m’ (‘magit-merge’)
-
- After resolving conflicts, proceed with the merge. If there are
- still conflicts, then this fails.
-
-‘m a’ (‘magit-merge-abort’)
-
- Abort the current merge operation.
-
-\1f
-File: magit.info, Node: Rebasing, Next: Cherry picking, Prev: Merging, Up: Manipulating
-
-6.7 Rebasing
-============
-
-Also see *note (gitman)git-rebase:: .
-
-‘r’ (‘magit-rebase-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no rebase is in progress, then the popup buffer features the
-following commands.
-
-‘r p’ (‘magit-rebase-onto-pushremote’)
-
- Rebase the current branch onto ‘branch.<name>.pushRemote’. If that
- variable is unset, then rebase onto ‘remote.pushDefault’.
-
-‘r u’ (‘magit-rebase-onto-upstream’)
-
- Rebase the current branch onto its upstream branch.
-
-‘r e’ (‘magit-rebase’)
-
- Rebase the current branch onto a branch read in the minibuffer.
- All commits that are reachable from head but not from the selected
- branch TARGET are being rebased."
-
-‘r o’ (‘magit-rebase-subset’)
-
- Start a non-interactive rebase sequence with commits from START to
- ‘HEAD’ onto NEWBASE. START has to be selected from a list of recent
- commits.
-
- Note that the popup also features the infix argument ‘--interactive’.
-This can be used to turn one of the above non-interactive rebase
-variants into an interactive rebase.
-
- For example if you want to clean up a feature branch and at the same
-time rebase it onto ‘master’, then you could use ‘r-iu’. But we
-recommend that you instead do that in two steps. First use ‘ri’ to
-cleanup the feature branch, and then in a second step ‘ru’ to rebase it
-onto ‘master’. That way if things turn out to be more complicated than
-you thought and/or you make a mistake and have to start over, then you
-only have to redo half the work.
-
- Explicitly enabling ‘--interactive’ won’t have an effect on the
-following commands as they always use that argument anyway, even if it
-is not enabled in the popup.
-
-‘r i’ (‘magit-rebase-interactive’)
-
- Start an interactive rebase sequence.
-
-‘r f’ (‘magit-rebase-autosquash’)
-
- Combine squash and fixup commits with their intended targets.
-
-‘r m’ (‘magit-rebase-edit-commit’)
-
- Edit a single older commit using rebase.
-
-‘r w’ (‘magit-rebase-reword-commit’)
-
- Reword a single older commit using rebase.
-
- When a rebase is in progress, then the popup buffer features these
-commands instead.
-
-‘r r’ (‘magit-rebase-continue’)
-
- Restart the current rebasing operation.
-
-‘r s’ (‘magit-rebase-skip’)
-
- Skip the current commit and restart the current rebase operation.
-
-‘r e’ (‘magit-rebase-edit’)
-
- Edit the todo list of the current rebase operation.
-
-‘r a’ (‘magit-rebase-abort’)
-
- Abort the current rebase operation, restoring the original branch.
-
-* Menu:
-
-* Editing rebase sequences::
-* Rebase sequence log::
-
-\1f
-File: magit.info, Node: Editing rebase sequences, Next: Rebase sequence log, Up: Rebasing
-
-6.7.1 Editing rebase sequences
-------------------------------
-
-‘C-c C-c’ (‘with-editor-finish’)
-
- Finish the current editing session by returning with exit code 0.
- Git then creates the commit using the message it finds in the file.
-
-‘C-c C-k’ (‘with-editor-cancel’)
-
- Cancel the current editing session by returning with exit code 1.
- Git then cancels the commit, but leaves the file untouched.
-
-‘RET’ (‘git-rebase-show-commit’)
-
- Show the commit on the current line in another buffer and select
- that buffer.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- Show the commit on the current line in another buffer without
- selecting that buffer. If the revision buffer is already visible
- in another window of the current frame, then instead scroll that
- window up.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- Show the commit on the current line in another buffer without
- selecting that buffer. If the revision buffer is already visible
- in another window of the current frame, then instead scroll that
- window down.
-
-‘p’ (‘git-rebase-backward-line’)
-
- Move to previous line.
-
-‘n’ (‘forward-line’)
-
- Move to next line.
-
-‘M-p’ (‘git-rebase-move-line-up’)
-
- Move the current commit (or command) up.
-
-‘M-n’ (‘git-rebase-move-line-down’)
-
- Move the current commit (or command) down.
-
-‘r’ (‘git-rebase-reword’)
-
- Edit message of commit on current line.
-
-‘e’ (‘git-rebase-edit’)
-
- Stop at the commit on the current line.
-
-‘s’ (‘git-rebase-squash’)
-
- Meld commit on current line into previous commit, and edit message.
-
-‘f’ (‘git-rebase-fixup’)
-
- Meld commit on current line into previous commit, discarding the
- current commit’s message.
-
-‘k’ (‘git-rebase-kill-line’)
-
- Kill the current action line.
-
-‘c’ (‘git-rebase-pick’)
-
- Use commit on current line.
-
-‘x’ (‘git-rebase-exec’)
-
- Insert a shell command to be run after the proceeding commit.
-
- If there already is such a command on the current line, then edit
- that instead. With a prefix argument insert a new command even
- when there already is one on the current line. With empty input
- remove the command on the current line, if any.
-
-‘y’ (‘git-rebase-insert’)
-
- Read an arbitrary commit and insert it below current line.
-
-‘C-x u’ (‘git-rebase-undo’)
-
- Undo some previous changes. Like ‘undo’ but works in read-only
- buffers.
-
- -- User Option: git-rebase-auto-advance
-
- Whether to move to next line after changing a line.
-
- -- User Option: git-rebase-show-instructions
-
- Whether to show usage instructions inside the rebase buffer.
-
- -- User Option: git-rebase-confirm-cancel
-
- Whether confirmation is required to cancel.
-
-\1f
-File: magit.info, Node: Rebase sequence log, Prev: Editing rebase sequences, Up: Rebasing
-
-6.7.2 Rebase sequence log
--------------------------
-
-While a rebase sequence is in progress, the status buffer features a
-section which lists the commits that have already been applied as well
-as the commits that still have to be applied.
-
- The commits are split in two halves. When rebase stops at a commit,
-either because the user has to deal with a conflict or explicitly
-requested that rebase stops at that commit, then point is placed on the
-commit that separates the two groups, i.e. on ‘HEAD’. The commits
-above it have not been applied yet, while it and the commits below it
-have already been applied. In between these two groups of applied and
-yet-to-be applied commits, there sometimes is a commit which has been
-dropped.
-
- Each commit is prefixed with a word and these words are additionally
-shown in different colors to indicate the status of the commits.
-
- The following colors are used:
-
- • Yellow commits have not been applied yet.
-
- • Gray commits have already been applied.
-
- • The blue commit is the ‘HEAD’ commit.
-
- • The green commit is the commit the rebase sequence stopped at. If
- this is the same commit as ‘HEAD’ (e.g. because you haven’t done
- anything yet after rebase stopped at the commit, then this commit
- is shown in blue, not green. There can only be a green and a blue
- commit at the same time, if you create one or more new commits
- after rebase stops at a commit.
-
- • Red commits have been dropped. They are shown for reference only,
- e.g. to make it easier to diff.
-
- Of course these colors are subject to the color-theme in use.
-
- The following words are used:
-
- • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and
- ‘fixup’ have not been applied yet. These words have the same
- meaning here as they do in the buffer used to edit the rebase
- sequence. See *note Editing rebase sequences: Editing rebase
- sequences.
-
- • The commit prefixed with ‘onto’ is the commit on top of which all
- the other commits are being re-applied. Like the commits that have
- already been re-applied, it is reachable from ‘HEAD’, but unlike
- those it has not actually been re-applied during the current
- session - it wasn’t touched at all.
-
- • Commits prefixed with ‘done’ have already been re-applied. Not all
- commits that have already been applied are prefixed with this word,
- though.
-
- • When a commit is prefixed with ‘void’, then that indicates that
- Magit knows for sure that all the changes in that commit have been
- applied using several new commits. This commit is no longer
- reachable from ‘HEAD’, and it also isn’t one of the commits that
- will be applied when resuming the session.
-
- • When a commit is prefixed with ‘join’, then that indicates that the
- rebase sequence stopped at that commit due to a conflict - you now
- have to join (merge) the changes with what has already been
- applied. In a sense this is the commit rebase stopped at, but
- while its effect is already in the index and in the worktree (with
- conflict markers), the commit itself has not actually been applied
- yet (it isn’t the ‘HEAD’). So it is shown in yellow, like the
- other commits that still have to be applied.
-
- • When a commit is prefixed with ‘goal’, ‘same’, or ‘work’, then that
- indicates that you reset to an earlier commit (and that this commit
- therefore is no longer reachable from ‘HEAD’), but that it might
- still be possible to create a new commit with the exact same tree
- or at least the same patch-id, without manually editing any file.
- Or at the very least that there are some uncommitted remaining,
- which may or may not originate from that commit.
-
- • When a commit is prefixed with ‘goal’, then that indicates
- that it is still possible to create a commit with the exact
- same tree (the "goal") without manually editing a file, by
- simply committing the index (or, provided nothing is already
- staged, by staging all unstaged changes and then committing
- that). This is the case when the original tree exists in the
- index or worktree in untainted form.
-
- • When a commit is prefixed with ‘same’, then that indicates
- that it is no longer possible to create a commit with the
- exact same tree, but that it is still possible to create a
- commit with the same patch-id. This would be the case if you
- created a new commit with other changes, but the changes from
- the original commit still exist in the index and/or working
- tree in untainted form.
-
- • When a commit is prefixed with ‘work’, then that indicates
- that you are working with the changes from that commit after
- resetting to an earlier commit. There are changes in the
- index and/or working tree and some of them likely originate
- from that commit.
-
- • When a commit is prefixed with ‘poof’ or ‘gone’, then that
- indicates that you reset to an earlier commit (and that this commit
- therefore is no longer reachable from ‘HEAD’), and that there are
- no uncommitted changes remaining which might allow you to create a
- new commit with the same tree or at least the same patch-id.
-
- • When a commit is prefixed with ‘poof’, then that indicates
- that it is no longer reachable from ‘HEAD’, but that it has
- been replaced with one or more commits, which together have
- the exact same effect.
-
- • When a commit is prefixed with ‘gone’, then that indicates
- that it is no longer reachable from ‘HEAD’ and that we also
- cannot determine whether its changes are still in effect in
- one or more new commits. They might be, but if so, then there
- must also be other changes which makes it impossible to know
- for sure.
-
- Do not worry if you do not fully understand the above. That’s okay,
-you will acquire a good enough understanding through practice.
-
- For other sequence operations such as cherry-picking, a similar
-section is displayed, but they lack some of the features described
-above, due to limitations in the git commands used to implement them.
-Most importantly these sequences only support "picking" a commit but not
-other actions such as "rewording", and they do not keep track of the
-commits which have already been applied.
-
-\1f
-File: magit.info, Node: Cherry picking, Next: Resetting, Prev: Rebasing, Up: Manipulating
-
-6.8 Cherry picking
-==================
-
-Also see *note (gitman)git-cherry-pick:: .
-
-‘A’ (‘magit-cherry-pick-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no cherry-pick or revert is in progress, then the popup buffer
-features the following commands.
-
-‘A A’ (‘magit-cherry-pick’)
-
- Cherry-pick a commit. Prompt for a commit, defaulting to the
- commit at point. If the region selects multiple commits, then pick
- all of them, without prompting.
-
-‘A a’ (‘magit-cherry-apply’)
-
- Apply the changes in a commit to the working tree, but do not
- commit them. Prompt for a commit, defaulting to the commit at
- point. If the region selects multiple commits, then apply all of
- them, without prompting.
-
- This command also has a top-level binding, which can be invoked
- without using the popup by typing ‘a’ at the top-level.
-
- When a cherry-pick or revert is in progress, then the popup buffer
-features these commands instead.
-
-‘A A’ (‘magit-sequence-continue’)
-
- Resume the current cherry-pick or revert sequence.
-
-‘A s’ (‘magit-sequence-skip’)
-
- Skip the stopped at commit during a cherry-pick or revert sequence.
-
-‘A a’ (‘magit-sequence-abort’)
-
- Abort the current cherry-pick or revert sequence. This discards
- all changes made since the sequence started.
-
-* Menu:
-
-* Reverting::
-
-\1f
-File: magit.info, Node: Reverting, Up: Cherry picking
-
-6.8.1 Reverting
----------------
-
-‘V’ (‘magit-revert-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no cherry-pick or revert is in progress, then the popup buffer
-features the following commands.
-
-‘V V’ (‘magit-revert’)
-
- Revert a commit by creating a new commit. Prompt for a commit,
- defaulting to the commit at point. If the region selects multiple
- commits, then revert all of them, without prompting.
-
-‘V v’ (‘magit-revert-no-commit’)
-
- Revert a commit by applying it in reverse to the working tree.
- Prompt for a commit, defaulting to the commit at point. If the
- region selects multiple commits, then revert all of them, without
- prompting.
-
- When a cherry-pick or revert is in progress, then the popup buffer
-features these commands instead.
-
-‘V A’ (‘magit-sequence-continue’)
-
- Resume the current cherry-pick or revert sequence.
-
-‘V s’ (‘magit-sequence-skip’)
-
- Skip the stopped at commit during a cherry-pick or revert sequence.
-
-‘V a’ (‘magit-sequence-abort’)
-
- Abort the current cherry-pick or revert sequence. This discards
- all changes made since the sequence started.
-
-\1f
-File: magit.info, Node: Resetting, Next: Stashing, Prev: Cherry picking, Up: Manipulating
-
-6.9 Resetting
-=============
-
-Also see *note (gitman)git-reset:: .
-
-‘x’ (‘magit-reset’)
-
- Reset the head and index to some commit read from the user and
- defaulting to the commit at point. The working tree is kept as-is.
- With a prefix argument also reset the working tree.
-
-‘M-x magit-reset-index’ (‘magit-reset-index’)
-
- Reset the index to some commit read from the user and defaulting to
- the commit at point. Keep the ‘HEAD’ and working tree as-is, so if
- the commit refers to the ‘HEAD’, then this effectively unstages all
- changes.
-
-‘M-x magit-reset-head’ (‘magit-reset-head’)
-
- Reset the ‘HEAD’ and index to some commit read from the user and
- defaulting to the commit at point. The working tree is kept as-is.
-
-‘M-x magit-reset-soft’ (‘magit-reset-soft’)
-
- Reset the ‘HEAD’ to some commit read from the user and defaulting
- to the commit at point. The index and the working tree are kept
- as-is.
-
-‘M-x magit-reset-hard’ (‘magit-reset-hard’)
-
- Reset the ‘HEAD’, index, and working tree to some commit read from
- the user and defaulting to the commit at point.
-
-‘M-x magit-checkout-file’ (‘magit-checkout-file’)
-
- Update file in the working tree and index to the contents from a
- revision.
-
- Both the revision and file are read from the user.
-
-\1f
-File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating
-
-6.10 Stashing
-=============
-
-Also see *note (gitman)git-stash:: .
-
-‘z’ (‘magit-stash-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘z z’ (‘magit-stash’)
-
- Create a stash of the index and working tree. Untracked files are
- included according to popup arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’.
-
-‘z i’ (‘magit-stash-index’)
-
- Create a stash of the index only. Unstaged and untracked changes
- are not stashed.
-
-‘z w’ (‘magit-stash-worktree’)
-
- Create a stash of the working tree only. Untracked files are
- included according to popup arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’.
-
-‘z x’ (‘magit-stash-keep-index’)
-
- Create a stash of the index and working tree, keeping index intact.
- Untracked files are included according to popup arguments. One
- prefix argument is equivalent to ‘--include-untracked’ while two
- prefix arguments are equivalent to ‘--all’.
-
-‘z Z’ (‘magit-snapshot’)
-
- Create a snapshot of the index and working tree. Untracked files
- are included according to popup arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’.
-
-‘z I’ (‘magit-snapshot-index’)
-
- Create a snapshot of the index only. Unstaged and untracked
- changes are not stashed.
-
-‘z W’ (‘magit-snapshot-worktree’)
-
- Create a snapshot of the working tree only. Untracked files are
- included according to popup arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’-.
-
-‘z a’ (‘magit-stash-apply’)
-
- Apply a stash to the working tree. Try to preserve the stash
- index. If that fails because there are staged changes, apply
- without preserving the stash index.
-
-‘z p’ (‘magit-stash-pop’)
-
- Apply a stash to the working tree and remove it from stash list.
- Try to preserve the stash index. If that fails because there are
- staged changes, apply without preserving the stash index and forgo
- removing the stash.
-
-‘z d’ (‘magit-stash-drop’)
-
- Remove a stash from the stash list. When the region is active,
- offer to drop all contained stashes.
-
-‘z l’ (‘magit-stash-list’)
-
- List all stashes in a buffer.
-
-‘z v’ (‘magit-stash-show’)
-
- Show all diffs of a stash in a buffer.
-
-‘z b’ (‘magit-stash-branch’)
-
- Create and checkout a new BRANCH from STASH.
-
-‘z f’ (‘magit-stash-format-patch’)
-
- Create a patch from STASH.
-
-‘k’ (‘magit-stash-clear’)
-
- Remove all stashes saved in REF’s reflog by deleting REF.
-
-\1f
-File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top
-
-7 Transferring
-**************
-
-* Menu:
-
-* Remotes::
-* Fetching::
-* Pulling::
-* Pushing::
-* Creating and sending patches::
-* Applying patches::
-
-\1f
-File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring
-
-7.1 Remotes
-===========
-
-Also see *note (gitman)git-remote:: .
-
-‘M’ (‘magit-remote-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘M a’ (‘magit-remote-add’)
-
- Add a remote and fetch it. The remote name and url are read in the
- minibuffer.
-
-‘M r’ (‘magit-remote-rename’)
-
- Rename a remote. Both the old and the new names are read in the
- minibuffer.
-
-‘M u’ (‘magit-remote-set-url’)
-
- Change the url of a remote. Both the remote and the new url are
- read in the minibuffer.
-
-‘M k’ (‘magit-remote-remove’)
-
- Delete a remote, read from the minibuffer.
-
- -- User Option: magit-remote-add-set-remote.pushDefault
-
- Whether to set the value of ‘remote.pushDefault’ after adding a
- remote.
-
- If ‘ask’, then always ask. If ‘ask-if-unset’, then ask, but only
- if the variable isn’t set already. If ‘nil’, then don’t ever set.
- If the value is a string, then set without asking, provided the
- name of the name of the added remote is equal to that string and
- the variable isn’t already set.
-
-\1f
-File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring
-
-7.2 Fetching
-============
-
-For information about the differences between the _upstream_ and the
-_push-remote_, see *note Branching: Branching.
-
- Also see *note (gitman)git-fetch:: .
-
-‘f’ (‘magit-fetch-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘f p’ (‘magit-fetch-from-pushremote’)
-
- Fetch from the push-remote of the current branch.
-
-‘f u’ (‘magit-fetch-from-upstream’)
-
- Fetch from the upstream of the current branch.
-
-‘f e’ (‘magit-fetch’)
-
- Fetch from another repository.
-
-‘f a’ (‘magit-fetch-all’)
-
- Fetch from all remotes.
-
-‘f m’ (‘magit-submodule-fetch’)
-
- Fetch all submodules. With a prefix argument fetch all remotes of
- all submodules.
-
- Instead of using one popup for fetching and another for pulling, you
-could also use ‘magit-pull-and-fetch-popup’. See its doc-string for
-more information.
-
-\1f
-File: magit.info, Node: Pulling, Next: Pushing, Prev: Fetching, Up: Transferring
-
-7.3 Pulling
-===========
-
-For information about the differences between the _upstream_ and the
-_push-remote_, see *note Branching: Branching.
-
- Also see *note (gitman)git-pull:: .
-
-‘F’ (‘magit-pull-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer.
-
-‘F p’ (‘magit-pull-from-pushremote’)
-
- Pull from the push-remote of the current branch.
-
-‘F u’ (‘magit-pull-from-upstream’)
-
- Pull from the upstream of the current branch.
-
-‘F e’ (‘magit-pull’)
-
- Pull from a branch read in the minibuffer.
-
- Instead of using one popup for fetching and another for pulling, you
-could also use ‘magit-pull-and-fetch-popup’. See its doc-string for
-more information.
-
-\1f
-File: magit.info, Node: Pushing, Next: Creating and sending patches, Prev: Pulling, Up: Transferring
-
-7.4 Pushing
-===========
-
-For information about the differences between the _upstream_ and the
-_push-remote_, see *note Branching: Branching.
-
- Also see *note (gitman)git-push:: .
-
-‘P’ (‘magit-push-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘P p’ (‘magit-push-current-to-pushremote’)
-
- Push the current branch to ‘branch.<name>.pushRemote’ or if that is
- unset to ‘remote.pushDefault’.
-
- When ‘magit-push-current-set-remote-if-missing’ is non-nil and the
- push-remote is not configured, then read the push-remote from the
- user, set it, and then push to it. With a prefix argument the
- push-remote can be changed before pushed to it.
-
-‘P u’ (‘magit-push-current-to-upstream’)
-
- Push the current branch to its upstream branch.
-
- When ‘magit-push-current-set-remote-if-missing’ is non-nil and the
- push-remote is not configured, then read the upstram from the user,
- set it, and then push to it. With a prefix argument the
- push-remote can be changed before pushed to it.
-
-‘P e’ (‘magit-push-current’)
-
- Push the current branch to a branch read in the minibuffer.
-
-‘P o’ (‘magit-push’)
-
- Push an arbitrary branch or commit somewhere. Both the source and
- the target are read in the minibuffer.
-
-‘P m’ (‘magit-push-matching’)
-
- Push all matching branches to another repository. If multiple
- remotes exit, then read one from the user. If just one exists, use
- that without requiring confirmation.
-
-‘P t’ (‘magit-push-tags’)
-
- Push all tags to another repository. If only one remote exists,
- then push to that. Otherwise prompt for a remote, offering the
- remote configured for the current branch as default.
-
-‘P T’ (‘magit-push-tag’)
-
- Push a tag to another repository.
-
- Two more push commands exist, which by default are not available from
-the push popup. See their doc-strings for instructions on how to add
-them to the popup.
-
- -- Command: magit-push-implicitly args
-
- Push somewhere without using an explicit refspec.
-
- This command simply runs ‘git push -v [ARGS]’. ARGS are the
- arguments specified in the popup buffer. No explicit refspec
- arguments are used. Instead the behavior depends on at least these
- Git variables: ‘push.default’, ‘remote.pushDefault’,
- ‘branch.<branch>.pushRemote’, ‘branch.<branch>.remote’,
- ‘branch.<branch>.merge’, and ‘remote.<remote>.push’.
-
- -- Command: magit-push-to-remote remote args
-
- Push to the remote REMOTE without using an explicit refspec. The
- remote is read in the minibuffer.
-
- This command simply runs ‘git push -v [ARGS] REMOTE’. ARGS are the
- arguments specified in the popup buffer. No refspec arguments are
- used. Instead the behavior depends on at least these Git
- variables: ‘push.default’, ‘remote.pushDefault’,
- ‘branch.<branch>.pushRemote’, ‘branch.<branch>.remote’,
- ‘branch.<branch>.merge’, and ‘remote.<remote>.push’.
-
- -- User Option: magit-push-current-set-remote-if-missing
-
- This option controls whether missing remotes are configured before
- pushing.
-
- When ‘nil’, then the command ‘magit-push-current-to-pushremote’ and
- ‘magit-push-current-to-upstream’ do not appear in the push popup if
- the push-remote resp. upstream is not configured. If the user
- invokes one of these commands anyway, then it raises an error.
-
- When ‘non-nil’, then these commands always appear in the push
- popup. But if the required configuration is missing, then they do
- appear in a way that indicates that this is the case. If the user
- invokes one of them, then it asks for the necessary configuration,
- stores the configuration, and then uses it to push a first time.
-
- This option also affects whether the argument ‘--set-upstream’ is
- available in the popup. If the value is ‘non-nil’, then that
- argument is redundant. But note that changing the value of this
- option does not take affect immediately, the argument will only be
- added or removed after restarting Emacs.
-
-\1f
-File: magit.info, Node: Creating and sending patches, Next: Applying patches, Prev: Pushing, Up: Transferring
-
-7.5 Creating and sending patches
-================================
-
-‘W’ (‘magit-patch-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘W p’ (‘magit-format-patch’)
-
- Create patches for a set commits. If the region marks commits,
- then create patches for those. Otherwise prompt for a range or a
- single commit, defaulting to the commit at point.
-
-‘W r’ (‘magit-request-pull’)
-
- Request that upstream pulls from your public repository.
-
-\1f
-File: magit.info, Node: Applying patches, Prev: Creating and sending patches, Up: Transferring
-
-7.6 Applying patches
-====================
-
-Also see *note (gitman)git-am:: .
-
-‘w’ (‘magit-am-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘w w’ (‘magit-am-apply-patches’)
-
- Apply one or more patches. If the region marks files, then apply
- those patches. Otherwise read a file name in the minibuffer
- defaulting to the file at point.
-
-‘w m’ (‘magit-am-apply-maildir’)
-
- Apply the patches from a maildir.
-
-‘w w’ (‘magit-am-continue’)
-
- Resume the current patch applying sequence.
-
-‘w s’ (‘magit-am-skip’)
-
- Skip the stopped at patch during a patch applying sequence.
-
-‘w a’ (‘magit-am-abort’)
-
- Abort the current patch applying sequence. This discards all
- changes made since the sequence started.
-
-\1f
-File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top
-
-8 Miscellaneous
-***************
-
-* Menu:
-
-* Tagging::
-* Notes::
-* Submodules::
-* Common commands::
-* Wip modes::
-* Minor mode for buffers visiting files::
-* Minor mode for buffers visiting blobs::
-
-\1f
-File: magit.info, Node: Tagging, Next: Notes, Up: Miscellaneous
-
-8.1 Tagging
-===========
-
-Also see *note (gitman)git-tag:: .
-
-‘t’ (‘magit-tag-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘t t’ (‘magit-tag’)
-
- Create a new tag with the given NAME at REV. With a prefix argument
- annotate the tag.
-
-‘t k’ (‘magit-tag-delete’)
-
- Delete one or more tags. If the region marks multiple tags (and
- nothing else), then offer to delete those. Otherwise, prompt for a
- single tag to be deleted, defaulting to the tag at point.
-
-‘t p’ (‘magit-tag-prune’)
-
- Offer to delete tags missing locally from REMOTE, and vice versa.
-
-\1f
-File: magit.info, Node: Notes, Next: Submodules, Prev: Tagging, Up: Miscellaneous
-
-8.2 Notes
-=========
-
-Also see *note (gitman)git-notes:: .
-
-‘T’ (‘magit-notes-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘T T’ (‘magit-notes-edit’)
-
- Edit the note attached to a commit, defaulting to the commit at
- point.
-
- By default use the value of Git variable ‘core.notesRef’ or
- "refs/notes/commits" if that is undefined.
-
-‘T r’ (‘magit-notes-remove’)
-
- Remove the note attached to a commit, defaulting to the commit at
- point.
-
- By default use the value of Git variable ‘core.notesRef’ or
- "refs/notes/commits" if that is undefined.
-
-‘T p’ (‘magit-notes-prune’)
-
- Remove notes about unreachable commits.
-
-‘T s’ (‘magit-notes-set-ref’)
-
- Set the current notes ref to a the value read from the user. The
- ref is made current by setting the value of the Git variable
- ‘core.notesRef’. With a prefix argument change the global value
- instead of the value in the current repository. When this is
- undefined, then "refs/notes/commit" is used.
-
- Other ‘magit-notes-*’ commands, as well as the sub-commands of
- Git’s ‘note’ command, default to operate on that ref.
-
-‘T S’ (‘magit-notes-set-display-refs’)
-
- Set notes refs to be display in addition to "core.notesRef". This
- reads a colon separated list of notes refs from the user. The
- values are stored in the Git variable ‘notes.displayRef’. With a
- prefix argument GLOBAL change the global values instead of the
- values in the current repository.
-
- It is possible to merge one note ref into another. That may result
-in conflicts which have to resolved in the temporary worktree
-".git/NOTES_MERGE_WORKTREE".
-
-‘T m’ (‘magit-notes-merge’)
-
- Merge the notes of a ref read from the user into the current notes
- ref. The current notes ref is the value of Git variable
- ‘core.notesRef’ or "refs/notes/commits" if that is undefined.
-
- When a notes merge is in progress then the popup features the
-following suffix commands, instead of those listed above.
-
-‘T c’ (‘magit-notes-merge-commit’)
-
- Commit the current notes ref merge, after manually resolving
- conflicts.
-
-‘T a’ (‘magit-notes-merge-abort’)
-
- Abort the current notes ref merge.
-
-\1f
-File: magit.info, Node: Submodules, Next: Common commands, Prev: Notes, Up: Miscellaneous
-
-8.3 Submodules
-==============
-
-Also see *note (gitman)git-submodule:: .
-
-‘o’ (‘magit-submodule-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘o a’ (‘magit-submodule-add’)
-
- Add the repository at URL as a submodule. Optional PATH is the
- path to the submodule relative to the root of the super-project.
- If it is nil then the path is determined based on URL.
-
-‘o b’ (‘magit-submodule-setup’)
-
- Clone and register missing submodules and checkout appropriate
- commits.
-
-‘o i’ (‘magit-submodule-init’)
-
- Register submodules listed in ".gitmodules" into ".git/config".
-
-‘o u’ (‘magit-submodule-update’)
-
- Clone missing submodules and checkout appropriate commits. With a
- prefix argument also register submodules in ".git/config".
-
-‘o s’ (‘magit-submodule-sync’)
-
- Update each submodule’s remote URL according to ".gitmodules".
-
-‘o f’ (‘magit-submodule-fetch’)
-
- Fetch submodule. With a prefix argument fetch all remotes.
-
-‘o i’ (‘magit-submodule-init’)
-
- Unregister the submodule at PATH.
-
-\1f
-File: magit.info, Node: Common commands, Next: Wip modes, Prev: Submodules, Up: Miscellaneous
-
-8.4 Common commands
-===================
-
-These are some of the commands that can be used in all buffers whose
-major-modes derive from ‘magit-mode’. There are other common commands
-beside the ones below, but these didn’t fit well anywhere else.
-
-‘M-w’ (‘magit-copy-section-value’)
-
- This command saves the value of the current section to the
- ‘kill-ring’, and, provided that the current section is a commit,
- branch, or tag section, it also pushes the (referenced) revision to
- the ‘magit-revision-stack’.
-
- When the current section is a branch or a tag, and a prefix
- argument is used, then it saves the revision at its tip to the
- ‘kill-ring’ instead of the reference name.
-
-‘C-w’ (‘magit-copy-buffer-revision’)
-
- This command save the revision being displayed in the current
- buffer to the ‘kill-ring’ and also pushes it to the
- ‘magit-revision-stack’. It is mainly intended for use in
- ‘magit-revision-mode’ buffers, the only buffers where it is always
- unambiguous exactly which revision should be saved.
-
- Most other Magit buffers usually show more than one revision, in
- some way or another, so this command has to select one of them, and
- that choice might not always be the one you think would have been
- the best pick.
-
- Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to
-‘kill-ring-save’ and ‘kill-region’, and these commands would also be
-useful in Magit buffers. Therefore when the region is active, then both
-of these commands behave like ‘kill-ring-save’ instead of as described
-above.
-
-\1f
-File: magit.info, Node: Wip modes, Next: Minor mode for buffers visiting files, Prev: Common commands, Up: Miscellaneous
-
-8.5 Wip modes
-=============
-
-Git keeps *committed* changes around long enough for users to recover
-changes they have accidentally deleted. It does so by not garbage
-collecting any committed but no longer referenced objects for a certain
-period of time, by default 30 days.
-
- But Git does *not* keep track of *uncommitted* changes in the working
-tree and not even the index (the staging area). Because Magit makes it
-so convenient to modify uncommitted changes, it also makes it easy to
-shoot yourself in the foot in the process.
-
- For that reason Magit provides three global modes that save *tracked*
-files to work-in-progress references after or before certain actions.
-(Untracked files are never saved and these modes also only work after
-the first commit has been created).
-
- Two separate work-in-progress references are used to track the state
-of the index and of the working tree: "refs/wip/index/<branchref>" and
-"refs/wip/wtree/<branchref>", where ‘<branchref>’ is the full ref of the
-current branch, e.g. "refs/heads/master". When the ‘HEAD’ is detached
-then "HEAD" is in place of ‘<branchref>’.
-
- Checking out another branch (or detaching ‘HEAD’) causes the use of
-different wip refs for subsequent changes, but the old refs are not
-deleted.
-
- Creating a commit and then making a change causes the wip refs to be
-recreated to fork from the new commit. But the old commits on the wip
-refs are not lost. They are still available from the reflog. To make
-it easier to see when the fork point of a wip ref was changed, an
-additional commit with the message "restart autosaving" is created on it
-(‘xxO’ commits below are such boundary commits).
-
- Starting with
-
- BI0---BI1 refs/wip/index/refs/heads/master
- /
-A---B refs/heads/master
- \
- BW0---BW1 refs/wip/wtree/refs/heads/master
-
- and committing the staged changes and editing and saving a file would
-result in
-
- BI0---BI1 refs/wip/index/refs/heads/master
- /
-A---B---C refs/heads/master
- \ \
- \ CW0---CW1 refs/wip/wtree/refs/heads/master
- \
- BW0---BW1 refs/wip/wtree/refs/heads/master@{2}
-
- The fork-point of the index wip ref is not changed until some change
-is being staged. Likewise just checking out a branch or creating a
-commit does not change the fork-point of the working tree wip ref. The
-fork-points are not adjusted until there actually is a change that
-should be committed to the respective wip ref.
-
- To view the log for the a branch and its wip refs use the commands
-‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’
-when using these commands. Alternatively you can use the reflog to show
-all commits that ever existed on a wip ref. You can then recover lost
-changes from the commits shown in the log or reflog.
-
- -- Command: magit-wip-log
-
- This command shows the log for a branch and its wip refs.
-
- With a negative prefix argument only the worktree wip ref is shown.
- The absolute numeric value of the prefix argument controls how many
- "branches" of each wip ref are shown.
-
- -- Command: magit-wip-log-current
-
- This command shows the log for the current branch and its wip refs.
-
- With a negative prefix argument only the worktree wip ref is shown.
- The absolute numeric value of the prefix argument controls how many
- "branches" of each wip ref are shown.
-
- There exists a total of three global modes that save to the wip refs,
-which might seem excessive, but allows fine tuning of when exactly
-changes are being committed to the wip refs. Enabling all modes makes
-it less likely that a change slips through the cracks.
-
- Setting the below variable directly does not take effect; either
-customize them or call the respective mode function.
-
- -- User Option: magit-wip-after-save-mode
-
- When this mode is enabled, then saving a buffer that visits a file
- tracked in a Git repository causes its current state to be
- committed to the working tree wip ref for the current branch.
-
- -- User Option: magit-wip-after-apply-mode
-
- When this mode is enabled, then applying (i.e. staging, unstaging,
- discarding, reversing, and regularly applying) a change to a file
- tracked in a Git repository causes its current state to be
- committed to the index and/or working tree wip refs for the current
- branch.
-
- If you only ever edit files using Emacs and only ever interact with
-Git using Magit, then the above two modes should be enough to protect
-each and every change from accidental loss. In practice nobody does
-that. So an additional mode exists that does commit to the wip refs
-before making changes that could cause the loss of earlier changes.
-
- -- User Option: magit-wip-before-change-mode
-
- When this mode is enabled, then certain commands commit the
- existing changes to the files they are about to make changes to.
-
- Note that even if you enable all three modes this won’t give you
-perfect protection. The most likely scenario for losing changes despite
-the use of these modes is making a change outside Emacs and then
-destroying it also outside Emacs. In such a scenario, Magit, being an
-Emacs package, didn’t get the opportunity to keep you from shooting
-yourself in the foot.
-
- When you are unsure whether Magit did commit a change to the wip
-refs, then you can explicitly request that all changes to all tracked
-files are being committed.
-
-‘M-x magit-wip-commit’ (‘magit-wip-commit’)
-
- This command commits all changes to all tracked files to the index
- and working tree work-in-progress refs. Like the modes described
- above, it does not commit untracked files, but it does check all
- tracked files for changes. Use this command when you suspect that
- the modes might have overlooked a change made outside Emacs/Magit.
-
- -- User Option: magit-wip-after-save-local-mode-lighter
-
- Mode-line lighter for ‘magit-wip-after-save-local-mode’.
-
- -- User Option: magit-wip-after-apply-mode-lighter
-
- Mode-line lighter for ‘magit-wip-after-apply-mode’.
-
- -- User Option: magit-wip-before-change-mode-lighter
-
- Mode-line lighter for ‘magit-wip-before-change-mode’.
-
- -- User Option: magit-wip-namespace
-
- The namespace used for work-in-progress refs. It has to end with a
- slash. The wip refs are named "<namespace>index/<branchref>" and
- "<namespace>wtree/<branchref>". When snapshots are created while
- the ‘HEAD’ is detached then "HEAD" is used in place of
- ‘<branchref>’.
-
-\1f
-File: magit.info, Node: Minor mode for buffers visiting files, Next: Minor mode for buffers visiting blobs, Prev: Wip modes, Up: Miscellaneous
-
-8.6 Minor mode for buffers visiting files
-=========================================
-
-The ‘magit-file-mode’ enables certain Magit features in file-visiting
-buffers belonging to a Git repository. It should be enabled globally
-using ‘global-magit-file-mode’. Currently this mode only establishes a
-few key bindings, but this might be extended in the future.
-
- -- User Option: global-magit-file-mode
-
- Whether to establish certain Magit key bindings in all
- file-visiting buffers belonging to a Git repository. This
- establishes the bindings suggested in *note Getting started:
- Getting started. (but only for file-visiting buffers), and
- additionally binds ‘C-c M-g’ to ‘magit-file-popup’.
-
-‘C-c M-g’ (‘magit-file-popup’)
-
- This prefix command shows a popup buffer featuring suffix commands
- that operate on the file being visited in the current buffer.
-
-‘C-c M-g s’ (‘magit-stage-file’)
-
- Stage all changes to the file being visited in the current buffer.
-
-‘C-c M-g u’ (‘magit-unstage-file’)
-
- Unstage all changes to the file being visited in the current
- buffer.
-
-‘C-c M-g l’ (‘magit-log-buffer-file’)
-
- This command shows the log for the file of blob that the current
- buffer visits. Renames are followed when a prefix argument is used
- or when ‘--follow’ is part of ‘magit-log-arguments’.
-
-‘C-c M-g b’ (‘magit-blame-popup’)
-
- This prefix command shows the ‘magit-blame’ suffix command along
- with the appropriate infix arguments in a popup buffer. See *note
- Initiating a commit: Initiating a commit.
-
-‘C-c M-g p’ (‘magit-blob-previous’)
-
- Visit the previous blob which modified the current file.
-
-‘C-c M-g c’ (‘magit-commit-popup’)
-
- This prefix command shows suffix commands along with the
- appropriate infix arguments in a popup buffer. See *note
- Initiating a commit: Initiating a commit.
-
-\1f
-File: magit.info, Node: Minor mode for buffers visiting blobs, Prev: Minor mode for buffers visiting files, Up: Miscellaneous
-
-8.7 Minor mode for buffers visiting blobs
-=========================================
-
-The ‘magit-blob-mode’ enables certain Magit features in blob-visiting
-buffers. Such buffers can be created using ‘magit-find-file’ and some
-of the commands mentioned below, which also take care of turning on this
-minor mode. Currently this mode only establishes a few key bindings,
-but this might be e
-
-‘p’ (‘magit-blob-previous’)
-
- Visit the previous blob which modified the current file.
-
-‘n’ (‘magit-blob-next’)
-
- Visit the next blob which modified the current file.
-
-‘q’ (‘magit-kill-this-buffer’)
-
- Kill the current buffer.
-
-\1f
-File: magit.info, Node: Customizing, Next: Plumbing, Prev: Miscellaneous, Up: Top
-
-9 Customizing
-*************
-
-Both Git and Emacs are highly customizable. Magit is both a Git
-porcelain as well as an Emacs package, so it makes sense to customize it
-using both Git variables as well as Emacs options. However this
-flexibility doesn’t come without problems, including but not limited to
-the following.
-
- • Some Git variables automatically have an effect in Magit without
- requiring any explicit support. Sometimes that is desirable - in
- other cases, it breaks Magit.
-
- When a certain Git setting breaks Magit but you want to keep using
- that setting on the command line, then that can be accomplished by
- overriding the value for Magit only by appending something like
- ‘("-c" "some.variable=compatible-value")’ to
- ‘magit-git-global-arguments’.
-
- • Certain settings like ‘fetch.prune=true’ are respected by Magit
- commands (because they simply call the respective Git command) but
- their value is not reflected in the respective popup buffers. In
- this case the ‘--prune’ argument in ‘magit-fetch-popup’ might be
- active or inactive depending on the value of
- ‘magit-fetch-arguments’ only, but that doesn’t keep the Git
- variable from being honored by the suffix commands anyway. So
- pruning might happen despite the the ‘--prune’ arguments being
- displayed in a way that seems to indicate that no pruning will
- happen.
-
- I intend to address these and similar issues in a future release.
-
-* Menu:
-
-* Per-repository configuration::
-* Essential settings::
-
-\1f
-File: magit.info, Node: Per-repository configuration, Next: Essential settings, Up: Customizing
-
-9.1 Per-repository configuration
-================================
-
-Magit can be configured on a per-repository level using both Git
-variables as well as Emacs options.
-
- To set a Git variable for one repository only, simply set it in
-‘/path/to/repo/.git/config’ instead of ‘$HOME/.gitconfig’ or
-‘/etc/gitconfig’. See *note (gitman)git-config:: .
-
- Similarly, Emacs options can be set for one repository only by
-editing ‘/path/to/repo/.dir-locals.el’. See *note (emacs)Directory
-Variables::. For example to disable automatic refreshes of
-file-visiting buffers in just one huge repository use this:
-
- • ‘/path/to/huge/repo/.dir-locals.el’
-
- ((nil . ((magit-refresh-buffers . nil))
-
- If you want to apply the same settings to several, but not all,
-repositories then keeping the repository-local config files in sync
-would quickly become annoying. To avoid that you can create config
-files for certain classes of repositories (e.g. "huge repositories")
-and then include those files in the per-repository config files. For
-example:
-
- • ‘/path/to/huge/repo/.git/config’
-
- [include]
- path = /path/to/huge-gitconfig
-
- • ‘/path/to/huge-gitconfig’
-
- [status]
- showUntrackedFiles = no
-
- • ‘$HOME/.emacs.d/init.el’
-
- (dir-locals-set-class-variables 'huge-git-repository
- '((nil . ((magit-refresh-buffers . nil)))))
-
- (dir-locals-set-directory-class
- "/path/to/huge/repo/" 'huge-git-repository)
-
-\1f
-File: magit.info, Node: Essential settings, Prev: Per-repository configuration, Up: Customizing
-
-9.2 Essential settings
-======================
-
-The next two sections list and discuss several variables that many users
-might want to customize, for safety and/or performance reasons.
-
-* Menu:
-
-* Safety::
-* Performance::
-
-\1f
-File: magit.info, Node: Safety, Next: Performance, Up: Essential settings
-
-9.2.1 Safety
-------------
-
-This section discusses various variables that you might want to change
-(or *not* change) for safety reasons.
-
- Git keeps *committed* changes around long enough for users to recover
-changes they have accidentally been deleted. It does not do the same
-for *uncommitted* changes in the working tree and not even the index
-(the staging area). Because Magit makes it so easy to modify
-uncommitted changes, it also makes it easy to shoot yourself in the foot
-in the process. For that reason Magit provides three global modes that
-save *tracked* files to work-in-progress references after or before
-certain actions. See *note Wip modes: Wip modes.
-
- These modes are not enabled by default because of performance
-concerns. Instead a lot of potentially destructive commands require
-confirmation every time they are used. In many cases this can be
-disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion
-and confirmation: Completion and confirmation.). If you enable the
-various wip modes then you should add ‘safe-with-wip’ to this list.
-
- Similarly it isn’t necessary to require confirmation before moving a
-file to the system trash - if you trashed a file by mistake then you can
-recover it from the there. Option ‘magit-delete-by-moving-to-trash’
-controls whether the system trash is used, which is the case by default.
-Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might
-want to change that.
-
- By default buffers visiting files are automatically reverted when the
-visited file changes on disk. This isn’t as risky as it might seem, but
-to make an informed decision you should see *note Risk of Reverting
-Automatically: Risk of Reverting Automatically.
-
-\1f
-File: magit.info, Node: Performance, Prev: Safety, Up: Essential settings
-
-9.2.2 Performance
------------------
-
-After Magit has run ‘git’ for side-effects, it also refreshes the
-current Magit buffer and the respective status buffer. This is
-necessary because otherwise outdated information might be displayed
-without the user noticing. Magit buffers are updated by recreating
-their content from scratch, which makes updating simpler and less
-error-prone, but also more costly. Keeping it simple and just
-re-creating everything from scratch is an old design decision and
-departing from that will require major refactoring.
-
- I plan to do that in time for the next major release. I also intend
-to create logs and diffs asynchronously, which should also help a lot
-but also requires major refactoring.
-
- Meanwhile you can tell Magit to only automatically refresh the
-current Magit buffer, but not the status buffer. If you do that, then
-the status buffer is only refreshed automatically if it itself is the
-current buffer.
-
- (setq magit-refresh-status-buffer nil)
-
- You should also check whether any third-party packages have added
-anything to ‘magit-refresh-buffer-hook’, ‘magit-status-refresh-hook’,
-‘magit-pre-refresh-hook’, and ‘magit-post-refresh-hook’. If so, then
-check whether those additions impacts performance significantly.
-Setting ‘magit-refresh-verbose’ and then inspecting the output in the
-‘*Messages*’ buffer, should help doing so.
-
- Magit also reverts buffers which visit files located inside the
-current repository, when the visited file changes on disk. That is
-implemented on top of ‘auto-revert-mode’ from the built-in library
-‘autorevert’. To figure out whether that impacts performance, check
-whether performance is significantly worse, when many buffers exist
-and/or when some buffers visit files using Tramp. If so, then this
-should help.
-
- (setq auto-revert-buffer-list-filter
- 'magit-auto-revert-repository-buffers-p)
-
- For alternative approaches see *note Automatic Reverting of
-File-Visiting Buffers: Automatic Reverting of File-Visiting Buffers.
-
- If you have enabled any features that are disabled by default, then
-you should check whether they impact performance significantly. It’s
-likely that they were not enabled by default because it is known that
-they reduce performance at least in large repositories.
-
- If performance is only slow inside certain unusually large
-repositories, then you might want to disable certain features on a
-per-repository or per-repository-class basis only. See *note
-Per-repository configuration: Per-repository configuration.
-
-Microsoft Windows Performance
-.............................
-
-In order to update the status buffer, ‘git’ has to be run a few dozen
-times. That is only problematic on Microsoft Windows, because that
-operating system is exceptionally slow at starting processes. Sadly
-this is an issue that can only be fixed by Microsoft itself, and they
-don’t appear to particularly interested in doing so.
-
- Beside the subprocess issue, there also exist other Window-specific
-performance issues, some of which can be worked around. The maintainers
-of "Git for Windows" try to reduce their effect, and in order to benefit
-from the latest performance tweaks, should always use the latest
-release. Magit too tries to work around some Windows-specific issues.
-
- But all these efforts might not be enough, forcing users to make some
-changes themselves. For example, according to
-<http://stackoverflow.com/questions/4485059>, setting the following Git
-variables might also help:
-
- git config --global core.preloadindex true
- git config --global core.fscache true
- git config --global gc.auto 256
-
- You should also check whether an anti-virus program is slowing things
-down.
-
-Log Performance
-...............
-
-When showing logs, Magit limits the number of commits initially shown in
-the hope that this avoids unnecessary work. When using ‘--graph’ is
-used, then this unfortunately does not have the desired effect for large
-histories. Junio, Git’s maintainer, said on the git mailing list
-(<http://www.spinics.net/lists/git/msg232230.html>): "‘--graph’ wants to
-compute the whole history and the max-count only affects the output
-phase after ‘--graph’ does its computation".
-
- In other words, it’s not that Git is slow at outputting the
-differences, or that Magit is slow at parsing the output - the problem
-is that Git first goes outside and has a smoke.
-
- We actually work around this issue by limiting the number of commits
-not only by using ‘-<N>’ but by also using a range. But unfortunately
-that’s not always possible.
-
- In repositories with more than a few thousand commits ‘--graph’
-should never be a member of ‘magit-log-section-arguments’. That
-variable is used in the status buffer which is refreshed every time you
-run any Magit command.
-
- Using ‘--color --graph’ is even slower. Magit uses code that is part
-of Emacs to turn control characters into faces. That code is pretty
-slow and this is quite noticeable when showing a log with many branches
-and merges. For that reason ‘--color’ is not enabled by default
-anymore. Consider leaving it at that.
-
-Diff Performance
-................
-
-If diffs are slow, then consider turning off some optional diff features
-by setting all or some of the following variables to ‘nil’:
-‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’,
-‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and
-‘magit-diff-refine-hunk’.
-
-Refs Buffer Performance
-.......................
-
-When refreshing the "references buffer" is slow, then that’s usually
-because several hundred refs are being displayed. The best way to
-address that is to display fewer refs, obviously.
-
- If you are not, or only mildly, interested in seeing the list of
-tags, then start by not displaying them:
-
- (remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
-
- Then you should also make sure that the listed remote branches
-actually all exist. You can do so by pruning branches which no longer
-exist using ‘f-pa’.
-
-\1f
-File: magit.info, Node: Plumbing, Next: FAQ, Prev: Customizing, Up: Top
-
-10 Plumbing
-***********
-
-The following sections describe how to use several of Magit’s core
-abstractions to extend Magit itself or implement a separate extension.
-
- A few of the low-level features used by Magit have been factored out
-into separate libraries/packages, so that they can be used by other
-packages, without having to depend on Magit. These libraries are
-described in separate manuals, see *note (with-editor)Top:: and *note
-(magit-popup)Top::.
-
-* Menu:
-
-* Calling Git::
-* Section plumbing::
-* Refreshing buffers::
-* Conventions::
-
-\1f
-File: magit.info, Node: Calling Git, Next: Section plumbing, Up: Plumbing
-
-10.1 Calling Git
-================
-
-Magit provides many specialized functions for calling Git. All of these
-functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and
-have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or
-‘magit-git-’ (which is also used for other things).
-
- All of these functions accept an indefinite number of arguments,
-which are strings that specify command line arguments for git (or in
-some cases an arbitrary executable). These arguments are flattened
-before being passed on to the executable; so instead of strings they can
-also be lists of strings and arguments that are ‘nil’ are silently
-dropped. Some of these functions also require a single mandatory
-argument before these command line arguments.
-
- Roughly speaking these functions run Git either to get some value or
-for side-effect. The functions that return a value are useful to
-collect the information necessary to populate a Magit buffer, while the
-others are used to implement Magit commands.
-
- The functions in the value-only group always run synchronously, and
-they never trigger a refresh. The function in the side-effect group can
-be further divided into subgroups depending on whether they run Git
-synchronously or asynchronously, and depending on whether they trigger a
-refresh when the executable has finished.
-
-* Menu:
-
-* Getting a value from Git::
-* Calling Git for effect::
-
-\1f
-File: magit.info, Node: Getting a value from Git, Next: Calling Git for effect, Up: Calling Git
-
-10.1.1 Getting a value from Git
--------------------------------
-
-These functions run Git in order to get a value, either its exit status
-or its output. Of course you could also use them to run Git commands
-that have side-effects, but that should be avoided.
-
- -- Function: magit-git-exit-code &rest args
-
- Executes git with ARGS and returns its exit code.
-
- -- Function: magit-git-success &rest args
-
- Executes git with ARGS and returns ‘t’ if the exit code is ‘0’,
- ‘nil’ otherwise.
-
- -- Function: magit-git-failure &rest args
-
- Executes git with ARGS and returns ‘t’ if the exit code is ‘1’,
- ‘nil’ otherwise.
-
- -- Function: magit-git-true &rest args
-
- Executes git with ARGS and returns ‘t’ if the first line printed by
- git is the string "true", ‘nil’ otherwise.
-
- -- Function: magit-git-false &rest args
-
- Executes git with ARGS and returns ‘t’ if the first line printed by
- git is the string "false", ‘nil’ otherwise.
-
- -- Function: magit-git-insert &rest args
-
- Executes git with ARGS and inserts its output at point.
-
- -- Function: magit-git-string &rest args
-
- Executes git with ARGS and returns the first line of its output.
- If there is no output or if it begins with a newline character,
- then this returns ‘nil’.
-
- -- Function: magit-git-lines &rest args
-
- Executes git with ARGS and returns its output as a list of lines.
- Empty lines anywhere in the output are omitted.
-
- -- Function: magit-git-items &rest args
-
- Executes git with ARGS and returns its null-separated output as a
- list. Empty items anywhere in the output are omitted.
-
- If the value of option ‘magit-git-debug’ is non-nil and git exits
- with a non-zero exit status, then warn about that in the echo area
- and add a section containing git’s standard error in the current
- repository’s process buffer.
-
- When an error occurs when using one of the above functions, then that
-is usually due to a bug, i.e. the use of an argument which is not
-actually supported. Such errors are usually not reported, but when they
-occur we need to be able to debug them.
-
- -- User Option: magit-git-debug
-
- Whether to report errors that occur when using ‘magit-git-insert’,
- ‘magit-git-string’, ‘magit-git-lines’, or ‘magit-git-items’. This
- does not actually raise an error. Instead a message is shown in
- the echo area, and git’s standard error is insert into a new
- section in the current repository’s process buffer.
-
- -- Function: magit-git-str &rest args
-
- This is a variant of ‘magit-git-string’ that ignores the option
- ‘magit-git-debug’. It is mainly intended to be used while handling
- errors in functions that do respect that option. Using such a
- function while handing an error could cause yet another error and
- therefore lead to an infinite recursion. You probably won’t ever
- need to use this function.
-
-\1f
-File: magit.info, Node: Calling Git for effect, Prev: Getting a value from Git, Up: Calling Git
-
-10.1.2 Calling Git for effect
------------------------------
-
-These functions are used to run git to produce some effect. Most Magit
-commands that actually run git do so by using such a function.
-
- Because we do not need to consume git’s output when using these
-functions, their output is instead logged into a per-repository buffer,
-which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’
-elsewhere.
-
- These functions can have an effect in two distinct ways. Firstly,
-running git may change something, i.e. create or push a new commit.
-Secondly, that change may require that Magit buffers are refreshed to
-reflect the changed state of the repository. But refreshing isn’t
-always desirable, so only some of these functions do perform such a
-refresh after git has returned.
-
- Sometimes it is useful to run git asynchronously. For example, when
-the user has just initiated a push, then there is no reason to make her
-wait until that has completed. In other cases it makes sense to wait
-for git to complete before letting the user do something else. For
-example after staging a change it is useful to wait until after the
-refresh because that also automatically moves to the next change.
-
- -- Function: magit-call-git &rest args
-
- Calls git synchronously with ARGS.
-
- -- Function: magit-call-process program &rest args
-
- Calls PROGRAM synchronously with ARGS.
-
- -- Function: magit-run-git &rest args
-
- Calls git synchronously with ARGS and then refreshes.
-
- -- Function: magit-run-git-with-input input &rest args
-
- Calls git synchronously with ARGS and sends it INPUT on standard
- input.
-
- INPUT should be a buffer or the name of an existing buffer. The
- content of that buffer is used as the process’ standard input.
- After the process returns a refresh is performed.
-
- As a special case, INPUT may also be nil. In that case the content
- of the current buffer is used as standard input and *no* refresh is
- performed.
-
- This function actually runs git asynchronously. But then it waits
- for the process to return, so the function itself is synchronous.
-
- -- Function: magit-run-git-with-logfile file &rest args
-
- Calls git synchronously with ARGS. The process’ output is saved in
- FILE. This is rarely useful and so this function might be removed
- in the future.
-
- This function actually runs git asynchronously. But then it waits
- for the process to return, so the function itself is synchronous.
-
- -- Function: magit-git &rest args
-
- Calls git synchronously with ARGS for side-effects only. This
- function does not refresh the buffer.
-
- -- Function: magit-git-wash washer &rest args
-
- Execute Git with ARGS, inserting washed output at point. Actually
- first insert the raw output at point. If there is no output call
- ‘magit-cancel-section’. Otherwise temporarily narrow the buffer to
- the inserted text, move to its beginning, and then call function
- WASHER with no argument.
-
- And now for the asynchronous variants.
-
- -- Function: magit-run-git-async &rest args
-
- Start Git, prepare for refresh, and return the process object.
- ARGS is flattened and then used as arguments to Git.
-
- Display the command line arguments in the echo area.
-
- After Git returns some buffers are refreshed: the buffer that was
- current when this function was called (if it is a Magit buffer and
- still alive), as well as the respective Magit status buffer.
- Unmodified buffers visiting files that are tracked in the current
- repository are reverted if ‘magit-revert-buffers’ is non-nil.
-
- -- Function: magit-run-git-with-editor &rest args
-
- Export GIT_EDITOR and start Git. Also prepare for refresh and
- return the process object. ARGS is flattened and then used as
- arguments to Git.
-
- Display the command line arguments in the echo area.
-
- After Git returns some buffers are refreshed: the buffer that was
- current when this function was called (if it is a Magit buffer and
- still alive), as well as the respective Magit status buffer.
-
- -- Function: magit-start-git &rest args
-
- Start Git, prepare for refresh, and return the process object.
-
- If INPUT is non-nil, it has to be a buffer or the name of an
- existing buffer. The buffer content becomes the processes standard
- input.
-
- Option ‘magit-git-executable’ specifies the Git executable and
- option ‘magit-git-global-arguments’ specifies constant arguments.
- The remaining arguments ARGS specify arguments to Git. They are
- flattened before use.
-
- After Git returns, some buffers are refreshed: the buffer that was
- current when this function was called (if it is a Magit buffer and
- still alive), as well as the respective Magit status buffer.
- Unmodified buffers visiting files that are tracked in the current
- repository are reverted if ‘magit-revert-buffers’ is non-nil.
-
- -- Function: magit-start-process &rest args
-
- Start PROGRAM, prepare for refresh, and return the process object.
-
- If optional argument INPUT is non-nil, it has to be a buffer or the
- name of an existing buffer. The buffer content becomes the
- processes standard input.
-
- The process is started using ‘start-file-process’ and then setup to
- use the sentinel ‘magit-process-sentinel’ and the filter
- ‘magit-process-filter’. Information required by these functions is
- stored in the process object. When this function returns the
- process has not started to run yet so it is possible to override
- the sentinel and filter.
-
- After the process returns, ‘magit-process-sentinel’ refreshes the
- buffer that was current when ‘magit-start-process’ was called (if
- it is a Magit buffer and still alive), as well as the respective
- Magit status buffer. Unmodified buffers visiting files that are
- tracked in the current repository are reverted if
- ‘magit-revert-buffers’ is non-nil.
-
- -- Variable: magit-this-process
-
- The child process which is about to start. This can be used to
- change the filter and sentinel.
-
- -- Variable: magit-process-raise-error
-
- When this is non-nil, then ‘magit-process-sentinel’ raises an error
- if git exits with a non-zero exit status. For debugging purposes.
-
-\1f
-File: magit.info, Node: Section plumbing, Next: Refreshing buffers, Prev: Calling Git, Up: Plumbing
-
-10.2 Section plumbing
-=====================
-
-* Menu:
-
-* Creating sections::
-* Section selection::
-* Matching sections::
-
-\1f
-File: magit.info, Node: Creating sections, Next: Section selection, Up: Section plumbing
-
-10.2.1 Creating sections
-------------------------
-
- -- Macro: magit-insert-section &rest args
-
- Insert a section at point.
-
- TYPE is the section type, a symbol. Many commands that act on the
- current section behave differently depending on that type. Also if
- a variable ‘magit-TYPE-section-map’ exists, then use that as the
- text-property ‘keymap’ of all text belonging to the section (but
- this may be overwritten in subsections).
-
- Optional VALUE is the value of the section, usually a string that
- is required when acting on the section.
-
- When optional HIDE is non-nil collapse the section body by default,
- i.e. when first creating the section, but not when refreshing the
- buffer. Otherwise, expand it by default. This can be overwritten
- using ‘magit-section-set-visibility-hook’. When a section is
- recreated during a refresh, then the visibility of predecessor is
- inherited and HIDE is ignored (but the hook is still honored).
-
- BODY is any number of forms that actually insert the section’s
- heading and body. Optional NAME, if specified, has to be a symbol,
- which is then bound to the struct of the section being inserted.
-
- Before BODY is evaluated the ‘start’ of the section object is set
- to the value of ‘point’ and after BODY was evaluated its ‘end’ is
- set to the new value of ‘point’; BODY is responsible for moving
- ‘point’ forward.
-
- If it turns out inside BODY that the section is empty, then
- ‘magit-cancel-section’ can be used to abort and remove all traces
- of the partially inserted section. This can happen when creating a
- section by washing Git’s output and Git didn’t actually output
- anything this time around.
-
- -- Function: magit-insert-heading &rest args
-
- Insert the heading for the section currently being inserted.
-
- This function should only be used inside ‘magit-insert-section’.
-
- When called without any arguments, then just set the ‘content’ slot
- of the object representing the section being inserted to a marker
- at ‘point’. The section should only contain a single line when
- this function is used like this.
-
- When called with arguments ARGS, which have to be strings, then
- insert those strings at point. The section should not contain any
- text before this happens and afterwards it should again only
- contain a single line. If the ‘face’ property is set anywhere
- inside any of these strings, then insert all of them unchanged.
- Otherwise use the ‘magit-section-heading’ face for all inserted
- text.
-
- The ‘content’ property of the section struct is the end of the
- heading (which lasts from ‘start’ to ‘content’) and the beginning
- of the body (which lasts from ‘content’ to ‘end’). If the value of
- ‘content’ is nil, then the section has no heading and its body
- cannot be collapsed. If a section does have a heading then its
- height must be exactly one line, including a trailing newline
- character. This isn’t enforced; you are responsible for getting it
- right. The only exception is that this function does insert a
- newline character if necessary.
-
- -- Function: magit-cancel-section
-
- Cancel the section currently being inserted. This exits the
- innermost call to ‘magit-insert-section’ and removes all traces of
- what has already happened inside that call.
-
- -- Function: magit-define-section-jumper sym title &optional value
-
- Define an interactive function to go to section SYM. TITLE is the
- displayed title of the section.
-
-\1f
-File: magit.info, Node: Section selection, Next: Matching sections, Prev: Creating sections, Up: Section plumbing
-
-10.2.2 Section selection
-------------------------
-
- -- Function: magit-current-section
-
- Return the section at point.
-
- -- Function: magit-region-sections
-
- Return a list of the selected sections.
-
- When the region is active and constitutes a valid section
- selection, then return a list of all selected sections. This is
- the case when the region begins in the heading of a section and
- ends in the heading of a sibling of that first section. When the
- selection is not valid then return nil. Most commands that can act
- on the selected sections, then instead just act on the current
- section, the one point is in.
-
- When the region looks like it would in any other buffer then the
- selection is invalid. When the selection is valid then the region
- uses the ‘magit-section-highlight’. This does not apply to diffs
- where things get a bit more complicated, but even here if the
- region looks like it usually does, then that’s not a valid
- selection as far as this function is concerned.
-
- -- Function: magit-region-values &rest types
-
- Return a list of the values of the selected sections.
-
- Also see ‘magit-region-sections’ whose doc-string explains when a
- region is a valid section selection. If the region is not active
- or is not a valid section selection, then return nil. If optional
- TYPES is non-nil then the selection not only has to be valid; the
- types of all selected sections additionally have to match one of
- TYPES, or nil is returned.
-
-\1f
-File: magit.info, Node: Matching sections, Prev: Section selection, Up: Section plumbing
-
-10.2.3 Matching sections
-------------------------
-
-‘M-x magit-describe-section’ (‘magit-describe-section’)
-
- Show information about the section at point. This command is
- intended for debugging purposes.
-
- -- Function: magit-section-ident
-
- Return an unique identifier for SECTION. The return value has the
- form ‘((TYPE . VALUE)...)’.
-
- -- Function: magit-get-section
-
- Return the section identified by IDENT. IDENT has to be a list as
- returned by ‘magit-section-ident’.
-
- -- Function: magit-section-match condition &optional section
-
- Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the
- section at point.
-
- Conditions can take the following forms:
- • ‘(CONDITION...)’
-
- matches if any of the CONDITIONs matches.
-
- • ‘[TYPE...]’
-
- matches if the first TYPE matches the type of the section at
- point, the second matches that of its parent, and so on.
-
- • ‘[* TYPE...]’
-
- matches sections that match [TYPE…] and also recursively all
- their child sections.
-
- • ‘TYPE’
-
- matches TYPE regardless of its parents.
- Each TYPE is a symbol. Note that is not necessary to specify all
- TYPEs up to the root section as printed by ‘magit-describe-type’,
- unless of course your want to be that precise.
-
- -- Function: magit-section-when condition &rest body
-
- If the section at point matches CONDITION evaluate BODY.
-
- If the section matches evaluate BODY forms sequentially and return
- the value of the last one, or if there are no BODY forms return the
- value of the section. If the section does not match return nil.
-
- See ‘magit-section-match’ for the forms CONDITION can take.
-
- -- Function: magit-section-case &rest clauses
-
- Choose among clauses on the type of the section at point.
-
- Each clause looks like (CONDITION BODY…). The type of the section
- is compared against each CONDITION; the BODY forms of the first
- match are evaluated sequentially and the value of the last form is
- returned. Inside BODY the symbol ‘it’ is bound to the section at
- point. If no clause succeeds or if there is no section at point
- return nil.
-
- See ‘magit-section-match’ for the forms CONDITION can take.
- Additionally a CONDITION of t is allowed in the final clause and
- matches if no other CONDITION match, even if there is no section at
- point.
-
- -- Variable: magit-root-section
-
- The root section in the current buffer. All other sections are
- descendants of this section. The value of this variable is set by
- ‘magit-insert-section’ and you should never modify it.
-
- For diff related sections a few additional tools exist.
-
- -- Function: magit-diff-type &optional section
-
- Return the diff type of SECTION.
-
- The returned type is one of the symbols ‘staged’, ‘unstaged’,
- ‘committed’, or ‘undefined’. This type serves a similar purpose as
- the general type common to all sections (which is stored in the
- ‘type’ slot of the corresponding ‘magit-section’ struct) but takes
- additional information into account. When the SECTION isn’t
- related to diffs and the buffer containing it also isn’t a
- diff-only buffer, then return nil.
-
- Currently the type can also be one of ‘tracked’ and ‘untracked’,
- but these values are not handled explicitly in every place they
- should be. A possible fix could be to just return nil here.
-
- The section has to be a ‘diff’ or ‘hunk’ section, or a section
- whose children are of type ‘diff’. If optional SECTION is nil,
- return the diff type for the current section. In buffers whose
- major mode is ‘magit-diff-mode’ SECTION is ignored and the type is
- determined using other means. In ‘magit-revision-mode’ buffers the
- type is always ‘committed’.
-
- -- Function: magit-diff-scope &optional section strict
-
- Return the diff scope of SECTION or the selected section(s).
-
- A diff’s "scope" describes what part of a diff is selected, it is a
- symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or
- ‘list’. Do not confuse this with the diff "type", as returned by
- ‘magit-diff-type’.
-
- If optional SECTION is non-nil, then return the scope of that,
- ignoring the sections selected by the region. Otherwise return the
- scope of the current section, or if the region is active and
- selects a valid group of diff related sections, the type of these
- sections, i.e. ‘hunks’ or ‘files’. If SECTION (or if the current
- section that is nil) is a ‘hunk’ section and the region starts and
- ends inside the body of a that section, then the type is ‘region’.
-
- If optional STRICT is non-nil then return nil if the diff type of
- the section at point is ‘untracked’ or the section at point is not
- actually a ‘diff’ but a ‘diffstat’ section.
-
-\1f
-File: magit.info, Node: Refreshing buffers, Next: Conventions, Prev: Section plumbing, Up: Plumbing
-
-10.3 Refreshing buffers
-=======================
-
-All commands that create a new Magit buffer or change what is being
-displayed in an existing buffer do so by calling ‘magit-mode-setup’.
-Among other things, that function sets the buffer local values of
-‘default-directory’ (to the top-level of the repository),
-‘magit-refresh-function’, and ‘magit-refresh-args’.
-
- Buffers are refreshed by calling the function that is the local value
-of ‘magit-refresh-function’ (a function named ‘magit-*-refresh-buffer’,
-where ‘*’ may be something like ‘diff’) with the value of
-‘magit-refresh-args’ as arguments.
-
- -- Macro: magit-mode-setup buffer switch-func mode refresh-func
- &optional refresh-args
-
- This function displays and selects BUFFER, turns on MODE, and
- refreshes a first time.
-
- This function displays and optionally selects BUFFER by calling
- ‘magit-mode-display-buffer’ with BUFFER, MODE and SWITCH-FUNC as
- arguments. Then it sets the local value of
- ‘magit-refresh-function’ to REFRESH-FUNC and that of
- ‘magit-refresh-args’ to REFRESH-ARGS. Finally it creates the buffer
- content by calling REFRESH-FUNC with REFRESH-ARGS as arguments.
-
- All arguments are evaluated before switching to BUFFER.
-
- -- Function: magit-mode-display-buffer buffer mode &optional
- switch-function
-
- This function display BUFFER in some window and select it. BUFFER
- may be a buffer or a string, the name of a buffer. The buffer is
- returned.
-
- Unless BUFFER is already displayed in the selected frame, store the
- previous window configuration as a buffer local value, so that it
- can later be restored by ‘magit-mode-bury-buffer’.
-
- The buffer is displayed and selected using SWITCH-FUNCTION. If that
- is ‘nil’ then ‘pop-to-buffer’ is used if the current buffer’s major
- mode derives from ‘magit-mode’. Otherwise ‘switch-to-buffer’ is
- used.
-
- -- Variable: magit-refresh-function
-
- The value of this buffer-local variable is the function used to
- refresh the current buffer. It is called with ‘magit-refresh-args’
- as arguments.
-
- -- Variable: magit-refresh-args
-
- The list of arguments used by ‘magit-refresh-function’ to refresh
- the current buffer. ‘magit-refresh-function’ is called with these
- arguments.
-
- The value is usually set using ‘magit-mode-setup’, but in some
- cases it’s also useful to provide commands which can change the
- value. For example, the ‘magit-diff-refresh-popup’ can be used to
- change any of the arguments used to display the diff, without
- having to specify again which differences should be shown.
- ‘magit-diff-more-context’, ‘magit-diff-less-context’, and
- ‘magit-diff-default-context’ change just the ‘-U<N>’ argument. In
- both case this is done by changing the value of this variable and
- then calling this ‘magit-refresh-function’.
-
-\1f
-File: magit.info, Node: Conventions, Prev: Refreshing buffers, Up: Plumbing
-
-10.4 Conventions
-================
-
-* Menu:
-
-* Confirmation and completion::
-* Theming Faces::
-
-\1f
-File: magit.info, Node: Confirmation and completion, Next: Theming Faces, Up: Conventions
-
-10.4.1 Confirmation and completion
-----------------------------------
-
-Dangerous operations that may lead to data loss have to be confirmed by
-default. With a multi-section selection, this is done using questions
-that can be answered with "yes" or "no". When the region isn’t active,
-or if it doesn’t constitute a valid section selection, then such
-commands instead read a single item in the minibuffer. When the value
-of the current section is among the possible choices, then that is
-presented as default choice. To confirm the action on a single item,
-the user has to answer ‘RET’ (instead of "yes"), and to abort, ‘C-g’
-(instead of "no"). But alternatively the user may also select another
-item, just like if the command had been invoked with no suitable section
-at point at all.
-
-\1f
-File: magit.info, Node: Theming Faces, Prev: Confirmation and completion, Up: Conventions
-
-10.4.2 Theming Faces
---------------------
-
-The default theme uses blue for local branches, green for remote
-branches, and goldenrod (brownish yellow) for tags. When creating a new
-theme, you should probably follow that example. If your theme already
-uses other colors, then stick to that.
-
- In older releases these reference faces used to have a background
-color and a box around them. The basic default faces no longer do so,
-to make Magit buffers much less noisy, and you should follow that
-example at least with regards to boxes. (Boxes were used in the past to
-work around a conflict between the highlighting overlay and text
-property backgrounds. That’s no longer necessary because highlighting
-no longer causes other background colors to disappear.) Alternatively
-you can keep the background color and/or box, but then have to take
-special care to adjust ‘magit-branch-current’ accordingly. By default
-it looks mostly like ‘magit-branch-local’, but with a box (by default
-the former is the only face that uses a box, exactly so that it sticks
-out). If the former also uses a box, then you have to make sure that it
-differs in some other way from the latter.
-
- The most difficult faces to theme are those related to diffs,
-headings, highlighting, and the region. There are faces that fall into
-all four groups - expect to spend some time getting this right.
-
- The ‘region’ face in the default theme, in both the light and dark
-variants, as well as in many other themes, distributed with Emacs or by
-third-parties, is very ugly. It is common to use a background color
-that really sticks out, which is ugly but if that were the only problem
-then it would be acceptable. Unfortunately many themes also set the
-foreground color, which ensures that all text within the region is
-readable. Without doing that there might be cases where some foreground
-color is too close to the region background color to still be readable.
-But it also means that text within the region loses all syntax
-highlighting.
-
- I consider the work that went into getting the ‘region’ face right to
-be a good indicator for the general quality of a theme. My
-recommendation for the ‘region’ face is this: use a background color
-slightly different from the background color of the ‘default’ face, and
-do not set the foreground color at all. So for a light theme you might
-use a light (possibly tinted) gray as the background color of ‘default’
-and a somewhat darker gray for the background of ‘region’. That should
-usually be enough to not collide with the foreground color of any other
-face. But if some other faces also set a light gray as background
-color, then you should also make sure it doesn’t collide with those (in
-some cases it might be acceptable though).
-
- Magit only uses the ‘region’ face when the region is "invalid" by its
-own definition. In a Magit buffer the region is used to either select
-multiple sibling sections, so that commands which support it act on all
-of these sections instead of just the current section, or to select
-lines within a single hunk section. In all other cases, the section is
-considered invalid and Magit won’t act on it. But such invalid sections
-happen, either because the user has not moved point enough yet to make
-it valid or because she wants to use a non-magit command to act on the
-region, e.g. ‘kill-region’.
-
- So using the regular ‘region’ face for invalid sections is a feature.
-It tells the user that Magit won’t be able to act on it. It’s
-acceptable if that face looks a bit odd and even (but less so) if it
-collides with the background colors of section headings and other things
-that have a background color.
-
- Magit highlights the current section. If a section has subsections,
-then all of them are highlighted. This is done using faces that have
-"highlight" in their names. For most sections,
-‘magit-section-highlight’ is used for both the body and the heading.
-Like the ‘region’ face, it should only set the background color to
-something similar to that of ‘default’. The highlight background color
-must be different from both the ‘region’ background color and the
-‘default’ background color.
-
- For diff related sections Magit uses various faces to highlight
-different parts of the selected section(s). Note that hunk headings,
-unlike all other section headings, by default have a background color,
-because it is useful to have very visible separators between hunks.
-That face ‘magit-diff-hunk-heading’, should be different from both
-‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as
-well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’.
-By default we do that by changing the foreground color. Changing the
-background color would lead to complications, and there are already
-enough we cannot get around. (Also note that it is generally a good
-idea for section headings to always be bold, but only for sections that
-have subsections).
-
- When there is a valid region selecting diff-related sibling sections,
-i.e. multiple files or hunks, then the bodies of all these sections use
-the respective highlight faces, but additionally the headings instead
-use one of the faces ‘magit-diff-file-heading-selection’ or
-‘magit-diff-hunk-heading-selection’. These faces have to be different
-from the regular highlight variants to provide explicit visual
-indication that the region is active.
-
- When theming diff related faces, start by setting the option
-‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only
-refine the current hunk or not use hunk refinement at all, but some of
-the users of your theme want all hunks to be refined, so you have to
-cater to that.
-
- (Also turn on ‘magit-diff-highlight-indentation’,
-‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and
-insert some whitespace errors into the code you use for testing.)
-
- For e.g. "added lines" you have to adjust three faces:
-‘magit-diff-added’, ‘magit-diff-added-highlight’, and
-‘smerge-refined-added’. Make sure that the latter works well with both
-of the former, as well as ‘smerge-other’ and ‘diff-added’. Then do the
-same for the removed lines, context lines, lines added by us, and lines
-added by them. Also make sure the respective added, removed, and
-context faces use approximately the same saturation for both the
-highlighted and unhighlighted variants. Also make sure the file and
-diff headings work nicely with context lines (e.g. make them look
-different). Line faces should set both the foreground and the
-background color. For example, for added lines use two different
-greens.
-
- It’s best if the foreground color of both the highlighted and the
-unhighlighted variants are the same, so you will need to have to find a
-color that works well on the highlight and unhighlighted background, the
-refine background, and the highlight context background. When there is
-an hunk internal region, then the added- and removed-lines background
-color is used only within that region. Outside the region the
-highlighted context background color is used. This makes it easier to
-see what is being staged. With an hunk internal region the hunk heading
-is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin
-lines that are added around the lines that fall within the region. The
-background color of that has to be distinct enough from the various
-other involved background colors.
-
- Nobody said this would be easy. If your theme restricts itself to a
-certain set of colors, then you should make an exception here.
-Otherwise it would be impossible to make the diffs look good in each and
-every variation. Actually you might want to just stick to the default
-definitions for these faces. You have been warned. Also please note
-that if you do not get this right, this will in some cases look to users
-like bugs in Magit - so please do it right or not at all.
-
-\1f
-File: magit.info, Node: FAQ, Next: Keystroke Index, Prev: Plumbing, Up: Top
-
-Appendix A FAQ
-**************
-
-Below you find a list of frequently asked questions. For a list of
-frequently *and recently* asked questions, i.e. questions that haven’t
-made it into the manual yet, see
-<https://github.com/magit/magit/wiki/FAQ>.
-
-* Menu:
-
-* Magit is slow::
-* I changed several thousand files at once and now Magit is unusable::
-* I am having problems committing::
-* I don't understand how branching and pushing work::
-* I don’t like the key binding in v2.4: I don't like the key binding in v24.
-* I cannot install the pre-requisites for Magit v2::
-* I am using an Emacs release older than v24.4: I am using an Emacs release older than v244.
-* I am using a Git release older than v1.9.4: I am using a Git release older than v194.
-* I am using MS Windows and cannot push with Magit::
-* How to install the gitman info manual?::
-* How can I show Git's output?::
-* Expanding a file to show the diff causes it to disappear::
-* Point is wrong in the COMMIT_EDITMSG buffer::
-* Can Magit be used as ediff-version-control-package?::
-* How to show diffs for gpg-encrypted files?::
-* Emacs 24.5 hangs when loading Magit: Emacs 245 hangs when loading Magit.
-* Symbol's value as function is void --some::
-* Where is the branch manager::
-
-\1f
-File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ
-
-A.1 Magit is slow
-=================
-
-See *note Performance: Performance.
-
-\1f
-File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ
-
-A.2 I changed several thousand files at once and now Magit is unusable
-======================================================================
-
-Magit is *currently* not expected to work under such conditions. It
-sure would be nice if it did, and v2.5 will hopefully be a big step into
-that direction. But it might take until v3.1 to accomplish fully
-satisfactory performance, because that requires some heavy refactoring.
-
- But for now we recommend you use the command line to complete this
-one commit. Also see *note Performance: Performance.
-
-\1f
-File: magit.info, Node: I am having problems committing, Next: I don't understand how branching and pushing work, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ
-
-A.3 I am having problems committing
-===================================
-
-That likely means that Magit is having problems finding an appropriate
-emacsclient executable. See *note (with-editor)Configuring
-With-Editor:: and *note (with-editor)Debugging::.
-
-\1f
-File: magit.info, Node: I don't understand how branching and pushing work, Next: I don't like the key binding in v24, Prev: I am having problems committing, Up: FAQ
-
-A.4 I don’t understand how branching and pushing work
-=====================================================
-
-Please see *note Branching: Branching. and
-<http://emacsair.me/2016/01/18/magit-2.4>
-
-\1f
-File: magit.info, Node: I don't like the key binding in v24, Next: I cannot install the pre-requisites for Magit v2, Prev: I don't understand how branching and pushing work, Up: FAQ
-
-A.5 I don’t like the key binding in v2.4
-========================================
-
-Please see <http://emacsair.me/2016/01/1/restore-old-bindings>.
-
-\1f
-File: magit.info, Node: I cannot install the pre-requisites for Magit v2, Next: I am using an Emacs release older than v244, Prev: I don't like the key binding in v24, Up: FAQ
-
-A.6 I cannot install the pre-requisites for Magit v2
-====================================================
-
-An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies is
-available from <http://magit.vc/elpa/v1>. But note that v1.4.2 is
-obsolete and no longer maintained.
-
-\1f
-File: magit.info, Node: I am using an Emacs release older than v244, Next: I am using a Git release older than v194, Prev: I cannot install the pre-requisites for Magit v2, Up: FAQ
-
-A.7 I am using an Emacs release older than v24.4
-================================================
-
-At least Emacs v24.4 is required. There is no way around it, if you
-want to use Magit v2.
-
- If you own the machine you work on, then consider updating to the
-latest release provided by your distribution. If it doesn’t feature a
-recent enough release, then you will have to use a backport package or
-build Emacs from source.
-
- Installing Emacs from source is quite simple. See the instructions
-at <http://git.savannah.gnu.org/cgit/emacs.git/tree/INSTALL> and
-<http://git.savannah.gnu.org/cgit/emacs.git/tree/INSTALL.REPO> to get an
-idea of that this involves. But when you perform the installation then
-use the instructions for the release you are actually installing.
-
- Unfortunately these instructions do not cover the hardest part (which
-is the hardest part exactly because it is not covered there): installing
-the build time dependencies.
-
- For that you’ll need to perform a web search and find an appropriate
-tutorial for your distribution. If you think you should not have had to
-do that yourself, then consider informing me about the resources that
-helped you figure what to do for your specific setup, so that I can post
-a link here. That way those coming after you have it easier.
-
- An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies
-is available from <http://magit.vc/elpa/v1>.
-
-\1f
-File: magit.info, Node: I am using a Git release older than v194, Next: I am using MS Windows and cannot push with Magit, Prev: I am using an Emacs release older than v244, Up: FAQ
-
-A.8 I am using a Git release older than v1.9.4
-==============================================
-
-At least Git v1.9.4 is required. There is no way around it, if you want
-to use Magit v2.
-
- If you own the machine, then consider updating to the latest release
-provided by your distribution. If it doesn’t feature a recent enough
-release, then you will have to use a backport package or build Git from
-source.
-
- Installing Git from source is quite simple. See the instructions at
-<https://github.com/git/git/blob/master/INSTALL> to get an idea of that
-this involves. But when you perform the installation then use the
-instructions for the release you are actually installing.
-
- An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies
-is available from <http://magit.vc/elpa/v1>.
-
-\1f
-File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: How to install the gitman info manual?, Prev: I am using a Git release older than v194, Up: FAQ
-
-A.9 I am using MS Windows and cannot push with Magit
-====================================================
-
-It’s almost certain that Magit is only incidental to this issue. It is
-much more likely that this is a configuration issue, even if you can
-push on the command line.
-
- Detailed setup instructions can be found at
-<https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows>.
-
-\1f
-File: magit.info, Node: How to install the gitman info manual?, Next: How can I show Git's output?, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ
-
-A.10 How to install the gitman info manual?
-===========================================
-
-Git’s manpages can be exported as an info manual called ‘gitman’.
-Magit’s own info manual links to nodes in that manual instead of the
-actual manpages because texinfo sadly doesn’t support linking to
-manpages.
-
- Unfortunately many distributions do not install the ‘gitman’ manual
-by default. Some distributions may provide a separate package
-containing the info manual. Please let me know the name of that package
-for your distribution, so that I can mention here.
-
- If the distribution you are using does not offer a package that
-contains the ‘gitman’ manual, then you have to install it manually.
-Clone Git’s own Git repository, checkout the tag corresponding to the
-Git release you have installed, and follow the instructions in
-‘INSTALL’. The relevant make targets are ‘info’ and ‘install-info’.
-
- Alternatively you may add this advice to your ‘init.el’ file.
-
- (defadvice Info-follow-nearest-node (around gitman activate)
- "When encountering a cross reference to the `gitman' info
- manual, then instead of following that cross reference show
- the actual manpage using the function `man'."
- (let ((node (Info-get-token
- (point) "\\*note[ \n\t]+"
- "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
- (if (and node (string-match "^(gitman)\\(.+\\)" node))
- (progn (require 'man)
- (man (match-string 1 node)))
- ad-do-it)))
-
- Or if you are using MS Windows and ‘man’ is not available, use this
-variation with used the Emacs Lisp implementation provided by the
-‘woman’ package.
-
- (defadvice Info-follow-nearest-node (around gitman activate)
- "When encountering a cross reference to the `gitman' info
- manual, then instead of following that cross reference show
- the actual manpage using the function `woman'."
- (let ((node (Info-get-token
- (point) "\\*note[ \n\t]+"
- "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
- (if (and node (string-match "^(gitman)\\(.+\\)" node))
- (progn (require 'woman)
- (woman (match-string 1 node)))
- ad-do-it)))
-
- Did I mention that texinfo cross reference are just awful? (This is
-just one of many issues.)
-
-\1f
-File: magit.info, Node: How can I show Git's output?, Next: Expanding a file to show the diff causes it to disappear, Prev: How to install the gitman info manual?, Up: FAQ
-
-A.11 How can I show Git’s output?
-=================================
-
-To show the output of recently run git commands, press ‘$’ (or, if that
-isn’t available, ‘M-x magit-process-buffer’). This will show a buffer
-containing a section per git invocation; as always press ‘TAB’ to expand
-or collapse them.
-
- By default git’s output is only inserted into the process buffer if
-it is run for side-effects. When the output is consumed in some way
-then also inserting it into the process buffer would be to expensive.
-For debugging purposes it’s possible to do so anyway by setting
-‘magit-git-debug’ to ‘t’.
-
-\1f
-File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the COMMIT_EDITMSG buffer, Prev: How can I show Git's output?, Up: FAQ
-
-A.12 Expanding a file to show the diff causes it to disappear
-=============================================================
-
-This is probably caused by a change of a ‘diff.*’ Git variable. You
-probably set that variable for a reason, and should therefore only undo
-that setting in Magit by customizing ‘magit-git-global-arguments’.
-
-\1f
-File: magit.info, Node: Point is wrong in the COMMIT_EDITMSG buffer, Next: Can Magit be used as ediff-version-control-package?, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ
-
-A.13 Point is wrong in the COMMIT_EDITMSG buffer
-================================================
-
-Neither Magit nor ‘git-commit‘ fiddle with point in the buffer used to
-write commit messages, so something else must be doing it.
-
- You have probably globally enabled a mode which does restore point in
-file-visiting buffers. It might be a bit surprising, but when you write
-a commit message, then you are actually editing a file.
-
- So you have to figure out which package is doing. ‘saveplace’,
-‘pointback’, and ‘session’ are likely candidates. These snippets might
-help:
-
- (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)")
-
- (with-eval-after-load 'pointback
- (lambda ()
- (when (or git-commit-mode git-rebase-mode)
- (pointback-mode -1))))
-
-\1f
-File: magit.info, Node: Can Magit be used as ediff-version-control-package?, Next: How to show diffs for gpg-encrypted files?, Prev: Point is wrong in the COMMIT_EDITMSG buffer, Up: FAQ
-
-A.14 Can Magit be used as ediff-version-control-package?
-========================================================
-
-No, it cannot. For that to work the functions ‘ediff-magit-internal’
-and ‘ediff-magit-merge-internal’ would have to be implemented, and they
-are not. These two functions are only used by the three commands
-‘ediff-revision’, ‘ediff-merge-revisions-with-ancestor’, and
-‘ediff-merge-revisions’.
-
- These commands only delegate the task of populating buffers with
-certain revisions to the "internal" functions. The equally important
-task of determining which revisions are to be compared/merged is not
-delegated. Instead this is done without any support whatsoever, from
-the version control package/system - meaning that the user has to enter
-the revisions explicitly. Instead of implementing
-‘ediff-magit-internal’ we provide ‘magit-ediff-compare’, which handles
-both tasks like it is 2005.
-
- The other commands ‘ediff-merge-revisions’ and
-‘ediff-merge-revisions-with-ancestor’ are normally not what you want
-when using a modern version control system like Git. Instead of letting
-the user resolve only those conflicts which Git could not resolve on its
-own, they throw away all work done by Git and then expect the user to
-manually merge all conflicts, including those that had already been
-resolved. That made sense back in the days when version control systems
-couldn’t merge (or so I have been told), but not anymore. Once in a
-blue moon you might actually want to see all conflicts, in which case
-you *can* use these commands, which then use ‘ediff-vc-merge-internal’.
-So we don’t actually have to implement ‘ediff-magit-merge-internal’.
-Instead we provide the more useful command ‘magit-ediff-resolve’ which
-only shows yet-to-be resolved conflicts.
-
-\1f
-File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: Emacs 245 hangs when loading Magit, Prev: Can Magit be used as ediff-version-control-package?, Up: FAQ
-
-A.15 How to show diffs for gpg-encrypted files?
-===============================================
-
-Git supports showing diffs for encrypted files, but has to be told to do
-so. Since Magit just uses Git to get the diffs, configuring Git also
-affects the diffs displayed inside Magit.
-
- git config --global diff.gpg.textconv "gpg --no-tty --decrypt"
- echo "*.gpg filter=gpg diff=gpg" > .gitattributes
-
-\1f
-File: magit.info, Node: Emacs 245 hangs when loading Magit, Next: Symbol's value as function is void --some, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ
-
-A.16 Emacs 24.5 hangs when loading Magit
-========================================
-
-This is actually triggered by loading Tramp. See
-<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=20015> for details. You
-can work around the problem by setting
-‘tramp-ssh-controlmaster-options’. Changing your DNS server (e.g. to
-Google’s ‘8.8.8.8’) may also be sufficient to work around the issue.
-
-\1f
-File: magit.info, Node: Symbol's value as function is void --some, Next: Where is the branch manager, Prev: Emacs 245 hangs when loading Magit, Up: FAQ
-
-A.17 Symbol’s value as function is void –some
-=============================================
-
-Update ‘dash’, restart Emacs, and then it will be defined.
-
-\1f
-File: magit.info, Node: Where is the branch manager, Prev: Symbol's value as function is void --some, Up: FAQ
-
-A.18 Where is the branch manager
-================================
-
-‘y’ is bound to the command that shows the "refs buffer", the successor
-of the "branch manager".
-
-\1f
-File: magit.info, Node: Keystroke Index, Next: Command Index, Prev: FAQ, Up: Top
-
-Appendix B Keystroke Index
-**************************
-
-\0\b[index\0\b]
-* Menu:
-
-* !: Running Git manually.
- (line 12)
-* ! !: Running Git manually.
- (line 19)
-* ! a: Running Git manually.
- (line 51)
-* ! b: Running Git manually.
- (line 55)
-* ! g: Running Git manually.
- (line 59)
-* ! k: Running Git manually.
- (line 47)
-* ! p: Running Git manually.
- (line 24)
-* ! s: Running Git manually.
- (line 33)
-* ! S: Running Git manually.
- (line 38)
-* $: Viewing Git output. (line 11)
-* +: Log Buffer. (line 53)
-* + <1>: Refreshing diffs. (line 58)
-* -: Refreshing diffs. (line 54)
-* 0: Refreshing diffs. (line 62)
-* 1: Section visibility. (line 26)
-* 2: Section visibility. (line 26)
-* 3: Section visibility. (line 26)
-* 4: Section visibility. (line 26)
-* =: Log Buffer. (line 47)
-* = <1>: Log Buffer. (line 57)
-* ^: Section movement. (line 31)
-* a: Applying. (line 33)
-* A: Cherry picking. (line 8)
-* A A: Cherry picking. (line 16)
-* A a: Cherry picking. (line 22)
-* A A <1>: Cherry picking. (line 35)
-* A a <1>: Cherry picking. (line 43)
-* A s: Cherry picking. (line 39)
-* B: Bisecting. (line 8)
-* b: Branching. (line 45)
-* B b: Bisecting. (line 31)
-* b b: Branching. (line 182)
-* b c: Branching. (line 200)
-* b d: Branching. (line 241)
-* B g: Bisecting. (line 36)
-* B k: Bisecting. (line 41)
-* b n: Branching. (line 190)
-* B r: Bisecting. (line 47)
-* b r: Branching. (line 247)
-* B s: Bisecting. (line 16)
-* b s: Branching. (line 207)
-* B u: Bisecting. (line 24)
-* b x: Branching. (line 224)
-* c: Initiating a commit. (line 8)
-* c <1>: Editing rebase sequences.
- (line 72)
-* c a: Initiating a commit. (line 18)
-* c A: Initiating a commit. (line 66)
-* c c: Initiating a commit. (line 13)
-* c e: Initiating a commit. (line 22)
-* c f: Initiating a commit. (line 42)
-* c F: Initiating a commit. (line 50)
-* c s: Initiating a commit. (line 54)
-* c S: Initiating a commit. (line 62)
-* c w: Initiating a commit. (line 32)
-* C-<return>: Diff buffer. (line 21)
-* C-<tab>: Section visibility. (line 13)
-* C-c C-a: Editing commit messages.
- (line 128)
-* C-c C-b: Log Buffer. (line 19)
-* C-c C-b <1>: Refreshing diffs. (line 80)
-* C-c C-c: Popup buffers and prefix commands.
- (line 20)
-* C-c C-c <1>: Select from log. (line 14)
-* C-c C-c <2>: Editing commit messages.
- (line 19)
-* C-c C-c <3>: Editing rebase sequences.
- (line 6)
-* C-c C-d: Refreshing diffs. (line 70)
-* C-c C-d <1>: Editing commit messages.
- (line 57)
-* C-c C-f: Log Buffer. (line 23)
-* C-c C-f <1>: Refreshing diffs. (line 84)
-* C-c C-i: Editing commit messages.
- (line 153)
-* C-c C-k: Select from log. (line 20)
-* C-c C-k <1>: Editing commit messages.
- (line 24)
-* C-c C-k <2>: Editing rebase sequences.
- (line 11)
-* C-c C-o: Editing commit messages.
- (line 144)
-* C-c C-p: Editing commit messages.
- (line 148)
-* C-c C-r: Editing commit messages.
- (line 132)
-* C-c C-s: Editing commit messages.
- (line 136)
-* C-c C-t: Editing commit messages.
- (line 140)
-* C-c C-w: Editing commit messages.
- (line 63)
-* C-c M-g: Minor mode for buffers visiting files.
- (line 19)
-* C-c M-g b: Minor mode for buffers visiting files.
- (line 39)
-* C-c M-g c: Minor mode for buffers visiting files.
- (line 49)
-* C-c M-g l: Minor mode for buffers visiting files.
- (line 33)
-* C-c M-g p: Minor mode for buffers visiting files.
- (line 45)
-* C-c M-g s: Minor mode for buffers visiting files.
- (line 24)
-* C-c M-g u: Minor mode for buffers visiting files.
- (line 28)
-* C-s M-s: Editing commit messages.
- (line 35)
-* C-w: Common commands. (line 21)
-* C-x g: Status buffer. (line 22)
-* C-x u: Editing rebase sequences.
- (line 89)
-* d: Diffing. (line 20)
-* D: Refreshing diffs. (line 11)
-* d c: Diffing. (line 67)
-* d d: Diffing. (line 25)
-* D f: Refreshing diffs. (line 45)
-* D g: Refreshing diffs. (line 16)
-* d p: Diffing. (line 59)
-* d r: Diffing. (line 29)
-* D r: Refreshing diffs. (line 40)
-* d s: Diffing. (line 49)
-* D s: Refreshing diffs. (line 21)
-* d t: Diffing. (line 72)
-* D t: Refreshing diffs. (line 36)
-* d u: Diffing. (line 55)
-* d w: Diffing. (line 43)
-* D w: Refreshing diffs. (line 28)
-* DEL: Log Buffer. (line 37)
-* DEL <1>: Diff buffer. (line 48)
-* DEL <2>: Blaming. (line 44)
-* DEL <3>: Editing rebase sequences.
- (line 28)
-* e: Ediffing. (line 6)
-* E: Ediffing. (line 18)
-* e <1>: Editing rebase sequences.
- (line 55)
-* E c: Ediffing. (line 62)
-* E i: Ediffing. (line 54)
-* E m: Ediffing. (line 32)
-* E r: Ediffing. (line 23)
-* E s: Ediffing. (line 45)
-* E u: Ediffing. (line 50)
-* E w: Ediffing. (line 58)
-* f: Editing rebase sequences.
- (line 63)
-* f <1>: Fetching. (line 11)
-* F: Pulling. (line 11)
-* f a: Fetching. (line 28)
-* f e: Fetching. (line 24)
-* F e: Pulling. (line 24)
-* f m: Fetching. (line 32)
-* f p: Fetching. (line 16)
-* F p: Pulling. (line 16)
-* f u: Fetching. (line 20)
-* F u: Pulling. (line 20)
-* g: Automatic Refreshing of Magit Buffers.
- (line 22)
-* G: Automatic Refreshing of Magit Buffers.
- (line 31)
-* j: Diff buffer. (line 38)
-* k: Viewing Git output. (line 19)
-* k <1>: Applying. (line 37)
-* k <2>: Editing rebase sequences.
- (line 68)
-* k <3>: Stashing. (line 92)
-* l: Logging. (line 26)
-* L: Refreshing logs. (line 11)
-* L <1>: Log Buffer. (line 6)
-* l a: Logging. (line 56)
-* l b: Logging. (line 52)
-* L g: Refreshing logs. (line 16)
-* l h: Logging. (line 44)
-* l H: Reflog. (line 19)
-* l l: Logging. (line 31)
-* l L: Logging. (line 48)
-* l o: Logging. (line 37)
-* l O: Reflog. (line 15)
-* l r: Reflog. (line 11)
-* L s: Refreshing logs. (line 21)
-* L t: Refreshing logs. (line 36)
-* L w: Refreshing logs. (line 28)
-* m: Merging. (line 8)
-* M: Remotes. (line 8)
-* m a: Merging. (line 56)
-* M a: Remotes. (line 13)
-* m e: Merging. (line 29)
-* M k: Remotes. (line 28)
-* m m: Merging. (line 16)
-* m m <1>: Merging. (line 51)
-* m n: Merging. (line 36)
-* m p: Merging. (line 43)
-* M r: Remotes. (line 18)
-* M u: Remotes. (line 23)
-* M-1: Section visibility. (line 34)
-* M-2: Section visibility. (line 34)
-* M-3: Section visibility. (line 34)
-* M-4: Section visibility. (line 34)
-* M-<tab>: Section visibility. (line 17)
-* M-n: Section movement. (line 26)
-* M-n <1>: Editing commit messages.
- (line 45)
-* M-n <2>: Editing rebase sequences.
- (line 47)
-* M-p: Section movement. (line 20)
-* M-p <1>: Editing commit messages.
- (line 39)
-* M-p <2>: Editing rebase sequences.
- (line 43)
-* M-w: Blaming. (line 75)
-* M-w <1>: Common commands. (line 10)
-* M-x magit-blame: Blaming. (line 8)
-* M-x magit-blame-popup: Blaming. (line 24)
-* M-x magit-checkout-file: Resetting. (line 37)
-* M-x magit-clone: Repository setup. (line 16)
-* M-x magit-describe-section: Section types and values.
- (line 13)
-* M-x magit-describe-section <1>: Matching sections. (line 6)
-* M-x magit-find-file: Visiting blobs. (line 6)
-* M-x magit-find-file-other-window: Visiting blobs. (line 11)
-* M-x magit-init: Repository setup. (line 6)
-* M-x magit-log-buffer-file: Logging. (line 67)
-* M-x magit-reset-hard: Resetting. (line 32)
-* M-x magit-reset-head: Resetting. (line 21)
-* M-x magit-reset-index: Staging and unstaging.
- (line 84)
-* M-x magit-reset-index <1>: Resetting. (line 14)
-* M-x magit-reset-soft: Resetting. (line 26)
-* M-x magit-reverse-in-index: Staging and unstaging.
- (line 59)
-* M-x magit-stage-file: Staging from file-visiting buffers.
- (line 10)
-* M-x magit-toggle-buffer-lock: Modes and Buffers. (line 17)
-* M-x magit-unstage-file: Staging from file-visiting buffers.
- (line 18)
-* M-x magit-version: Git executable. (line 17)
-* M-x magit-wip-commit: Wip modes. (line 129)
-* n: Section movement. (line 16)
-* n <1>: Blaming. (line 54)
-* N: Blaming. (line 58)
-* n <2>: Editing rebase sequences.
- (line 39)
-* n <3>: Minor mode for buffers visiting blobs.
- (line 16)
-* o: Submodules. (line 8)
-* o a: Submodules. (line 13)
-* o b: Submodules. (line 19)
-* o f: Submodules. (line 37)
-* o i: Submodules. (line 24)
-* o i <1>: Submodules. (line 41)
-* o s: Submodules. (line 33)
-* o u: Submodules. (line 28)
-* p: Section movement. (line 10)
-* p <1>: Blaming. (line 62)
-* P: Blaming. (line 66)
-* p <2>: Editing rebase sequences.
- (line 35)
-* P <1>: Pushing. (line 11)
-* p <3>: Minor mode for buffers visiting blobs.
- (line 12)
-* P e: Pushing. (line 35)
-* P m: Pushing. (line 44)
-* P o: Pushing. (line 39)
-* P p: Pushing. (line 16)
-* P t: Pushing. (line 50)
-* P T: Pushing. (line 56)
-* P u: Pushing. (line 26)
-* q: Quitting Windows. (line 6)
-* q <1>: Log Buffer. (line 12)
-* q <2>: Blaming. (line 70)
-* q <3>: Minor mode for buffers visiting blobs.
- (line 20)
-* r: Rebasing. (line 8)
-* r <1>: Editing rebase sequences.
- (line 51)
-* r a: Rebasing. (line 84)
-* r e: Rebasing. (line 25)
-* r e <1>: Rebasing. (line 80)
-* r f: Rebasing. (line 57)
-* r i: Rebasing. (line 53)
-* r m: Rebasing. (line 61)
-* r o: Rebasing. (line 31)
-* r p: Rebasing. (line 16)
-* r r: Rebasing. (line 72)
-* r s: Rebasing. (line 76)
-* r u: Rebasing. (line 21)
-* r w: Rebasing. (line 65)
-* RET: Diff buffer. (line 6)
-* RET <1>: References buffer. (line 99)
-* RET <2>: Blaming. (line 29)
-* RET <3>: Editing rebase sequences.
- (line 16)
-* s: Staging and unstaging.
- (line 29)
-* S: Staging and unstaging.
- (line 33)
-* s <1>: Editing rebase sequences.
- (line 59)
-* s-<tab>: Section visibility. (line 22)
-* SPC: Log Buffer. (line 27)
-* SPC <1>: Diff buffer. (line 44)
-* SPC <2>: Blaming. (line 34)
-* SPC <3>: Editing rebase sequences.
- (line 21)
-* t: Blaming. (line 79)
-* t <1>: Tagging. (line 8)
-* T: Notes. (line 8)
-* T a: Notes. (line 70)
-* T c: Notes. (line 65)
-* t k: Tagging. (line 18)
-* T m: Notes. (line 56)
-* t p: Tagging. (line 24)
-* T p: Notes. (line 29)
-* T r: Notes. (line 21)
-* T s: Notes. (line 33)
-* T S: Notes. (line 44)
-* t t: Tagging. (line 13)
-* T T: Notes. (line 13)
-* TAB: Section visibility. (line 9)
-* u: Staging and unstaging.
- (line 40)
-* U: Staging and unstaging.
- (line 49)
-* v: Applying. (line 41)
-* V: Reverting. (line 6)
-* V A: Reverting. (line 30)
-* V a: Reverting. (line 38)
-* V s: Reverting. (line 34)
-* V V: Reverting. (line 14)
-* V v: Reverting. (line 20)
-* W: Creating and sending patches.
- (line 6)
-* w: Applying patches. (line 8)
-* w a: Applying patches. (line 31)
-* w m: Applying patches. (line 19)
-* W p: Creating and sending patches.
- (line 11)
-* W r: Creating and sending patches.
- (line 17)
-* w s: Applying patches. (line 27)
-* w w: Applying patches. (line 13)
-* w w <1>: Applying patches. (line 23)
-* x: Editing rebase sequences.
- (line 76)
-* x <1>: Resetting. (line 8)
-* Y: Logging. (line 62)
-* y: References buffer. (line 6)
-* y <1>: Editing rebase sequences.
- (line 85)
-* y c: References buffer. (line 19)
-* y o: References buffer. (line 24)
-* y y: References buffer. (line 14)
-* z: Stashing. (line 8)
-* z a: Stashing. (line 58)
-* z b: Stashing. (line 84)
-* z d: Stashing. (line 71)
-* z f: Stashing. (line 88)
-* z i: Stashing. (line 20)
-* z I: Stashing. (line 46)
-* z l: Stashing. (line 76)
-* z p: Stashing. (line 64)
-* z v: Stashing. (line 80)
-* z w: Stashing. (line 25)
-* z W: Stashing. (line 51)
-* z x: Stashing. (line 32)
-* z z: Stashing. (line 13)
-* z Z: Stashing. (line 39)
-
-\1f
-File: magit.info, Node: Command Index, Next: Function Index, Prev: Keystroke Index, Up: Top
-
-Appendix C Command Index
-************************
-
-\0\b[index\0\b]
-* Menu:
-
-* auto-revert-mode: Automatic Reverting of File-Visiting Buffers.
- (line 62)
-* forward-line: Editing rebase sequences.
- (line 39)
-* git-commit-ack: Editing commit messages.
- (line 128)
-* git-commit-cc: Editing commit messages.
- (line 144)
-* git-commit-next-message: Editing commit messages.
- (line 45)
-* git-commit-prev-message: Editing commit messages.
- (line 39)
-* git-commit-reported: Editing commit messages.
- (line 148)
-* git-commit-review: Editing commit messages.
- (line 132)
-* git-commit-save-message: Editing commit messages.
- (line 35)
-* git-commit-signoff: Editing commit messages.
- (line 136)
-* git-commit-suggested: Editing commit messages.
- (line 153)
-* git-commit-test: Editing commit messages.
- (line 140)
-* git-rebase-backward-line: Editing rebase sequences.
- (line 35)
-* git-rebase-edit: Editing rebase sequences.
- (line 55)
-* git-rebase-exec: Editing rebase sequences.
- (line 76)
-* git-rebase-fixup: Editing rebase sequences.
- (line 63)
-* git-rebase-insert: Editing rebase sequences.
- (line 85)
-* git-rebase-kill-line: Editing rebase sequences.
- (line 68)
-* git-rebase-move-line-down: Editing rebase sequences.
- (line 47)
-* git-rebase-move-line-up: Editing rebase sequences.
- (line 43)
-* git-rebase-pick: Editing rebase sequences.
- (line 72)
-* git-rebase-reword: Editing rebase sequences.
- (line 51)
-* git-rebase-show-commit: Editing rebase sequences.
- (line 16)
-* git-rebase-squash: Editing rebase sequences.
- (line 59)
-* git-rebase-undo: Editing rebase sequences.
- (line 89)
-* ido-enter-magit-status: Status buffer. (line 42)
-* magit-am-abort: Applying patches. (line 31)
-* magit-am-apply-maildir: Applying patches. (line 19)
-* magit-am-apply-patches: Applying patches. (line 13)
-* magit-am-continue: Applying patches. (line 23)
-* magit-am-popup: Applying patches. (line 8)
-* magit-am-skip: Applying patches. (line 27)
-* magit-apply: Applying. (line 33)
-* magit-bisect-bad: Bisecting. (line 31)
-* magit-bisect-good: Bisecting. (line 36)
-* magit-bisect-popup: Bisecting. (line 8)
-* magit-bisect-reset: Bisecting. (line 47)
-* magit-bisect-run: Bisecting. (line 24)
-* magit-bisect-skip: Bisecting. (line 41)
-* magit-bisect-start: Bisecting. (line 16)
-* magit-blame: Blaming. (line 8)
-* magit-blame-copy-hash: Blaming. (line 75)
-* magit-blame-next-chunk: Blaming. (line 54)
-* magit-blame-next-chunk-same-commit: Blaming. (line 58)
-* magit-blame-popup: Blaming. (line 24)
-* magit-blame-popup <1>: Minor mode for buffers visiting files.
- (line 39)
-* magit-blame-previous-chunk: Blaming. (line 62)
-* magit-blame-previous-chunk-same-commit: Blaming. (line 66)
-* magit-blame-quit: Blaming. (line 70)
-* magit-blame-toggle-headings: Blaming. (line 79)
-* magit-blob-next: Minor mode for buffers visiting blobs.
- (line 16)
-* magit-blob-previous: Minor mode for buffers visiting files.
- (line 45)
-* magit-blob-previous <1>: Minor mode for buffers visiting blobs.
- (line 12)
-* magit-branch: Branching. (line 190)
-* magit-branch-and-checkout: Branching. (line 200)
-* magit-branch-delete: Branching. (line 241)
-* magit-branch-popup: Branching. (line 45)
-* magit-branch-rename: Branching. (line 247)
-* magit-branch-reset: Branching. (line 224)
-* magit-branch-spinoff: Branching. (line 207)
-* magit-checkout: Branching. (line 182)
-* magit-checkout-file: Resetting. (line 37)
-* magit-cherry: Logging. (line 62)
-* magit-cherry-apply: Cherry picking. (line 22)
-* magit-cherry-pick: Cherry picking. (line 16)
-* magit-cherry-pick-popup: Cherry picking. (line 8)
-* magit-clone: Repository setup. (line 16)
-* magit-commit: Initiating a commit. (line 13)
-* magit-commit-amend: Initiating a commit. (line 18)
-* magit-commit-augment: Initiating a commit. (line 66)
-* magit-commit-extend: Initiating a commit. (line 22)
-* magit-commit-fixup: Initiating a commit. (line 42)
-* magit-commit-instant-fixup: Initiating a commit. (line 50)
-* magit-commit-instant-squash: Initiating a commit. (line 62)
-* magit-commit-popup: Initiating a commit. (line 8)
-* magit-commit-popup <1>: Minor mode for buffers visiting files.
- (line 49)
-* magit-commit-reword: Initiating a commit. (line 32)
-* magit-commit-squash: Initiating a commit. (line 54)
-* magit-copy-buffer-revision: Common commands. (line 21)
-* magit-copy-section-value: Common commands. (line 10)
-* magit-describe-section: Section types and values.
- (line 13)
-* magit-describe-section <1>: Matching sections. (line 6)
-* magit-diff: Diffing. (line 29)
-* magit-diff-default-context: Refreshing diffs. (line 62)
-* magit-diff-dwim: Diffing. (line 25)
-* magit-diff-flip-revs: Refreshing diffs. (line 45)
-* magit-diff-less-context: Refreshing diffs. (line 54)
-* magit-diff-more-context: Refreshing diffs. (line 58)
-* magit-diff-paths: Diffing. (line 59)
-* magit-diff-popup: Diffing. (line 20)
-* magit-diff-refresh: Refreshing diffs. (line 16)
-* magit-diff-refresh-popup: Refreshing diffs. (line 11)
-* magit-diff-save-default-arguments: Refreshing diffs. (line 28)
-* magit-diff-set-default-arguments: Refreshing diffs. (line 21)
-* magit-diff-show-or-scroll-down: Log Buffer. (line 37)
-* magit-diff-show-or-scroll-down <1>: Blaming. (line 44)
-* magit-diff-show-or-scroll-down <2>: Editing rebase sequences.
- (line 28)
-* magit-diff-show-or-scroll-up: Log Buffer. (line 27)
-* magit-diff-show-or-scroll-up <1>: Blaming. (line 34)
-* magit-diff-show-or-scroll-up <2>: Editing rebase sequences.
- (line 21)
-* magit-diff-staged: Diffing. (line 49)
-* magit-diff-switch-range-type: Refreshing diffs. (line 40)
-* magit-diff-toggle-refine-hunk: Refreshing diffs. (line 36)
-* magit-diff-unstaged: Diffing. (line 55)
-* magit-diff-visit-file: Diff buffer. (line 6)
-* magit-diff-visit-file-worktree: Diff buffer. (line 21)
-* magit-diff-while-committing: Refreshing diffs. (line 70)
-* magit-diff-while-committing <1>: Editing commit messages.
- (line 57)
-* magit-diff-worktree: Diffing. (line 43)
-* magit-discard: Applying. (line 37)
-* magit-dispatch-popup: Popup buffers and prefix commands.
- (line 20)
-* magit-ediff-compare: Ediffing. (line 23)
-* magit-ediff-dwim: Ediffing. (line 6)
-* magit-ediff-popup: Ediffing. (line 18)
-* magit-ediff-resolve: Ediffing. (line 32)
-* magit-ediff-show-commit: Ediffing. (line 62)
-* magit-ediff-show-staged: Ediffing. (line 54)
-* magit-ediff-show-unstaged: Ediffing. (line 50)
-* magit-ediff-show-working-tree: Ediffing. (line 58)
-* magit-ediff-stage: Ediffing. (line 45)
-* magit-fetch: Fetching. (line 24)
-* magit-fetch-all: Fetching. (line 28)
-* magit-fetch-from-pushremote: Fetching. (line 16)
-* magit-fetch-from-upstream: Fetching. (line 20)
-* magit-fetch-popup: Fetching. (line 11)
-* magit-file-popup: Minor mode for buffers visiting files.
- (line 19)
-* magit-find-file: Visiting blobs. (line 6)
-* magit-find-file-other-window: Visiting blobs. (line 11)
-* magit-format-patch: Creating and sending patches.
- (line 11)
-* magit-git-command: Running Git manually.
- (line 24)
-* magit-git-command-topdir: Running Git manually.
- (line 19)
-* magit-go-backward: Log Buffer. (line 19)
-* magit-go-backward <1>: Refreshing diffs. (line 80)
-* magit-go-forward: Log Buffer. (line 23)
-* magit-go-forward <1>: Refreshing diffs. (line 84)
-* magit-init: Repository setup. (line 6)
-* magit-jump-to-diffstat-or-diff: Diff buffer. (line 38)
-* magit-kill-this-buffer: Minor mode for buffers visiting blobs.
- (line 20)
-* magit-log: Logging. (line 37)
-* magit-log-all: Logging. (line 56)
-* magit-log-all-branches: Logging. (line 52)
-* magit-log-branches: Logging. (line 48)
-* magit-log-buffer-file: Logging. (line 67)
-* magit-log-buffer-file <1>: Minor mode for buffers visiting files.
- (line 33)
-* magit-log-bury-buffer: Log Buffer. (line 12)
-* magit-log-current: Logging. (line 31)
-* magit-log-double-commit-limit: Log Buffer. (line 53)
-* magit-log-half-commit-limit: Log Buffer. (line 57)
-* magit-log-head: Logging. (line 44)
-* magit-log-popup: Logging. (line 26)
-* magit-log-refresh: Refreshing logs. (line 16)
-* magit-log-refresh-popup: Refreshing logs. (line 11)
-* magit-log-refresh-popup <1>: Log Buffer. (line 6)
-* magit-log-save-default-arguments: Refreshing logs. (line 28)
-* magit-log-select-pick: Select from log. (line 14)
-* magit-log-select-quit: Select from log. (line 20)
-* magit-log-set-default-arguments: Refreshing logs. (line 21)
-* magit-log-toggle-commit-limit: Log Buffer. (line 47)
-* magit-merge: Merging. (line 16)
-* magit-merge <1>: Merging. (line 51)
-* magit-merge-abort: Merging. (line 56)
-* magit-merge-editmsg: Merging. (line 29)
-* magit-merge-nocommit: Merging. (line 36)
-* magit-merge-popup: Merging. (line 8)
-* magit-merge-preview: Merging. (line 43)
-* magit-mode-bury-buffer: Quitting Windows. (line 6)
-* magit-notes-edit: Notes. (line 13)
-* magit-notes-merge: Notes. (line 56)
-* magit-notes-merge-abort: Notes. (line 70)
-* magit-notes-merge-commit: Notes. (line 65)
-* magit-notes-popup: Notes. (line 8)
-* magit-notes-prune: Notes. (line 29)
-* magit-notes-remove: Notes. (line 21)
-* magit-notes-set-display-refs: Notes. (line 44)
-* magit-notes-set-ref: Notes. (line 33)
-* magit-patch-popup: Creating and sending patches.
- (line 6)
-* magit-pop-revision-stack: Editing commit messages.
- (line 63)
-* magit-process: Viewing Git output. (line 11)
-* magit-process-kill: Viewing Git output. (line 19)
-* magit-pull: Pulling. (line 24)
-* magit-pull-from-pushremote: Pulling. (line 16)
-* magit-pull-from-upstream: Pulling. (line 20)
-* magit-pull-popup: Pulling. (line 11)
-* magit-push: Pushing. (line 39)
-* magit-push-current: Pushing. (line 35)
-* magit-push-current-to-pushremote: Pushing. (line 16)
-* magit-push-current-to-upstream: Pushing. (line 26)
-* magit-push-implicitly args: Pushing. (line 64)
-* magit-push-matching: Pushing. (line 44)
-* magit-push-popup: Pushing. (line 11)
-* magit-push-tag: Pushing. (line 56)
-* magit-push-tags: Pushing. (line 50)
-* magit-push-to-remote remote args: Pushing. (line 75)
-* magit-rebase: Rebasing. (line 25)
-* magit-rebase-abort: Rebasing. (line 84)
-* magit-rebase-autosquash: Rebasing. (line 57)
-* magit-rebase-continue: Rebasing. (line 72)
-* magit-rebase-edit: Rebasing. (line 80)
-* magit-rebase-edit-commit: Rebasing. (line 61)
-* magit-rebase-interactive: Rebasing. (line 53)
-* magit-rebase-onto-pushremote: Rebasing. (line 16)
-* magit-rebase-onto-upstream: Rebasing. (line 21)
-* magit-rebase-popup: Rebasing. (line 8)
-* magit-rebase-reword-commit: Rebasing. (line 65)
-* magit-rebase-skip: Rebasing. (line 76)
-* magit-rebase-subset: Rebasing. (line 31)
-* magit-reflog-current: Reflog. (line 11)
-* magit-reflog-head: Reflog. (line 19)
-* magit-reflog-other: Reflog. (line 15)
-* magit-refresh: Automatic Refreshing of Magit Buffers.
- (line 22)
-* magit-refresh-all: Automatic Refreshing of Magit Buffers.
- (line 31)
-* magit-remote-add: Remotes. (line 13)
-* magit-remote-popup: Remotes. (line 8)
-* magit-remote-remove: Remotes. (line 28)
-* magit-remote-rename: Remotes. (line 18)
-* magit-remote-set-url: Remotes. (line 23)
-* magit-request-pull: Creating and sending patches.
- (line 17)
-* magit-reset: Resetting. (line 8)
-* magit-reset-hard: Resetting. (line 32)
-* magit-reset-head: Resetting. (line 21)
-* magit-reset-index: Staging and unstaging.
- (line 84)
-* magit-reset-index <1>: Resetting. (line 14)
-* magit-reset-soft: Resetting. (line 26)
-* magit-reverse: Applying. (line 41)
-* magit-reverse-in-index: Staging and unstaging.
- (line 59)
-* magit-revert: Reverting. (line 14)
-* magit-revert-no-commit: Reverting. (line 20)
-* magit-revert-popup: Reverting. (line 6)
-* magit-run-git-gui: Running Git manually.
- (line 59)
-* magit-run-gitk: Running Git manually.
- (line 47)
-* magit-run-gitk-all: Running Git manually.
- (line 51)
-* magit-run-gitk-branches: Running Git manually.
- (line 55)
-* magit-run-popup: Running Git manually.
- (line 12)
-* magit-section-backward: Section movement. (line 10)
-* magit-section-backward-siblings: Section movement. (line 20)
-* magit-section-cycle: Section visibility. (line 13)
-* magit-section-cycle-diffs: Section visibility. (line 17)
-* magit-section-cycle-global: Section visibility. (line 22)
-* magit-section-forward: Section movement. (line 16)
-* magit-section-forward-siblings: Section movement. (line 26)
-* magit-section-hide: Section visibility. (line 51)
-* magit-section-hide-children: Section visibility. (line 66)
-* magit-section-show: Section visibility. (line 47)
-* magit-section-show-children: Section visibility. (line 60)
-* magit-section-show-headings: Section visibility. (line 55)
-* magit-section-show-level-1: Section visibility. (line 26)
-* magit-section-show-level-1-all: Section visibility. (line 34)
-* magit-section-show-level-2: Section visibility. (line 27)
-* magit-section-show-level-2-all: Section visibility. (line 35)
-* magit-section-show-level-3: Section visibility. (line 28)
-* magit-section-show-level-3-all: Section visibility. (line 36)
-* magit-section-show-level-4: Section visibility. (line 29)
-* magit-section-show-level-4-all: Section visibility. (line 37)
-* magit-section-toggle: Section visibility. (line 9)
-* magit-section-toggle-children: Section visibility. (line 70)
-* magit-section-up: Section movement. (line 31)
-* magit-sequence-abort: Cherry picking. (line 43)
-* magit-sequence-abort <1>: Reverting. (line 38)
-* magit-sequence-continue: Cherry picking. (line 35)
-* magit-sequence-continue <1>: Reverting. (line 30)
-* magit-sequence-skip: Cherry picking. (line 39)
-* magit-sequence-skip <1>: Reverting. (line 34)
-* magit-shell-command: Running Git manually.
- (line 38)
-* magit-shell-command-topdir: Running Git manually.
- (line 33)
-* magit-show-commit: Diffing. (line 67)
-* magit-show-commit <1>: Blaming. (line 29)
-* magit-show-refs: References buffer. (line 24)
-* magit-show-refs-current: References buffer. (line 19)
-* magit-show-refs-head: References buffer. (line 14)
-* magit-show-refs-popup: References buffer. (line 6)
-* magit-snapshot: Stashing. (line 39)
-* magit-snapshot-index: Stashing. (line 46)
-* magit-snapshot-worktree: Stashing. (line 51)
-* magit-stage: Staging and unstaging.
- (line 29)
-* magit-stage-file: Staging from file-visiting buffers.
- (line 10)
-* magit-stage-file <1>: Minor mode for buffers visiting files.
- (line 24)
-* magit-stage-modified: Staging and unstaging.
- (line 33)
-* magit-stash: Stashing. (line 13)
-* magit-stash-apply: Stashing. (line 58)
-* magit-stash-branch: Stashing. (line 84)
-* magit-stash-clear: Stashing. (line 92)
-* magit-stash-drop: Stashing. (line 71)
-* magit-stash-format-patch: Stashing. (line 88)
-* magit-stash-index: Stashing. (line 20)
-* magit-stash-keep-index: Stashing. (line 32)
-* magit-stash-list: Stashing. (line 76)
-* magit-stash-pop: Stashing. (line 64)
-* magit-stash-popup: Stashing. (line 8)
-* magit-stash-show: Diffing. (line 72)
-* magit-stash-show <1>: Stashing. (line 80)
-* magit-stash-worktree: Stashing. (line 25)
-* magit-status: Status buffer. (line 22)
-* magit-submodule-add: Submodules. (line 13)
-* magit-submodule-fetch: Fetching. (line 32)
-* magit-submodule-fetch <1>: Submodules. (line 37)
-* magit-submodule-init: Submodules. (line 24)
-* magit-submodule-init <1>: Submodules. (line 41)
-* magit-submodule-popup: Submodules. (line 8)
-* magit-submodule-setup: Submodules. (line 19)
-* magit-submodule-sync: Submodules. (line 33)
-* magit-submodule-update: Submodules. (line 28)
-* magit-tag: Tagging. (line 13)
-* magit-tag-delete: Tagging. (line 18)
-* magit-tag-popup: Tagging. (line 8)
-* magit-tag-prune: Tagging. (line 24)
-* magit-toggle-buffer-lock: Modes and Buffers. (line 17)
-* magit-toggle-margin: Refreshing logs. (line 36)
-* magit-unstage: Staging and unstaging.
- (line 40)
-* magit-unstage-all: Staging and unstaging.
- (line 49)
-* magit-unstage-file: Staging from file-visiting buffers.
- (line 18)
-* magit-unstage-file <1>: Minor mode for buffers visiting files.
- (line 28)
-* magit-version: Git executable. (line 17)
-* magit-visit-ref: References buffer. (line 99)
-* magit-wip-commit: Wip modes. (line 129)
-* magit-wip-log: Wip modes. (line 69)
-* magit-wip-log-current: Wip modes. (line 77)
-* scroll-down: Diff buffer. (line 48)
-* scroll-up: Diff buffer. (line 44)
-* with-editor-cancel: Editing commit messages.
- (line 24)
-* with-editor-cancel <1>: Editing rebase sequences.
- (line 11)
-* with-editor-finish: Editing commit messages.
- (line 19)
-* with-editor-finish <1>: Editing rebase sequences.
- (line 6)
-
+++ /dev/null
-Authors
-=======
-
-The following people have contributed to Magit, including the
-libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el`
-which are distributed as separate Elpa packages.
-
-For statistics see https://magit.vc/stats/authors.html.
-
-Names below are sorted alphabetically.
-
-Author
-------
-
-- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-
-Maintainer
-----------
-
-- Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-Developers
-----------
-
-- Kyle Meyer <kyleNOSPAMkyleam.com>
-- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-
-Retired Maintainers and Developers
-----------------------------------
-
-- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-- Pieter Praet <pieterNOSPAMpraet.org>
-- Phil Jackson <philNOSPAMshellarchive.co.uk>
-- Rémi Vanicat <vanicatNOSPAMdebian.org>
-- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-
-Contributors
-------------
-
-- Aaron Culich <aculichNOSPAMgmail.com>
-- Abdo Roig-Maranges <abdo.roigNOSPAMgmail.com>
-- acple <silentsphere110NOSPAMgmail.com>
-- Adam Spiers <emacsNOSPAMadamspiers.org>
-- Adeodato Simó <datoNOSPAMnet.com.org.es>
-- Ævar Arnfjörð Bjarmason <avarabNOSPAMgmail.com>
-- Alan Falloon <alan.falloonNOSPAMgmail.com>
-- Alex Dunn <adunnNOSPAMucsb.edu>
-- Alexey Voinov <alexey.v.voinovNOSPAMgmail.com>
-- Alex Kost <alezostNOSPAMgmail.com>
-- Alex Ott <alexottNOSPAMgmail.com>
-- Andreas Fuchs <asfNOSPAMboinkor.net>
-- Andreas Liljeqvist <andreas.liljeqvistNOSPAMrobacks.se>
-- Andreas Rottmann <a.rottmannNOSPAMgmx.at>
-- Andrei Chițu <andrei.chitu1NOSPAMgmail.com>
-- Andrew Kirkpatrick <andrew.kirkpatrickNOSPAMadelaide.edu.au>
-- Andrew Schwartzmeyer <andrewNOSPAMschwartzmeyer.com>
-- Andrey Smirnov <andrew.smirnovNOSPAMgmail.com>
-- Andriy Kmit' <devNOSPAMmadand.net>
-- Andy Sawyer <gitNOSPAMpureabstract.org>
-- Barak A. Pearlmutter <barak+gitNOSPAMpearlmutter.net>
-- Bart Bakker <bartNOSPAMthesoftwarecraft.com>
-- Bastian Beischer <beischerNOSPAMphysik.rwth-aachen.de>
-- Ben Walton <bwaltonNOSPAMartsci.utoronto.ca>
-- Bradley Wright <bradNOSPAMintranation.com>
-- Brandon W Maister <quodlibetorNOSPAMgmail.com>
-- Brian Warner <warnerNOSPAMlothar.com>
-- Bryan Shell <bryan.shellNOSPAMorbitz.com>
-- Carl Lieberman <liebermancarlNOSPAMgmail.com>
-- Chris Bernard <cebernardNOSPAMgmail.com>
-- Chris Done <chrisdoneNOSPAMgmail.com>
-- Chris Moore <dooglusNOSPAMgmail.com>
-- Chris Ring <chrisNOSPAMringthis.com>
-- Christian Dietrich <christian.dietrichNOSPAMinformatik.uni-erlangen.de>
-- Christian Kluge <ckfrakturfreakNOSPAMweb.de>
-- Christopher Monsanto <chrisNOSPAMmonsan.to>
-- Cornelius Mika <cornelius.mikaNOSPAMgmail.com>
-- Craig Andera <canderaNOSPAMwangdera.com>
-- Dale Hagglund <dale.hagglundNOSPAMgmail.com>
-- Damien Cassou <damienNOSPAMcassou.me>
-- Dan Erikson <derikson3NOSPAMgmail.com>
-- Daniel Brockman <danielNOSPAMgointeractive.se>
-- Daniel Farina <drfarinaNOSPAMacm.org>
-- Daniel Hackney <danNOSPAMhaxney.org>
-- Dan LaManna <dan.lamannaNOSPAMgmail.com>
-- Dato Simó <datoNOSPAMnet.com.org.es>
-- David Abrahams <daveNOSPAMboostpro.com>
-- David Hull <david.hullNOSPAMopenx.com>
-- David L. Rager <ragerdlNOSPAMgmail.com>
-- David Wallin <david.wallinNOSPAMgmail.com>
-- Dennis Paskorz <dennisNOSPAMwalltowall.com>
-- Divye Kapoor <divyeNOSPAMgoogle.com>
-- Dominique Quatravaux <domqNOSPAMgoogle.com>
-- Eli Barzilay <eliNOSPAMbarzilay.org>
-- Eric Davis <edNOSPAMnpri.org>
-- Eric Schulte <schulte.ericNOSPAMgmail.com>
-- Evgkeni Sampelnikof <esabofNOSPAMgmail.com>
-- Felix Geller <fgeller@gmail.com>
-- Feng Li <fengliNOSPAMblackmagicdesign.com>
-- Florian Ragwitz <raflNOSPAMdebian.org>
-- Fritz Grabo <fritz.graboNOSPAMgmail.com>
-- Geoff Shannon <geoffpshannonNOSPAMgmail.com>
-- George Kadianakis <desnackedNOSPAMgmail.com>
-- Graham Clark <grclarkNOSPAMgmail.com>
-- Greg A. Woods <woodsNOSPAMplanix.com>
-- Greg Lucas <gregNOSPAMglucas.net>
-- Greg Sexton <gregsextonNOSPAMgmail.com>
-- Guillaume Martres <smarterNOSPAMubuntu.com>
-- Hannu Koivisto <azureNOSPAMiki.fi>
-- Hans-Peter Deifel <hpdeifelNOSPAMgmx.de>
-- Ian Eure <ian.eureNOSPAMgmail.com>
-- Ingo Lohmar <i.lohmarNOSPAMgmail.com>
-- Jan Tatarik <jan.tatarikNOSPAMxing.com>
-- Jasper St. Pierre <jstpierreNOSPAMmecheye.net>
-- Jeff Bellegarde <jbellegardeNOSPAMwhitepages.com>
-- Jeff Dairiki <dairikiNOSPAMdairiki.org>
-- Jesse Alama <jesse.alamaNOSPAMgmail.com>
-- Johann Klähn <kljohannNOSPAMgmail.com>
-- John Mastro <john.b.mastroNOSPAMgmail.com>
-- John Wiegley <johnwNOSPAMnewartisans.com>
-- Jonas Bernoulli <jonasNOSPAMbernoul.li>
-- Jonathan Roes <jroesNOSPAMjroes.net>
-- Jordan Greenberg <jordanNOSPAMsoftwareslave.com>
-- Josiah Schwab <jschwabNOSPAMgmail.com>
-- Julien Danjou <julienNOSPAMdanjou.info>
-- Justin Caratzas <justin.caratzasNOSPAMgmail.com>
-- Kan-Ru Chen <kanruNOSPAMkanru.info>
-- Kan-Ru Chen <kosterNOSPAMdebian.org>
-- Kimberly Wolk <kimwolkNOSPAMhotmail.com>
-- Kyle Meyer <kyleNOSPAMkyleam.com>
-- Laurent Laffont <laurent.laffontNOSPAMgmail.com>
-- Leandro Facchinetti <meNOSPAMleafac.com>
-- Lele Gaifax <leleNOSPAMmetapensiero.it>
-- Leo Liu <sdl.webNOSPAMgmail.com>
-- Leonardo Etcheverry <leoNOSPAMkalio.net>
-- Lingchao Xin <douglarekNOSPAMusers.noreply.github.com>
-- Lluís Vilanova <vilanovaNOSPAMac.upc.edu>
-- Loic Dachary <loicNOSPAMdachary.org>
-- Luís Oliveira <luismboNOSPAMgmail.com>
-- Luke Amdor <luke.amdorNOSPAMgmail.com>
-- Manuel Vázquez Acosta <mva.ledNOSPAMgmail.com>
-- Marcel Wolf <mwolfNOSPAMml1.net>
-- Marc Herbert <marc.herbertNOSPAMgmail.com>
-- Marcin Bachry <hegel666NOSPAMgmail.com>
-- Marco Craveiro <marco.craveiroNOSPAMgmail.com>
-- Marian Schubert <marian.schubertNOSPAMgooddata.com>
-- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-- Mark Hepburn <Mark.HepburnNOSPAMcsiro.au>
-- Mark Karpov <markkarpovNOSPAMopmbx.org>
-- Mark Oteiza <mvoteizaNOSPAMudel.edu>
-- Matus Goljer <dota.keysNOSPAMgmail.com>
-- Michael Fogleman <michaelwfoglemanNOSPAMgmail.com>
-- Michael Griffiths <mikeyNOSPAMcich.li>
-- Michael Heerdegen <michael_heerdegenNOSPAMweb.de>
-- Michal Sojka <sojkam1NOSPAMfel.cvut.cz>
-- Miles Bader <milesNOSPAMgnu.org>
-- Miloš Mošić <mosic.milosNOSPAMgmail.com>
-- Mitchel Humpherys <mitch.specialNOSPAMgmail.com>
-- Moritz Bunkus <moritzNOSPAMbunkus.org>
-- Natalie Weizenbaum <nex342NOSPAMgmail.com>
-- Nguyễn Tuấn Anh <ubolontonNOSPAMgmail.com>
-- Nic Ferier <nicNOSPAMferrier.me.uk>
-- Nick Alcock <nick.alcockNOSPAMoracle.com>
-- Nick Alexander <nalexanderNOSPAMmozilla.com>
-- Nick Dimiduk <ndimidukNOSPAMgmail.com>
-- Nicklas Lindgren <niliNOSPAMgulmohar.se>
-- Nicolas Dudebout <nicolas.dudebout@gatech.edu>
-- Nicolas Petton <nicolasNOSPAMpetton.fr>
-- Nicolas Richard <theonewiththeevillookNOSPAMyahoo.fr>
-- Nikolay Martynov <mar.kolyaNOSPAMgmail.com>
-- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-- Ole Arndt <oliver.arndtNOSPAMcegedim.com>
-- Oleh Krehel <ohwoeowhoNOSPAMgmail.com>
-- Óscar Fuentes <ofvNOSPAMwanadoo.es>
-- Paul Stadig <paulNOSPAMstadig.name>
-- Pavel Holejsovsky <pavel.holejsovskyNOSPAMupek.com>
-- Pekka Pessi <nospamNOSPAMpessi.fi>
-- Peter Eisentraut <peterNOSPAMeisentraut.org>
-- Peter Jaros <peter.a.jarosNOSPAMgmail.com>
-- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-- Peter Vasil <mailNOSPAMpetervasil.net>
-- Philippe Vaucher <philippe.vaucherNOSPAMgmail.com>
-- Philipp Haselwarter <philippNOSPAMhaselwarter.org>
-- Philip Weaver <philip.weaverNOSPAMgmail.com>
-- Phil Jackson <philNOSPAMshellarchive.co.uk>
-- Phil Sainty <philNOSPAMcatalyst.net.nz>
-- Pieter Praet <pieterNOSPAMpraet.org>
-- Prathamesh Sonpatki <csonpatkiNOSPAMgmail.com>
-- rabio <rabiodevNOSPAMo2.pl>
-- Rafael Laboissiere <rafaelNOSPAMlaboissiere.net>
-- Raimon Grau <raimonNOSPAM3scale.net>
-- Ramkumar Ramachandra <artagnonNOSPAMgmail.com>
-- Remco van 't Veer <rwvtveerNOSPAMxs4all.nl>
-- Rémi Vanicat <vanicatNOSPAMdebian.org>
-- René Stadler <mailNOSPAMrenestadler.de>
-- Richard Kim <emacs18NOSPAMgmail.com>
-- Robert Boone <robo4288NOSPAMgmail.com>
-- Robin Green <greenrdNOSPAMgreenrd.org>
-- Roger Crew <crewNOSPAMcs.stanford.edu>
-- Romain Francoise <romainNOSPAMorebokech.com>
-- Ron Parker <rparkerNOSPAMa123systems.com>
-- Roy Crihfield <rscrihfNOSPAMgmail.com>
-- Rüdiger Sonderfeld <ruedigerNOSPAMc-plusplus.net>
-- Russell Black <black.russellNOSPAMgmail.com>
-- Ryan C. Thompson <rctNOSPAMthompsonclan.org>
-- Samuel Bronson <naestenNOSPAMgmail.com>
-- Sanjoy Das <sanjoyNOSPAMplayingwithpointers.com>
-- Sean Bryant <sbryantNOSPAMhackinggibsons.com>
-- Sebastian Wiesner <lunaryornNOSPAMgmail.com>
-- Sébastien Gross <sebNOSPAMchezwam.org>
-- Seong-Kook Shin <cinskyNOSPAMgmail.com>
-- Sergey Pashinin <sergeyNOSPAMpashinin.com>
-- Sergey Vinokurov <serg.fooNOSPAMgmail.com>
-- Servilio Afre Puentes <afrepuesNOSPAMmcmaster.ca>
-- Štěpán Němec <stepnemNOSPAMgmail.com>
-- Steven Chow <steveNOSPAMmyfreestuffapp.com>
-- Steven E. Harris <sehNOSPAMpanix.com>
-- Steven Thomas <sthomas314NOSPAMgmail.com>
-- Steven Vancoillie <steven.vancoillieNOSPAMrunbox.com>
-- Steve Purcell <steveNOSPAMsanityinc.com>
-- Suhail Shergill <suhailshergillNOSPAMgmail.com>
-- Sylvain Rousseau <thisirsNOSPAMgmail.com>
-- Syohei Yoshida <syohexNOSPAMgmail.com>
-- Takafumi Arakaki <aka.tkfNOSPAMgmail.com>
-- Teemu Likonen <tlikonenNOSPAMiki.fi>
-- Teruki Shigitani <teruki.shigitaniNOSPAMgmail.com>
-- Thierry Volpiatto <thierry.volpiattoNOSPAMgmail.com>
-- Thomas A Caswell <tcaswellNOSPAMgmail.com>
-- Thomas Frössman <thomasfNOSPAMjossystem.se>
-- Thomas Jost <thomas.jostNOSPAMgmail.com>
-- Thomas Riccardi <riccardi.thomasNOSPAMgmail.com>
-- Tibor Simko <tibor.simkoNOSPAMcern.ch>
-- Timo Juhani Lindfors <timo.lindforsNOSPAMiki.fi>
-- Tim Perkins <tprk77NOSPAMgmail.com>
-- Tim Wraight <timNOSPAMwraight.net>
-- Ting-Yu Lin <aethanycNOSPAMgmail.com>
-- Tom Feist <shabbleNOSPAMmetavore.org>
-- Vineet Naik <vineetNOSPAMhelpshift.com>
-- Wei Huang <weihNOSPAMopera.com>
-- Wilfred Hughes <meNOSPAMwilfred.me.uk>
-- Win Treese <treeseNOSPAMacm.org>
-- Xavier Noria <fxnNOSPAMhashref.com>
-- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-- York Zhao <gtdplatformNOSPAMgmail.com>
-- Yuichi Higashi <aaa707bNOSPAMgmail.com>
-- Zach Latta <zachNOSPAMzachlatta.com>
+++ /dev/null
-
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- <program> Copyright (C) <year> <name of author>
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-<http://www.gnu.org/licenses/>.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-
+++ /dev/null
-This is the file .../info/dir, which contains the
-topmost node of the Info hierarchy, called (dir)Top.
-The first time you invoke Info you start off looking at this node.
-\1f
-File: dir, Node: Top This is the top of the INFO tree
-
- This (the Directory node) gives a menu of major topics.
- Typing "q" exits, "?" lists all Info commands, "d" returns here,
- "h" gives a primer for first-timers,
- "mEmacs<Return>" visits the Emacs manual, etc.
-
- In Emacs, you can click mouse button 2 on a menu item or cross reference
- to select it.
-
-* Menu:
-
-Emacs
-* Magit: (magit). Using Git from Emacs with Magit.
+++ /dev/null
-;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Phil Jackson <philNOSPAMshellarchive.co.uk>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; This file is not part of GNU Emacs.
-
-;; This file is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-
-;; This file is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this file. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This package assists the user in editing the list of commits to be
-;; rewritten during an interactive rebase.
-
-;; When the user initiates an interactive rebase, e.g. using "r e" in
-;; a Magit buffer or on the command line using "git rebase -i REV",
-;; Git invokes the `$GIT_SEQUENCE_EDITOR' (or if that is undefined
-;; `$GIT_EDITOR' or even `$EDITOR') letting the user rearrange, drop,
-;; reword, edit, and squash commits.
-
-;; This package provides the major-mode `git-rebase-mode' which makes
-;; doing so much more fun, by making the buffer more colorful and
-;; providing the following commands:
-;;
-;; C-c C-c Tell Git to make it happen.
-;; C-c C-k Tell Git that you changed your mind, i.e. abort.
-;;
-;; p Move point to previous line.
-;; n Move point to next line.
-;;
-;; M-p Move the commit at point up.
-;; M-n Move the commit at point down.
-;;
-;; k Drop the commit at point.
-;; c Don't drop the commit at point.
-;; r Change the message of the commit at point.
-;; e Edit the commit at point.
-;; s Squash the commit at point, into the one above.
-;; f Like "s" but don't also edit the commit message.
-;; x Add a script to be run with the commit at point
-;; being checked out.
-;;
-;; RET Show the commit at point in another buffer.
-;; C-/ Undo last change.
-
-;; You should probably also read the `git-rebase' manpage.
-
-;;; Code:
-
-(require 'dash)
-(require 'easymenu)
-(require 'server)
-(require 'with-editor)
-(require 'magit)
-
-(and (require 'async-bytecomp nil t)
- (memq 'magit (bound-and-true-p async-bytecomp-allowed-packages))
- (fboundp 'async-bytecomp-package-mode)
- (async-bytecomp-package-mode 1))
-
-(eval-when-compile (require 'recentf))
-
-;;; Options
-;;;; Variables
-
-(defgroup git-rebase nil
- "Edit Git rebase sequences."
- :group 'tools)
-
-(defcustom git-rebase-auto-advance t
- "Whether to move to next line after changing a line."
- :group 'git-rebase
- :type 'boolean)
-
-(defcustom git-rebase-show-instructions t
- "Whether to show usage instructions inside the rebase buffer."
- :group 'git-rebase
- :type 'boolean)
-
-(defcustom git-rebase-confirm-cancel t
- "Whether confirmation is required to cancel."
- :group 'git-rebase
- :type 'boolean)
-
-;;;; Faces
-
-(defgroup git-rebase-faces nil
- "Faces used by Git-Rebase mode."
- :group 'faces
- :group 'git-rebase)
-
-(defface git-rebase-hash
- '((((class color) (background light)) :foreground "grey60")
- (((class color) (background dark)) :foreground "grey40"))
- "Face for commit hashes."
- :group 'git-rebase-faces)
-
-(defface git-rebase-description nil
- "Face for commit descriptions."
- :group 'git-rebase-faces)
-
-(defface git-rebase-killed-action
- '((t (:inherit font-lock-comment-face :strike-through t)))
- "Face for commented action and exec lines."
- :group 'git-rebase-faces)
-
-;;; Keymaps
-
-(defvar git-rebase-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map special-mode-map)
- (define-key map (kbd "q") 'undefined)
- (define-key map [remap undo] 'git-rebase-undo)
- (define-key map (kbd "RET") 'git-rebase-show-commit)
- (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up)
- (define-key map (kbd "x") 'git-rebase-exec)
- (define-key map (kbd "c") 'git-rebase-pick)
- (define-key map (kbd "r") 'git-rebase-reword)
- (define-key map (kbd "w") 'git-rebase-reword)
- (define-key map (kbd "e") 'git-rebase-edit)
- (define-key map (kbd "s") 'git-rebase-squash)
- (define-key map (kbd "f") 'git-rebase-fixup)
- (define-key map (kbd "y") 'git-rebase-insert)
- (define-key map (kbd "k") 'git-rebase-kill-line)
- (define-key map (kbd "C-k") 'git-rebase-kill-line)
- (define-key map (kbd "p") 'git-rebase-backward-line)
- (define-key map (kbd "n") 'forward-line)
- (define-key map (kbd "M-p") 'git-rebase-move-line-up)
- (define-key map (kbd "M-n") 'git-rebase-move-line-down)
- (define-key map (kbd "M-<up>") 'git-rebase-move-line-up)
- (define-key map (kbd "M-<down>") 'git-rebase-move-line-down)
- (define-key map (kbd "C-x C-t") 'git-rebase-move-line-up)
- map)
- "Keymap for Git-Rebase mode.")
-
-(put 'git-rebase-reword :advertised-binding "r")
-(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p"))
-
-(easy-menu-define git-rebase-mode-menu git-rebase-mode-map
- "Git-Rebase mode menu"
- '("Rebase"
- ["Pick" git-rebase-pick t]
- ["Reword" git-rebase-reword t]
- ["Edit" git-rebase-edit t]
- ["Squash" git-rebase-squash t]
- ["Fixup" git-rebase-fixup t]
- ["Kill" git-rebase-kill-line t]
- ["Execute" git-rebase-exec t]
- ["Move Down" git-rebase-move-line-down t]
- ["Move Up" git-rebase-move-line-up t]
- "---"
- ["Cancel" with-editor-cancel t]
- ["Finish" with-editor-finish t]))
-
-(defvar git-rebase-command-descriptions
- '((with-editor-finish . "tell Git to make it happen")
- (with-editor-cancel . "tell Git that you changed your mind, i.e. abort")
- (previous-line . "move point to previous line")
- (next-line . "move point to next line")
- (git-rebase-move-line-up . "move the commit at point up")
- (git-rebase-move-line-down . "move the commit at point down")
- (git-rebase-show-commit . "show the commit at point in another buffer")
- (undo . "undo last change")
- (git-rebase-kill-line . "drop the commit at point")))
-
-;;; Commands
-
-(defun git-rebase-pick ()
- "Use commit on current line."
- (interactive)
- (git-rebase-set-action "pick"))
-
-(defun git-rebase-reword ()
- "Edit message of commit on current line."
- (interactive)
- (git-rebase-set-action "reword"))
-
-(defun git-rebase-edit ()
- "Stop at the commit on the current line."
- (interactive)
- (git-rebase-set-action "edit"))
-
-(defun git-rebase-squash ()
- "Meld commit on current line into previous commit, edit message."
- (interactive)
- (git-rebase-set-action "squash"))
-
-(defun git-rebase-fixup ()
- "Meld commit on current line into previous commit, discard its message."
- (interactive)
- (git-rebase-set-action "fixup"))
-
-(defconst git-rebase-line
- "^\\(#?\\(?:[fprse]\\|pick\\|reword\\|edit\\|squash\\|fixup\\|exec\\)\\) \
-\\(?:\\([^ \n]+\\) \\(.*\\)\\)?")
-
-(defun git-rebase-set-action (action)
- (goto-char (line-beginning-position))
- (if (and (looking-at git-rebase-line)
- (not (string-match-p "\\(e\\|exec\\)$" (match-string 1))))
- (let ((inhibit-read-only t))
- (replace-match action t t nil 1)
- (when git-rebase-auto-advance
- (forward-line)))
- (ding)))
-
-(defun git-rebase-line-p (&optional pos)
- (save-excursion
- (when pos (goto-char pos))
- (goto-char (line-beginning-position))
- (looking-at-p git-rebase-line)))
-
-(defun git-rebase-region-bounds ()
- (when (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))))))
-
-(defun git-rebase-move-line-down (n)
- "Move the current commit (or command) N lines down.
-If N is negative, move the commit up instead. With an active
-region, move all the lines that the region touches, not just the
-current line."
- (interactive "p")
- (-let* (((beg end) (or (git-rebase-region-bounds)
- (list (line-beginning-position)
- (1+ (line-end-position)))))
- (pt-offset (- (point) beg))
- (mark-offset (and mark-active (- (mark) beg))))
- (save-restriction
- (narrow-to-region
- (point-min)
- (1+ (save-excursion
- (goto-char (point-min))
- (while (re-search-forward git-rebase-line nil t))
- (point))))
- (if (or (and (< n 0) (= beg (point-min)))
- (and (> n 0) (= end (point-max)))
- (> end (point-max)))
- (ding)
- (goto-char (if (< n 0) beg end))
- (forward-line n)
- (atomic-change-group
- (let ((inhibit-read-only t))
- (insert (delete-and-extract-region beg end)))
- (let ((new-beg (- (point) (- end beg))))
- (when (use-region-p)
- (setq deactivate-mark nil)
- (set-mark (+ new-beg mark-offset)))
- (goto-char (+ new-beg pt-offset))))))))
-
-(defun git-rebase-move-line-up (n)
- "Move the current commit (or command) N lines up.
-If N is negative, move the commit down instead. With an active
-region, move all the lines that the region touches, not just the
-current line."
- (interactive "p")
- (git-rebase-move-line-down (- n)))
-
-(defun git-rebase-highlight-region (start end window rol)
- (let ((inhibit-read-only t)
- (deactivate-mark nil)
- (bounds (git-rebase-region-bounds)))
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (when bounds
- (magit-section-make-overlay (car bounds) (cadr bounds)
- 'magit-section-heading-selection))
- (if (and bounds (not magit-keep-region-overlay))
- (funcall (default-value 'redisplay-unhighlight-region-function) rol)
- (funcall (default-value 'redisplay-highlight-region-function)
- start end window rol))))
-
-(defun git-rebase-unhighlight-region (rol)
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (funcall (default-value 'redisplay-unhighlight-region-function) rol))
-
-(defun git-rebase-kill-line ()
- "Kill the current action line."
- (interactive)
- (goto-char (line-beginning-position))
- (when (and (looking-at git-rebase-line)
- (not (eq (char-after) ?#)))
- (let ((inhibit-read-only t))
- (insert ?#))
- (when git-rebase-auto-advance
- (forward-line))))
-
-(defun git-rebase-insert (rev)
- "Read an arbitrary commit and insert it below current line."
- (interactive (list (magit-read-branch-or-commit "Insert revision")))
- (forward-line)
- (--if-let (magit-rev-format "%h %s" rev)
- (let ((inhibit-read-only t))
- (insert "pick " it ?\n))
- (user-error "Unknown revision")))
-
-(defun git-rebase-exec (arg)
- "Insert a shell command to be run after the proceeding commit.
-
-If there already is such a command on the current line, then edit
-that instead. With a prefix argument insert a new command even
-when there already is one on the current line. With empty input
-remove the command on the current line, if any."
- (interactive "P")
- (let ((inhibit-read-only t) initial command)
- (unless arg
- (goto-char (line-beginning-position))
- (when (looking-at "^#?\\(e\\|exec\\) \\(.*\\)")
- (setq initial (match-string-no-properties 2))))
- (setq command (read-shell-command "Execute: " initial))
- (pcase (list command initial)
- (`("" nil) (ding))
- (`("" ,_)
- (delete-region (match-beginning 0) (1+ (match-end 0))))
- (`(,_ nil)
- (forward-line)
- (insert (concat "exec " command "\n"))
- (unless git-rebase-auto-advance
- (forward-line -1)))
- (_
- (replace-match (concat "exec " command) t t)
- (if git-rebase-auto-advance
- (forward-line)
- (goto-char (line-beginning-position)))))))
-
-(defun git-rebase-undo (&optional arg)
- "Undo some previous changes.
-Like `undo' but works in read-only buffers."
- (interactive "P")
- (let ((inhibit-read-only t))
- (undo arg)))
-
-(defun git-rebase-show-commit ()
- "Show the commit on the current line if any."
- (interactive)
- (save-excursion
- (goto-char (line-beginning-position))
- (--if-let (and (looking-at git-rebase-line)
- (match-string 2))
- (apply #'magit-show-commit it (magit-diff-arguments))
- (ding))))
-
-(defun git-rebase-backward-line (&optional n)
- "Move N lines backward (forward if N is negative).
-Like `forward-line' but go into the opposite direction."
- (interactive "p")
- (forward-line (- n)))
-
-;;; Mode
-
-;;;###autoload
-(define-derived-mode git-rebase-mode special-mode "Git Rebase"
- "Major mode for editing of a Git rebase file.
-
-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."
- :group 'git-rebase
- (setq font-lock-defaults '(git-rebase-mode-font-lock-keywords t t))
- (unless git-rebase-show-instructions
- (let ((inhibit-read-only t))
- (flush-lines "^\\($\\|#\\)")))
- (with-editor-mode 1)
- (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)
- (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)
- (when (boundp 'save-place)
- (setq save-place nil)))
-
-(defun git-rebase-cancel-confirm (force)
- (or (not (buffer-modified-p)) force (y-or-n-p "Abort this rebase? ")))
-
-(defun git-rebase-autostash-save ()
- (--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash"))
- (push (cons 'stash it) with-editor-cancel-alist)))
-
-(defun git-rebase-autostash-apply ()
- (--when-let (cdr (assq 'stash with-editor-cancel-alist))
- (magit-stash-apply it)))
-
-(defconst git-rebase-mode-font-lock-keywords
- `(("^\\([efprs]\\|pick\\|reword\\|edit\\|squash\\|fixup\\) \\([^ \n]+\\) \\(.*\\)"
- (1 'font-lock-keyword-face)
- (2 'git-rebase-hash)
- (3 'git-rebase-description))
- ("^\\(exec\\) \\(.*\\)"
- (1 'font-lock-keyword-face)
- (2 'git-rebase-description))
- ("^#.*" 0 'font-lock-comment-face)
- ("^#[^ \n].*" 0 'git-rebase-killed-action t))
- "Font lock keywords for Git-Rebase mode.")
-
-(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."
- (let ((inhibit-read-only t))
- (save-excursion
- (goto-char (point-min))
- (when (and git-rebase-show-instructions
- (re-search-forward "^# Commands:\n" nil t))
- (--each git-rebase-command-descriptions
- (insert (format "# %-8s %s\n"
- (substitute-command-keys (format "\\[%s]" (car it)))
- (cdr it))))
- (while (re-search-forward "^#\\( ?\\)\\([^,],\\) \\([^ ]+\\) = " nil t)
- (let ((cmd (intern (concat "git-rebase-" (match-string 3)))))
- (if (not (fboundp cmd))
- (delete-region (line-beginning-position) (1+ (line-end-position)))
- (replace-match " " t t nil 1)
- (replace-match
- (format "%-8s"
- (mapconcat #'key-description
- (--filter (not (eq (elt it 0) 'menu-bar))
- (reverse (where-is-internal cmd)))
- ", "))
- t t nil 2))))))))
-
-(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t)
-
-(defun git-rebase-mode-disable-before-save-hook ()
- (set (make-local-variable 'before-save-hook) nil))
-
-(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook)
-
-;;;###autoload
-(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
-;;;###autoload
-(add-to-list 'auto-mode-alist
- (cons git-rebase-filename-regexp 'git-rebase-mode))
-
-(add-to-list 'with-editor-server-window-alist
- (cons git-rebase-filename-regexp 'switch-to-buffer))
-
-(eval-after-load 'recentf
- '(add-to-list 'recentf-exclude git-rebase-filename-regexp))
-
-(provide 'git-rebase)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; git-rebase.el ends here
+++ /dev/null
-;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements commands for applying Git diffs or parts
-;; of such a diff. The supported "apply variants" are apply, stage,
-;; unstage, discard, and reverse - more than Git itself knows about,
-;; at least at the porcelain level.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-diff)
-(require 'magit-wip)
-
-;; For `magit-apply'
-(declare-function magit-am-popup 'magit-sequence)
-;; For `magit-discard-files'
-(declare-function magit-checkout-stage 'magit)
-(declare-function magit-checkout-read-stage 'magit)
-(defvar auto-revert-verbose)
-
-(require 'dired)
-
-;;; Options
-
-(defcustom magit-delete-by-moving-to-trash t
- "Whether Magit uses the system's trash can."
- :package-version '(magit . "2.1.0")
- :group 'magit
- :type 'boolean)
-
-(defcustom magit-unstage-committed t
- "Whether unstaging a committed change reverts it instead.
-
-A committed change cannot be unstaged, because staging and
-unstaging are actions that are concerned with the differences
-between the index and the working tree, not with committed
-changes.
-
-If this option is non-nil (the default), then typing \"u\"
-(`magit-unstage') on a committed change, causes it to be
-reversed in the index but not the working tree. For more
-information see command `magit-reverse-in-index'."
- :package-version '(magit . "2.4.1")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-reverse-atomically nil
- "Whether to reverse changes atomically.
-
-If some changes can be reversed while others cannot, then nothing
-is reversed if the value of this option is non-nil. But when it
-is nil, then the changes that can be reversed are reversed and
-for the other changes diff files are created that contain the
-rejected reversals."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Commands
-;;;; Apply
-
-(defun magit-apply (&rest args)
- "Apply the change at point to the working tree.
-With a prefix argument fallback to a 3-way merge. Doing
-so causes the change to be applied to the index as well."
- (interactive (and current-prefix-arg (list "--3way")))
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(,(or `unstaged `staged) ,_)
- (user-error "Change is already in the working tree"))
- (`(untracked ,(or `file `files))
- (magit-am-popup))
- (`(,_ region) (magit-apply-region it args))
- (`(,_ hunk) (magit-apply-hunk it args))
- (`(,_ hunks) (magit-apply-hunks it args))
- (`(,_ file) (magit-apply-diff it args))
- (`(,_ files) (magit-apply-diffs it args)))))
-
-(defun magit-apply--section-content (section)
- (buffer-substring-no-properties (if (eq (magit-section-type section) 'hunk)
- (magit-section-start section)
- (magit-section-content section))
- (magit-section-end section)))
-
-(defun magit-apply-diffs (sections &rest args)
- (setq sections (magit-apply--get-diffs sections))
- (magit-apply-patch sections args
- (mapconcat
- (lambda (s)
- (concat (magit-diff-file-header s)
- (magit-apply--section-content s)))
- sections "")))
-
-(defun magit-apply-diff (section &rest args)
- (setq section (car (magit-apply--get-diffs (list section))))
- (magit-apply-patch section args
- (concat (magit-diff-file-header section)
- (magit-apply--section-content section))))
-
-(defun magit-apply-hunks (sections &rest args)
- (let ((section (magit-section-parent (car sections))))
- (when (string-match "^diff --cc" (magit-section-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch section args
- (concat (magit-section-diff-header section)
- (mapconcat 'magit-apply--section-content
- sections "")))))
-
-(defun magit-apply-hunk (section &rest args)
- (when (string-match "^diff --cc" (magit-section-parent-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch (magit-section-parent section) args
- (concat (magit-diff-file-header section)
- (magit-apply--section-content section))))
-
-(defun magit-apply-region (section &rest args)
- (unless (magit-diff-context-p)
- (user-error "Not enough context to apply region. Increase the context"))
- (when (string-match "^diff --cc" (magit-section-parent-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch (magit-section-parent section) args
- (concat (magit-diff-file-header section)
- (magit-diff-hunk-region-patch section args))))
-
-(defun magit-apply-patch (section:s args patch)
- (let* ((files (if (atom section:s)
- (list (magit-section-value section:s))
- (mapcar 'magit-section-value section:s)))
- (command (symbol-name this-command))
- (command (if (and command (string-match "^magit-\\([^-]+\\)" command))
- (match-string 1 command)
- "apply")))
- (when (and magit-wip-before-change-mode (not inhibit-magit-refresh))
- (magit-wip-commit-before-change files (concat " before " command)))
- (with-temp-buffer
- (insert patch)
- (magit-run-git-with-input
- "apply" args "-p0"
- (unless (magit-diff-context-p) "--unidiff-zero")
- "--ignore-space-change" "-"))
- (unless inhibit-magit-refresh
- (when magit-wip-after-apply-mode
- (magit-wip-commit-after-apply files (concat " after " command)))
- (magit-refresh))))
-
-(defun magit-apply--get-selection ()
- (or (magit-region-sections 'hunk 'file)
- (let ((section (magit-current-section)))
- (pcase (magit-section-type section)
- ((or `hunk `file) section)
- ((or `staged `unstaged `untracked
- `stashed-index `stashed-worktree `stashed-untracked)
- (magit-section-children section))
- (_ (user-error "Cannot apply this, it's not a change"))))))
-
-(defun magit-apply--get-diffs (sections)
- (magit-section-case
- ([file diffstat]
- (--map (or (magit-get-section
- (append `((file . ,(magit-section-value it)))
- (magit-section-ident magit-root-section)))
- (error "Cannot get required diff headers"))
- sections))
- (t sections)))
-
-;;;; Stage
-
-(defun magit-stage (&optional intent)
- "Add the change at point to the staging area.
-With a prefix argument, INTENT, and an untracked file (or files)
-at point, stage the file but not its content."
- (interactive "P")
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(untracked ,_) (magit-stage-untracked intent))
- (`(unstaged region) (magit-apply-region it "--cached"))
- (`(unstaged hunk) (magit-apply-hunk it "--cached"))
- (`(unstaged hunks) (magit-apply-hunks it "--cached"))
- (`(unstaged file) (magit-stage-1 "-u" (list (magit-section-value it))))
- (`(unstaged files) (magit-stage-1 "-u" (magit-region-values)))
- (`(unstaged list) (magit-stage-1 "-u"))
- (`(staged ,_) (user-error "Already staged"))
- (`(committed ,_) (user-error "Cannot stage committed changes"))
- (`(undefined ,_) (user-error "Cannot stage this change")))))
-
-;;;###autoload
-(defun magit-stage-file (file)
- "Stage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be staged. Otherwise stage the file at point without
-requiring confirmation."
- (interactive
- (let* ((atpoint (magit-section-when (file)))
- (current (magit-file-relative-name))
- (choices (nconc (magit-modified-files)
- (magit-untracked-files)))
- (default (car (member (or atpoint current) choices))))
- (list (if (or current-prefix-arg (not default))
- (magit-completing-read "Stage file" choices
- nil t nil nil default)
- default))))
- (magit-with-toplevel
- (magit-stage-1 nil (list file))))
-
-;;;###autoload
-(defun magit-stage-modified (&optional all)
- "Stage all changes to files modified in the worktree.
-Stage all new content of tracked files and remove tracked files
-that no longer exist in the working tree from the index also.
-With a prefix argument also stage previously untracked (but not
-ignored) files.
-\('git add --update|--all .')."
- (interactive (progn (unless (or (not (magit-anything-staged-p))
- (magit-confirm 'stage-all-changes))
- (user-error "Abort"))
- (list current-prefix-arg)))
- (magit-with-toplevel
- (magit-stage-1 (if all "--all" "-u"))))
-
-(defun magit-stage-1 (arg &optional files)
- (magit-wip-commit-before-change files " before stage")
- (magit-run-git "add" arg (if files (cons "--" files) "."))
- (when magit-auto-revert-mode
- (mapc #'magit-turn-on-auto-revert-mode-if-desired files))
- (magit-wip-commit-after-apply files " after stage"))
-
-(defun magit-stage-untracked (&optional intent)
- (let* ((section (magit-current-section))
- (files (pcase (magit-diff-scope)
- (`file (list (magit-section-value section)))
- (`files (magit-region-values))
- (`list (magit-untracked-files))))
- plain repos)
- (dolist (file files)
- (if (magit-git-repo-p file t)
- (push file repos)
- (push file plain)))
- (magit-wip-commit-before-change files " before stage")
- (when plain
- (magit-run-git "add" (and intent "--intent-to-add")
- "--" plain)
- (when magit-auto-revert-mode
- (mapc #'magit-turn-on-auto-revert-mode-if-desired plain)))
- (dolist (repo repos)
- (save-excursion
- (goto-char (magit-section-start
- (magit-get-section
- `((file . ,repo) (untracked) (status)))))
- (call-interactively 'magit-submodule-add)))
- (magit-wip-commit-after-apply files " after stage")))
-
-;;;; Unstage
-
-(defun magit-unstage ()
- "Remove the change at point from the staging area."
- (interactive)
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(untracked ,_) (user-error "Cannot unstage untracked changes"))
- (`(unstaged ,_) (user-error "Already unstaged"))
- (`(staged region) (magit-apply-region it "--reverse" "--cached"))
- (`(staged hunk) (magit-apply-hunk it "--reverse" "--cached"))
- (`(staged hunks) (magit-apply-hunks it "--reverse" "--cached"))
- (`(staged file) (magit-unstage-1 (list (magit-section-value it))))
- (`(staged files) (magit-unstage-1 (magit-region-values)))
- (`(staged list) (magit-unstage-all))
- (`(committed ,_) (if magit-unstage-committed
- (magit-reverse-in-index)
- (user-error "Cannot unstage committed changes")))
- (`(undefined ,_) (user-error "Cannot unstage this change")))))
-
-;;;###autoload
-(defun magit-unstage-file (file)
- "Unstage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be unstaged. Otherwise unstage the file at point
-without requiring confirmation."
- (interactive
- (let* ((atpoint (magit-section-when (file)))
- (current (magit-file-relative-name))
- (choices (magit-staged-files))
- (default (car (member (or atpoint current) choices))))
- (list (if (or current-prefix-arg (not default))
- (magit-completing-read "Unstage file" choices
- nil t nil nil default)
- default))))
- (magit-with-toplevel
- (magit-unstage-1 (list file))))
-
-(defun magit-unstage-1 (files)
- (magit-wip-commit-before-change files " before unstage")
- (if (magit-no-commit-p)
- (magit-run-git "rm" "--cached" "--" files)
- (magit-run-git "reset" "HEAD" "--" files))
- (magit-wip-commit-after-apply files " after unstage"))
-
-;;;###autoload
-(defun magit-unstage-all ()
- "Remove all changes from the staging area."
- (interactive)
- (when (or (and (not (magit-anything-unstaged-p))
- (not (magit-untracked-files)))
- (magit-confirm 'unstage-all-changes))
- (magit-wip-commit-before-change nil " before unstage")
- (magit-run-git "reset" "HEAD" "--")
- (magit-wip-commit-after-apply nil " after unstage")))
-
-;;;; Discard
-
-(defun magit-discard ()
- "Remove the change at point."
- (interactive)
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(committed ,_) (user-error "Cannot discard committed changes"))
- (`(undefined ,_) (user-error "Cannot discard this change"))
- (`(,_ region) (magit-discard-region it))
- (`(,_ hunk) (magit-discard-hunk it))
- (`(,_ hunks) (magit-discard-hunks it))
- (`(,_ file) (magit-discard-file it))
- (`(,_ files) (magit-discard-files it))
- (`(,_ list) (magit-discard-files it)))))
-
-(defun magit-discard-region (section)
- (when (magit-confirm 'discard "Discard region")
- (magit-discard-apply section 'magit-apply-region)))
-
-(defun magit-discard-hunk (section)
- (when (magit-confirm 'discard "Discard hunk")
- (magit-discard-apply section 'magit-apply-hunk)))
-
-(defun magit-discard-apply (section apply)
- (if (eq (magit-diff-type section) 'unstaged)
- (funcall apply section "--reverse")
- (if (magit-anything-unstaged-p
- nil (if (eq (magit-section-type section) 'file)
- (magit-section-value section)
- (magit-section-parent-value section)))
- (progn (let ((inhibit-magit-refresh t))
- (funcall apply section "--reverse" "--cached")
- (funcall apply section "--reverse" "--reject"))
- (magit-refresh))
- (funcall apply section "--reverse" "--index"))))
-
-(defun magit-discard-hunks (sections)
- (when (magit-confirm 'discard
- (format "Discard %s 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)
- (let ((section (car sections)))
- (if (eq (magit-diff-type section) 'unstaged)
- (funcall apply sections "--reverse")
- (if (magit-anything-unstaged-p
- nil (if (eq (magit-section-type section) 'file)
- (magit-section-value section)
- (magit-section-parent-value section)))
- (progn (let ((inhibit-magit-refresh t))
- (funcall apply sections "--reverse" "--cached")
- (funcall apply sections "--reverse" "--reject"))
- (magit-refresh))
- (funcall apply sections "--reverse" "--index")))))
-
-(defun magit-discard-file (section)
- (magit-discard-files (list section)))
-
-(defun magit-discard-files (sections)
- (let ((auto-revert-verbose nil)
- (type (magit-diff-type (car sections)))
- (status (magit-file-status))
- files delete resurrect rename discard discard-new resolve)
- (dolist (section sections)
- (let ((file (magit-section-value section)))
- (push file files)
- (pcase (cons (pcase type
- (`staged ?X)
- (`unstaged ?Y)
- (`untracked ?Z))
- (cddr (assoc file status)))
- (`(?Z) (--each (magit-untracked-files nil file)
- (push it delete)))
- ((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete))
- ((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete))
- ((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve))
- (`(,_ ?A ?A) (push file resolve))
- (`(?X ?M ,(or ? ?M ?D)) (push section discard))
- (`(?Y ,_ ?M ) (push section discard))
- (`(?X ?A ?M ) (push file discard-new))
- (`(?X ?C ?M ) (push file discard-new))
- (`(?X ?A ,(or ? ?D)) (push file delete))
- (`(?X ?C ,(or ? ?D)) (push file delete))
- (`(?X ?D ,(or ? ?M )) (push file resurrect))
- (`(?Y ,_ ?D ) (push file resurrect))
- (`(?X ?R ,(or ? ?M ?D)) (push file rename)))))
- (unwind-protect
- (let ((inhibit-magit-refresh t))
- (magit-wip-commit-before-change files " before discard")
- (when resolve
- (dolist (file (nreverse resolve))
- (magit-checkout-stage file (magit-checkout-read-stage file))))
- (magit-discard-files--resurrect (nreverse resurrect))
- (magit-discard-files--delete (nreverse delete) status)
- (magit-discard-files--rename (nreverse rename) status)
- (magit-discard-files--discard (nreverse discard)
- (nreverse discard-new))
- (magit-wip-commit-after-apply files " after discard"))
- (magit-refresh))))
-
-(defun magit-discard-files--resurrect (files)
- (when (magit-confirm-files 'resurrect files)
- (if (eq (magit-diff-type) 'staged)
- (magit-call-git "reset" "--" files)
- (magit-call-git "checkout" "--" files))))
-
-(defun magit-discard-files--delete (files status)
- (when (if magit-delete-by-moving-to-trash
- (magit-confirm-files 'trash files)
- (magit-confirm-files 'delete files))
- (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
- (dolist (file files)
- (if (memq (magit-diff-type) '(unstaged untracked))
- (dired-delete-file file dired-recursive-deletes
- magit-delete-by-moving-to-trash)
- (pcase (nth 3 (assoc file status))
- (? (delete-file file t)
- (magit-call-git "rm" "--cached" "--" file))
- (?M (let ((temp (magit-git-string "checkout-index" "--temp" file)))
- (string-match
- (format "\\(.+?\\)\t%s" (regexp-quote file)) temp)
- (rename-file (match-string 1 temp)
- (setq temp (concat file ".~{index}~")))
- (delete-file temp t))
- (magit-call-git "rm" "--cached" "--force" "--" file))
- (?D (magit-call-git "checkout" "--" file)
- (delete-file file t)
- (magit-call-git "rm" "--cached" "--force" "--" file))))))))
-
-(defun magit-discard-files--rename (files status)
- (when (magit-confirm 'rename "Undo rename %s" "Undo %i renames"
- (mapcar (lambda (file)
- (setq file (assoc file status))
- (format "%s -> %s" (cadr file) (car file)))
- files))
- (dolist (file files)
- (let ((orig (cadr (assoc file status))))
- (if (file-exists-p file)
- (magit-call-git "mv" file orig)
- (magit-call-git "rm" "--cached" "--" file)
- (magit-call-git "reset" "--" orig))))))
-
-(defun magit-discard-files--discard (sections new-files)
- (let ((files (mapcar #'magit-section-value sections)))
- (when (magit-confirm-files
- 'discard (append files new-files)
- (format "Discard %s changes in" (magit-diff-type)))
- (if (eq (magit-diff-type (car sections)) 'unstaged)
- (magit-call-git "checkout" "--" files)
- (when new-files
- (magit-call-git "add" "--" new-files)
- (magit-call-git "reset" "--" new-files))
- (let ((binaries (magit-staged-binary-files)))
- (when binaries
- (setq sections
- (--filter (not (member (magit-section-value it) 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-modified-files t)))
- (setq binaries (--separate (member it modified) binaries)))
- (when (cadr binaries)
- (magit-call-git "reset" "--" (cadr binaries)))
- (when (car binaries)
- (user-error
- (concat
- "Cannot discard staged changes to binary files, "
- "which also have unstaged changes. Unstage instead.")))))))))
-
-;;;; Reverse
-
-(defun magit-reverse (&rest args)
- "Reverse the change at point in the working tree.
-With a prefix argument fallback to a 3-way merge. Doing
-so causes the change to be applied to the index as well."
- (interactive (and current-prefix-arg (list "--3way")))
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(untracked ,_) (user-error "Cannot reverse untracked changes"))
- (`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
- (`(,_ region) (magit-reverse-region it args))
- (`(,_ hunk) (magit-reverse-hunk it args))
- (`(,_ hunks) (magit-reverse-hunks it args))
- (`(,_ file) (magit-reverse-file it args))
- (`(,_ files) (magit-reverse-files it args))
- (`(,_ list) (magit-reverse-files it args)))))
-
-(defun magit-reverse-region (section args)
- (when (magit-confirm 'reverse "Reverse region")
- (magit-reverse-apply section 'magit-apply-region args)))
-
-(defun magit-reverse-hunk (section args)
- (when (magit-confirm 'reverse "Reverse hunk")
- (magit-reverse-apply section 'magit-apply-hunk args)))
-
-(defun magit-reverse-hunks (sections args)
- (when (magit-confirm 'reverse
- (format "Reverse %s 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)
- (magit-reverse-files (list section) args))
-
-(defun magit-reverse-files (sections args)
- (-let [(binaries sections)
- (let ((bs (magit-staged-binary-files)))
- (--separate (member (magit-section-value it) bs) sections))]
- (when (magit-confirm-files 'reverse (mapcar #'magit-section-value sections))
- (if (= (length sections) 1)
- (magit-reverse-apply (car sections) 'magit-apply-diff args)
- (magit-reverse-apply sections 'magit-apply-diffs args)))
- (when binaries
- (user-error "Cannot reverse binary files"))))
-
-(defun magit-reverse-apply (section:s apply args)
- (funcall apply section:s "--reverse" args
- (and (not magit-reverse-atomically)
- (not (member "--3way" args))
- "--reject")))
-
-(defun magit-reverse-in-index (&rest args)
- "Reverse the change at point in the index but not the working tree.
-
-Use this command to extract a change from `HEAD', while leaving
-it in the working tree, so that it can later be committed using
-a separate commit. A typical workflow would be:
-
-0. Optionally make sure that there are no uncommitted changes.
-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.
-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\"
- and then type \"c c\" to create a new commit."
- (interactive)
- (magit-reverse (cons "--cached" args)))
-
-;;; magit-apply.el ends soon
-(provide 'magit-apply)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-apply.el ends here
+++ /dev/null
-;;; magit-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-(add-to-list 'load-path (or (file-name-directory #$) (car load-path)))
-\f
-;;;### (autoloads nil "git-rebase" "git-rebase.el" (22348 36366 0
-;;;;;; 0))
-;;; Generated autoloads from git-rebase.el
-
-(autoload 'git-rebase-mode "git-rebase" "\
-Major mode for editing of a Git rebase file.
-
-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.
-
-\(fn)" t nil)
-
-(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
-
-(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp 'git-rebase-mode))
-
-;;;***
-\f
-;;;### (autoloads nil "magit" "magit.el" (22348 36366 0 0))
-;;; Generated autoloads from magit.el
-
-(autoload 'magit-status "magit" "\
-Show the status of the current Git repository in a buffer.
-With a prefix argument prompt for a repository to be shown.
-With two prefix arguments prompt for an arbitrary directory.
-If that directory isn't the root of an existing repository
-then offer to initialize it as a new repository.
-
-\(fn &optional DIRECTORY)" t nil)
-
-(autoload 'magit-status-internal "magit" "\
-
-
-\(fn DIRECTORY)" nil nil)
- (autoload 'magit-show-refs-popup "magit" nil t)
-
-(autoload 'magit-show-refs-head "magit" "\
-List and compare references in a dedicated buffer.
-Refs are compared with `HEAD'.
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-show-refs-current "magit" "\
-List and compare references in a dedicated buffer.
-Refs are compared with the current branch or `HEAD' if
-it is detached.
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-show-refs "magit" "\
-List and compare references in a dedicated buffer.
-Refs are compared with a branch read form the user.
-
-\(fn &optional REF ARGS)" t nil)
-
-(autoload 'magit-find-file "magit" "\
-View FILE from REV.
-Switch to a buffer visiting blob REV:FILE,
-creating one if none already exists.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-find-file-other-window "magit" "\
-View FILE from REV, in another window.
-Like `magit-find-file', but create a new window or reuse an
-existing one.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-dired-jump "magit" "\
-Visit file at point using Dired.
-With a prefix argument, visit in other window. If there
-is no file at point then instead visit `default-directory'.
-
-\(fn &optional OTHER-WINDOW)" t nil)
-
-(autoload 'magit-checkout-file "magit" "\
-Checkout FILE from REV.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-init "magit" "\
-Initialize a Git repository, then show its status.
-
-If the directory is below an existing repository, then the user
-has to confirm that a new one should be created inside. If the
-directory is the root of the existing repository, then the user
-has to confirm that it should be reinitialized.
-
-Non-interactively DIRECTORY is (re-)initialized unconditionally.
-
-\(fn DIRECTORY)" t nil)
- (autoload 'magit-branch-popup "magit" nil t)
-
-(autoload 'magit-checkout "magit" "\
-Checkout REVISION, updating the index and the working tree.
-If REVISION is a local branch then that becomes the current
-branch. If it is something else then `HEAD' becomes detached.
-Checkout fails if the working tree or the staging area contain
-changes.
-
-\(git checkout REVISION).
-
-\(fn REVISION)" t nil)
-
-(autoload 'magit-branch "magit" "\
-Create BRANCH at branch or revision START-POINT.
-
-\(git branch [ARGS] BRANCH START-POINT).
-
-\(fn BRANCH START-POINT &optional ARGS)" t nil)
-
-(autoload 'magit-branch-and-checkout "magit" "\
-Create and checkout BRANCH at branch or revision START-POINT.
-
-\(git checkout [ARGS] -b BRANCH START-POINT).
-
-\(fn BRANCH START-POINT &optional ARGS)" t nil)
-
-(autoload 'magit-branch-spinoff "magit" "\
-Create new branch from the unpushed commits.
-
-Create and checkout a new branch starting at and tracking the
-current branch. That branch in turn is reset to the last commit
-it shares with its upstream. If the current branch has no
-upstream or no unpushed commits, then the new branch is created
-anyway and the previously current branch is not touched.
-
-This is useful to create a feature branch after work has already
-began on the old branch (likely but not necessarily \"master\").
-
-If the current branch is a member of the value of option
-`magit-branch-prefer-remote-upstream' (which see), then the
-current branch will be used as the starting point as usual, but
-the upstream of the starting-point may be used as the upstream
-of the new branch, instead of the starting-point itself.
-
-\(fn BRANCH &rest ARGS)" t nil)
-
-(autoload 'magit-branch-reset "magit" "\
-Reset a branch to the tip of another branch or any other commit.
-
-When the branch being reset is the current branch, then do a
-hard reset. If there are any uncommitted changes, then the user
-has to confirming the reset because those changes would be lost.
-
-This is useful when you have started work on a feature branch but
-realize it's all crap and want to start over.
-
-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.
-
-\(fn BRANCH TO &optional ARGS SET-UPSTREAM)" t nil)
-
-(autoload 'magit-branch-delete "magit" "\
-Delete one or multiple branches.
-If the region marks multiple branches, then offer to delete
-those, otherwise prompt for a single branch to be deleted,
-defaulting to the branch at point.
-
-\(fn BRANCHES &optional FORCE)" t nil)
-
-(autoload 'magit-branch-rename "magit" "\
-Rename branch OLD to NEW.
-With prefix, forces the rename even if NEW already exists.
-
-\(git branch -m|-M OLD NEW).
-
-\(fn OLD NEW &optional FORCE)" t nil)
-
-(autoload 'magit-branch-config-popup "magit" "\
-Popup console for setting branch variables.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-edit-branch*description "magit" "\
-Edit the description of the current branch.
-With a prefix argument edit the description of another branch.
-
-The description for the branch named NAME is stored in the Git
-variable `branch.<name>.description'.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-set-branch*merge/remote "magit" "\
-Set or unset the upstream of the current branch.
-With a prefix argument do so for another branch.
-
-When the branch in question already has an upstream then simply
-unsets it. Invoke this command again to set another upstream.
-
-Together the Git variables `branch.<name>.remote' and
-`branch.<name>.merge' define the upstream branch of the local
-branch named NAME. The value of `branch.<name>.remote' is the
-name of the upstream remote. The value of `branch.<name>.merge'
-is the full reference of the upstream branch, on the remote.
-
-Non-interactively, when UPSTREAM is non-nil, then always set it
-as the new upstream, regardless of whether another upstream was
-already set. When nil, then always unset.
-
-\(fn BRANCH UPSTREAM)" t nil)
-
-(autoload 'magit-cycle-branch*rebase "magit" "\
-Cycle the value of `branch.<name>.rebase' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variables `branch.<name>.rebase' controls whether pulling
-into the branch named NAME is done by rebasing that branch onto
-the fetched branch or by merging that branch.
-
-When `true' then pulling is done by rebasing.
-When `false' then pulling is done by merging.
-
-When that variable is undefined then the value of `pull.rebase'
-is used instead. It defaults to `false'.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-cycle-branch*pushRemote "magit" "\
-Cycle the value of `branch.<name>.pushRemote' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variable `branch.<name>.pushRemote' specifies the remote
-that the branch named NAME is usually pushed to. The value has
-to be the name of an existing remote.
-
-If that variable is undefined, then the value of the Git variable
-`remote.pushDefault' is used instead, provided that it is defined,
-which by default it is not.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-cycle-pull\.rebase "magit" "\
-Cycle the repository-local value of `pull.rebase'.
-
-The Git variable `pull.rebase' specifies whether pulling is done
-by rebasing or by merging. It can be overwritten using the Git
-variable `branch.<name>.rebase'.
-
-When `true' then pulling is done by rebasing.
-When `false' (the default) then pulling is done by merging.
-
-\(fn)" t nil)
-
-(autoload 'magit-cycle-remote\.pushDefault "magit" "\
-Cycle the repository-local value of `remote.pushDefault'.
-
-The Git variable `remote.pushDefault' specifies the remote that
-local branches are usually pushed to. It can be overwritten
-using the Git variable `branch.<name>.pushRemote'.
-
-\(fn)" t nil)
-
-(autoload 'magit-cycle-branch*autoSetupMerge "magit" "\
-Cycle the repository-local value of `branch.autoSetupMerge'.
-
-The Git variable `branch.autoSetupMerge' under what circumstances
-creating a branch (named NAME) should result in the variables
-`branch.<name>.merge' and `branch.<name>.remote' being set
-according to the starting point used to create the branch. If
-the starting point isn't a branch, then these variables are never
-set.
-
-When `always' then the variables are set regardless of whether
-the starting point is a local or a remote branch.
-
-When `true' (the default) then the variable are set when the
-starting point is a remote branch, but not when it is a local
-branch.
-
-When `false' then the variables are never set.
-
-\(fn)" t nil)
-
-(autoload 'magit-cycle-branch*autoSetupRebase "magit" "\
-Cycle the repository-local value of `branch.autoSetupRebase'.
-
-The Git variable `branch.autoSetupRebase' specifies whether
-creating a branch (named NAME) should result in the variable
-`branch.<name>.rebase' being set to `true'.
-
-When `always' then the variable is set regardless of whether the
-starting point is a local or a remote branch.
-
-When `local' then the variable are set when the starting point
-is a local branch, but not when it is a remote branch.
-
-When `remote' then the variable are set when the starting point
-is a remote branch, but not when it is a local branch.
-
-When `never' (the default) then the variable is never set.
-
-\(fn)" t nil)
- (autoload 'magit-merge-popup "magit" nil t)
-
-(autoload 'magit-merge "magit" "\
-Merge commit REV into the current branch; using default message.
-
-Unless there are conflicts or a prefix argument is used create a
-merge commit using a generic commit message and without letting
-the user inspect the result. With a prefix argument pretend the
-merge failed to give the user the opportunity to inspect the
-merge.
-
-\(git merge --no-edit|--no-commit [ARGS] REV)
-
-\(fn REV &optional ARGS NOCOMMIT)" t nil)
-
-(autoload 'magit-merge-editmsg "magit" "\
-Merge commit REV into the current branch; and edit message.
-Perform the merge and prepare a commit message but let the user
-edit it.
-
-\(git merge --edit --no-ff [ARGS] rev)
-
-\(fn REV &optional ARGS)" t nil)
-
-(autoload 'magit-merge-nocommit "magit" "\
-Merge commit REV into the current branch; pretending it failed.
-Pretend the merge failed to give the user the opportunity to
-inspect the merge and change the commit message.
-
-\(git merge --no-commit --no-ff [ARGS] rev)
-
-\(fn REV &optional ARGS)" t nil)
-
-(autoload 'magit-merge-preview "magit" "\
-Preview result of merging REV into the current branch.
-
-\(fn REV)" t nil)
-
-(autoload 'magit-merge-abort "magit" "\
-Abort the current merge operation.
-
-\(git merge --abort)
-
-\(fn)" t nil)
- (autoload 'magit-reset-popup "magit" nil t)
-
-(autoload 'magit-reset-index "magit" "\
-Reset the index to COMMIT.
-Keep the head and working tree as-is, so if COMMIT refers to the
-head this effectively unstages all changes.
-
-\(git reset COMMIT .)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset "magit" "\
-Reset the head and index to COMMIT, but not the working tree.
-With a prefix argument also reset the working tree.
-
-\(git reset --mixed|--hard COMMIT)
-
-\(fn COMMIT &optional HARD)" t nil)
-
-(autoload 'magit-reset-head "magit" "\
-Reset the head and index to COMMIT, but not the working tree.
-
-\(git reset --mixed COMMIT)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-soft "magit" "\
-Reset the head to COMMIT, but not the index and working tree.
-
-\(git reset --soft REVISION)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-hard "magit" "\
-Reset the head, index, and working tree to COMMIT.
-
-\(git reset --hard REVISION)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-worktree-checkout "magit" "\
-
-
-\(fn PATH BRANCH)" t nil)
-
-(autoload 'magit-worktree-branch "magit" "\
-Create a new BRANCH and check it out in a new worktree at PATH.
-
-\(fn PATH BRANCH START-POINT &optional FORCE)" t nil)
- (autoload 'magit-tag-popup "magit" nil t)
-
-(autoload 'magit-tag "magit" "\
-Create a new tag with the given NAME at REV.
-With a prefix argument annotate the tag.
-
-\(git tag [--annotate] NAME REV)
-
-\(fn NAME REV &optional ARGS)" t nil)
-
-(autoload 'magit-tag-delete "magit" "\
-Delete one or more tags.
-If the region marks multiple tags (and nothing else), then offer
-to delete those, otherwise prompt for a single tag to be deleted,
-defaulting to the tag at point.
-
-\(git tag -d TAGS)
-
-\(fn TAGS)" t nil)
- (autoload 'magit-notes-popup "magit" nil t)
- (autoload 'magit-file-popup "magit" nil t)
-
-(defvar global-magit-file-mode nil "\
-Non-nil if Global-Magit-File mode is enabled.
-See the command `global-magit-file-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `global-magit-file-mode'.")
-
-(custom-autoload 'global-magit-file-mode "magit" nil)
-
-(autoload 'global-magit-file-mode "magit" "\
-Toggle Magit-File mode in all buffers.
-With prefix ARG, enable Global-Magit-File mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Magit-File mode is enabled in all buffers where
-`magit-file-mode-turn-on' would do it.
-See `magit-file-mode' for more information on Magit-File mode.
-
-\(fn &optional ARG)" t nil)
- (autoload 'magit-dispatch-popup "magit" nil t)
- (autoload 'magit-run-popup "magit" nil t)
-
-(autoload 'magit-git-command "magit" "\
-Execute a Git subcommand asynchronously, displaying the output.
-With a prefix argument run Git in the root of the current
-repository, otherwise in `default-directory'.
-
-\(fn ARGS DIRECTORY)" t nil)
-
-(autoload 'magit-git-command-topdir "magit" "\
-Execute a Git subcommand asynchronously, displaying the output.
-Run Git in the top-level directory of the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-shell-command "magit" "\
-Execute a shell command asynchronously, displaying the output.
-With a prefix argument run the command in the root of the current
-repository, otherwise in `default-directory'.
-
-\(fn ARGS DIRECTORY)" t nil)
-
-(autoload 'magit-shell-command-topdir "magit" "\
-Execute a shell command asynchronously, displaying the output.
-Run the command in the top-level directory of the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-version "magit" "\
-Return the version of Magit currently in use.
-When called interactive also show the used versions of Magit,
-Git, and Emacs in the echo area.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-apply" "magit-apply.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-apply.el
-
-(autoload 'magit-stage-file "magit-apply" "\
-Stage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be staged. Otherwise stage the file at point without
-requiring confirmation.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-stage-modified "magit-apply" "\
-Stage all changes to files modified in the worktree.
-Stage all new content of tracked files and remove tracked files
-that no longer exist in the working tree from the index also.
-With a prefix argument also stage previously untracked (but not
-ignored) files.
-\('git add --update|--all .').
-
-\(fn &optional ALL)" t nil)
-
-(autoload 'magit-unstage-file "magit-apply" "\
-Unstage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be unstaged. Otherwise unstage the file at point
-without requiring confirmation.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-unstage-all "magit-apply" "\
-Remove all changes from the staging area.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-autorevert" "magit-autorevert.el" (22348
-;;;;;; 36366 0 0))
-;;; Generated autoloads from magit-autorevert.el
-
-(defvar magit-revert-buffers t)
-
-(defvar magit-auto-revert-mode (and magit-revert-buffers (not global-auto-revert-mode) (not noninteractive)) "\
-Non-nil if Magit-Auto-Revert mode is enabled.
-See the command `magit-auto-revert-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `magit-auto-revert-mode'.")
-
-(custom-autoload 'magit-auto-revert-mode "magit-autorevert" nil)
-
-(autoload 'magit-auto-revert-mode "magit-autorevert" "\
-Toggle Auto-Revert mode in all buffers.
-With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Auto-Revert mode is enabled in all buffers where
-`magit-turn-on-auto-revert-mode-if-desired' would do it.
-See `auto-revert-mode' for more information on Auto-Revert mode.
-
-\(fn &optional ARG)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-bisect" "magit-bisect.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-bisect.el
- (autoload 'magit-bisect-popup "magit-bisect" nil t)
-
-(autoload 'magit-bisect-start "magit-bisect" "\
-Start a bisect session.
-
-Bisecting a bug means to find the commit that introduced it.
-This command starts such a bisect session by asking for a know
-good and a bad commit. To move the session forward use the
-other actions from the bisect popup (\\<magit-status-mode-map>\\[magit-bisect-popup]).
-
-\(fn BAD GOOD)" t nil)
-
-(autoload 'magit-bisect-reset "magit-bisect" "\
-After bisecting, cleanup bisection state and return to original `HEAD'.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-good "magit-bisect" "\
-While bisecting, mark the current commit as good.
-Use this after you have asserted that the commit does not contain
-the bug in question.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-bad "magit-bisect" "\
-While bisecting, mark the current commit as bad.
-Use this after you have asserted that the commit does contain the
-bug in question.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-skip "magit-bisect" "\
-While bisecting, skip the current commit.
-Use this if for some reason the current commit is not a good one
-to test. This command lets Git choose a different one.
-
-\(fn)" t nil)
-
-(autoload 'magit-bisect-run "magit-bisect" "\
-Bisect automatically by running commands after each step.
-
-Unlike `git bisect run' this can be used before bisecting has
-begun. In that case it behaves like `git bisect start; git
-bisect run'.
-
-\(fn CMDLINE &optional BAD GOOD)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-blame" "magit-blame.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-blame.el
- (autoload 'magit-blame-popup "magit-blame" nil t)
-
-(autoload 'magit-blame "magit-blame" "\
-Display edit history of FILE up to REVISION.
-
-Interactively blame the file being visited in the current buffer.
-If the buffer visits a revision of that file, then blame up to
-that revision, otherwise blame the file's full history, including
-uncommitted changes.
-
-If Magit-Blame mode is already turned on then blame recursively, by
-visiting REVISION:FILE (using `magit-find-file'), where revision
-is the revision before the revision that added the lines at
-point.
-
-ARGS is a list of additional arguments to pass to `git blame';
-only arguments available from `magit-blame-popup' should be used.
-
-\(fn REVISION FILE &optional ARGS)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-commit" "magit-commit.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-commit.el
-
-(autoload 'magit-commit "magit-commit" "\
-Create a new commit on HEAD.
-With a prefix argument amend to the commit at HEAD instead.
-
-\(git commit [--amend] ARGS)
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-commit-amend "magit-commit" "\
-Amend the last commit.
-
-\(git commit --amend ARGS)
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-commit-extend "magit-commit" "\
-Amend the last commit, without editing the 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.
-\(git commit
---amend --no-edit)
-
-\(fn &optional ARGS OVERRIDE-DATE)" t nil)
-
-(autoload 'magit-commit-reword "magit-commit" "\
-Reword the last commit, ignoring staged changes.
-
-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.
-
-\(git commit --amend --only)
-
-\(fn &optional ARGS OVERRIDE-DATE)" t nil)
-
-(autoload 'magit-commit-fixup "magit-commit" "\
-Create a fixup commit.
-
-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'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-squash "magit-commit" "\
-Create a squash commit, without editing the squash 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'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-augment "magit-commit" "\
-Create a squash commit, editing the squash 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'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-instant-fixup "magit-commit" "\
-Create a fixup commit targeting COMMIT and instantly rebase.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-instant-squash "magit-commit" "\
-Create a squash commit targeting COMMIT and instantly rebase.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-diff" "magit-diff.el" (22348 36366 0
-;;;;;; 0))
-;;; Generated autoloads from magit-diff.el
-
-(autoload 'magit-diff-popup "magit-diff" "\
-Popup console for diff commands.
-
-\(fn ARG)" t nil)
-
-(autoload 'magit-diff-buffer-file-popup "magit-diff" "\
-Popup console for diff commands.
-
-This is a variant of `magit-diff-popup' which shows the same popup
-but which limits the diff to the file being visited in the current
-buffer.
-
-\(fn)" t nil)
-
-(autoload 'magit-diff-dwim "magit-diff" "\
-Show changes for the thing at point.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff "magit-diff" "\
-Show differences between two commits.
-
-REV-OR-RANGE should be a range or a single revision. If it is a
-revision, then show changes in the working tree relative to that
-revision. If it is a range, but one side is omitted, then show
-changes relative to `HEAD'.
-
-If the region is active, use the revisions on the first and last
-line of the region as the two sides of the range. With a prefix
-argument, instead of diffing the revisions, choose a revision to
-view changes along, starting at the common ancestor of both
-revisions (i.e., use a \"...\" range).
-
-\(fn REV-OR-RANGE &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-working-tree "magit-diff" "\
-Show changes between the current working tree and the `HEAD' commit.
-With a prefix argument show changes between the working tree and
-a commit read from the minibuffer.
-
-\(fn &optional REV ARGS FILES)" t nil)
-
-(autoload 'magit-diff-staged "magit-diff" "\
-Show changes between the index and the `HEAD' commit.
-With a prefix argument show changes between the index and
-a commit read from the minibuffer.
-
-\(fn &optional REV ARGS FILES)" t nil)
-
-(autoload 'magit-diff-unstaged "magit-diff" "\
-Show changes between the working tree and the index.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-while-committing "magit-diff" "\
-While committing, show the changes that are about to be committed.
-While amending, invoking the command again toggles between
-showing just the new changes or all the changes that will
-be committed.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-buffer-file "magit-diff" "\
-Show diff for the blob or file visited in the current buffer.
-
-\(fn)" t nil)
-
-(autoload 'magit-diff-paths "magit-diff" "\
-Show changes between any two files on disk.
-
-\(fn A B)" t nil)
-
-(autoload 'magit-show-commit "magit-diff" "\
-Show the revision at point.
-If there is no revision at point or with a prefix argument prompt
-for a revision.
-
-\(fn REV &optional ARGS FILES MODULE)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-ediff" "magit-ediff.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-ediff.el
- (autoload 'magit-ediff-popup "magit-ediff" nil t)
-
-(autoload 'magit-ediff-resolve "magit-ediff" "\
-Resolve outstanding conflicts in FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-In the rare event that you want to manually resolve all
-conflicts, including those already resolved by Git, use
-`ediff-merge-revisions-with-ancestor'.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-stage "magit-ediff" "\
-Stage and unstage changes to FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-compare "magit-ediff" "\
-Compare REVA:FILEA with REVB:FILEB using Ediff.
-
-FILEA and FILEB have to be relative to the top directory of the
-repository. If REVA or REVB is nil then this stands for the
-working tree state.
-
-If the region is active, use the revisions on the first and last
-line of the region. With a prefix argument, instead of diffing
-the revisions, choose a revision to view changes along, starting
-at the common ancestor of both revisions (i.e., use a \"...\"
-range).
-
-\(fn REVA REVB FILEA FILEB)" t nil)
-
-(autoload 'magit-ediff-dwim "magit-ediff" "\
-Compare, stage, or resolve using Ediff.
-This command tries to guess what file, and what commit or range
-the user wants to compare, stage, or resolve using Ediff. It
-might only be able to guess either the file, or range or commit,
-in which case the user is asked about the other. It might not
-always guess right, in which case the appropriate `magit-ediff-*'
-command has to be used explicitly. If it cannot read the user's
-mind at all, then it asks the user for a command to run.
-
-\(fn)" t nil)
-
-(autoload 'magit-ediff-show-staged "magit-ediff" "\
-Show staged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-unstaged "magit-ediff" "\
-Show unstaged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-working-tree "magit-ediff" "\
-Show changes between HEAD and working tree using Ediff.
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-commit "magit-ediff" "\
-Show changes introduced by COMMIT using Ediff.
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-ediff-show-stash "magit-ediff" "\
-Show changes introduced by STASH using Ediff.
-`magit-ediff-show-stash-with-index' controls whether a
-three-buffer Ediff is used in order to distinguish changes in the
-stash that were staged.
-
-\(fn STASH)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-extras" "magit-extras.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-extras.el
-
-(autoload 'magit-run-git-gui "magit-extras" "\
-Run `git gui' for the current git repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-run-git-gui-blame "magit-extras" "\
-Run `git gui blame' on the given FILENAME and COMMIT.
-Interactively run it for the current file and the HEAD, with a
-prefix or when the current file cannot be determined let the user
-choose. When the current buffer is visiting FILENAME instruct
-blame to center around the line point is on.
-
-\(fn COMMIT FILENAME &optional LINENUM)" t nil)
-
-(autoload 'magit-run-gitk "magit-extras" "\
-Run `gitk' in the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-run-gitk-branches "magit-extras" "\
-Run `gitk --branches' in the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-run-gitk-all "magit-extras" "\
-Run `gitk --all' in the current repository.
-
-\(fn)" t nil)
-
-(autoload 'magit-clean "magit-extras" "\
-Remove untracked files from the working tree.
-With a prefix argument also remove ignored files,
-with two prefix arguments remove ignored files only.
-
-\(git clean -f -d [-x|-X])
-
-\(fn &optional ARG)" t nil)
-
-(autoload 'magit-gitignore "magit-extras" "\
-Instruct Git to ignore FILE-OR-PATTERN.
-With a prefix argument only ignore locally.
-
-\(fn FILE-OR-PATTERN &optional LOCAL)" t nil)
-
-(autoload 'magit-gitignore-locally "magit-extras" "\
-Instruct Git to locally ignore FILE-OR-PATTERN.
-
-\(fn FILE-OR-PATTERN)" t nil)
-
-(autoload 'magit-add-change-log-entry "magit-extras" "\
-Find change log file and add date entry and item for current change.
-This differs from `add-change-log-entry' (which see) in that
-it acts on the current hunk in a Magit buffer instead of on
-a position in a file-visiting buffer.
-
-\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil)
-
-(autoload 'magit-add-change-log-entry-other-window "magit-extras" "\
-Find change log file in other window and add entry and item.
-This differs from `add-change-log-entry-other-window' (which see)
-in that it acts on the current hunk in a Magit buffer instead of
-on a position in a file-visiting buffer.
-
-\(fn &optional WHOAMI FILE-NAME)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-log" "magit-log.el" (22348 36366 0 0))
-;;; Generated autoloads from magit-log.el
-
-(autoload 'magit-log-buffer-file-popup "magit-log" "\
-Popup console for log commands.
-
-This is a variant of `magit-log-popup' which shows the same popup
-but which limits the log to the file being visited in the current
-buffer.
-
-\(fn)" t nil)
-
-(autoload 'magit-log-current "magit-log" "\
-Show log for the current branch.
-When `HEAD' is detached or with a prefix argument show log for
-one or more revs read from the minibuffer.
-
-\(fn REVS &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log "magit-log" "\
-Show log for one or more revs read from the minibuffer.
-The user can input any revision or revisions separated by a
-space, or even ranges, but only branches and tags, and a
-representation of the commit at point, are available as
-completion candidates.
-
-\(fn REVS &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-head "magit-log" "\
-Show log for `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-branches "magit-log" "\
-Show log for all local branches and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-all-branches "magit-log" "\
-Show log for all local and remote branches and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-all "magit-log" "\
-Show log for all references and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-buffer-file "magit-log" "\
-Show log for the blob or file visited in the current buffer.
-With a prefix argument or when `--follow' is part of
-`magit-log-arguments', then follow renames.
-
-\(fn &optional FOLLOW BEG END)" t nil)
-
-(autoload 'magit-reflog-current "magit-log" "\
-Display the reflog of the current branch.
-
-\(fn)" t nil)
-
-(autoload 'magit-reflog "magit-log" "\
-Display the reflog of a branch.
-
-\(fn REF)" t nil)
-
-(autoload 'magit-reflog-head "magit-log" "\
-Display the `HEAD' reflog.
-
-\(fn)" t nil)
-
-(autoload 'magit-cherry "magit-log" "\
-Show commits in a branch that are not merged in the upstream branch.
-
-\(fn HEAD UPSTREAM)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-remote" "magit-remote.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-remote.el
-
-(autoload 'magit-clone "magit-remote" "\
-Clone the REPOSITORY to DIRECTORY.
-Then show the status buffer for the new repository.
-
-\(fn REPOSITORY DIRECTORY)" t nil)
- (autoload 'magit-remote-popup "magit-remote" nil t)
-
-(autoload 'magit-remote-add "magit-remote" "\
-Add a remote named REMOTE and fetch it.
-
-\(fn REMOTE URL)" t nil)
-
-(autoload 'magit-remote-rename "magit-remote" "\
-Rename the remote named OLD to NEW.
-
-\(fn OLD NEW)" t nil)
-
-(autoload 'magit-remote-set-url "magit-remote" "\
-Change the url of the remote named REMOTE to URL.
-
-\(fn REMOTE URL)" t nil)
-
-(autoload 'magit-remote-remove "magit-remote" "\
-Delete the remote named REMOTE.
-
-\(fn REMOTE)" t nil)
-
-(autoload 'magit-remote-set-head "magit-remote" "\
-Set the local representation of REMOTE's default branch.
-Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
-accordingly. With a prefix argument query for the branch to be
-used, which allows you to select an incorrect value if you fancy
-doing that.
-
-\(fn REMOTE &optional BRANCH)" t nil)
-
-(autoload 'magit-remote-unset-head "magit-remote" "\
-Unset the local representation of REMOTE's default branch.
-Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\".
-
-\(fn REMOTE)" t nil)
- (autoload 'magit-fetch-popup "magit-remote" nil t)
-
-(autoload 'magit-fetch-from-pushremote "magit-remote" "\
-Fetch from the push-remote of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-fetch-from-upstream "magit-remote" "\
-Fetch from the upstream repository of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-fetch "magit-remote" "\
-Fetch from another repository.
-
-\(fn REMOTE ARGS)" t nil)
-
-(autoload 'magit-fetch-branch "magit-remote" "\
-Fetch a BRANCH from a REMOTE.
-
-\(fn REMOTE BRANCH ARGS)" t nil)
-
-(autoload 'magit-fetch-refspec "magit-remote" "\
-Fetch a REFSPEC from a REMOTE.
-
-\(fn REMOTE REFSPEC ARGS)" t nil)
-
-(autoload 'magit-fetch-all "magit-remote" "\
-Fetch from all remotes.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-fetch-all-prune "magit-remote" "\
-Fetch from all remotes, and prune.
-Prune remote tracking branches for branches that have been
-removed on the respective remote.
-
-\(fn)" t nil)
-
-(autoload 'magit-fetch-all-no-prune "magit-remote" "\
-Fetch from all remotes.
-
-\(fn)" t nil)
- (autoload 'magit-pull-popup "magit-remote" nil t)
- (autoload 'magit-pull-and-fetch-popup "magit-remote" nil t)
-
-(autoload 'magit-pull-from-pushremote "magit-remote" "\
-Pull from the push-remote of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-pull-from-upstream "magit-remote" "\
-Pull from the upstream of the current branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-pull "magit-remote" "\
-Pull from a branch read in the minibuffer.
-
-\(fn SOURCE ARGS)" t nil)
- (autoload 'magit-push-popup "magit-remote" nil t)
-
-(autoload 'magit-push-current-to-pushremote "magit-remote" "\
-Push the current branch to `branch.<name>.pushRemote'.
-If that variable is unset, then push to `remote.pushDefault'.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the push-remote is not configured, then read the push-remote from
-the user, set it, and then push to it. With a prefix argument
-the push-remote can be changed before pushed to it.
-
-\(fn ARGS &optional PUSH-REMOTE)" t nil)
-
-(autoload 'magit-push-current-to-upstream "magit-remote" "\
-Push the current branch to its upstream branch.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the upstream is not configured, then read the upstream from the
-user, set it, and then push to it. With a prefix argument the
-upstream can be changed before pushed to it.
-
-\(fn ARGS &optional UPSTREAM)" t nil)
-
-(autoload 'magit-push-current "magit-remote" "\
-Push the current branch to a branch read in the minibuffer.
-
-\(fn TARGET ARGS)" t nil)
-
-(autoload 'magit-push "magit-remote" "\
-Push an arbitrary branch or commit somewhere.
-Both the source and the target are read in the minibuffer.
-
-\(fn SOURCE TARGET ARGS)" t nil)
-
-(autoload 'magit-push-refspecs "magit-remote" "\
-Push one or multiple REFSPECS to a REMOTE.
-Both the REMOTE and the REFSPECS are read in the minibuffer. To
-use multiple REFSPECS, separate them with commas. Completion is
-only available for the part before the colon, or when no colon
-is used.
-
-\(fn REMOTE REFSPECS ARGS)" t nil)
-
-(autoload 'magit-push-matching "magit-remote" "\
-Push all matching branches to another repository.
-If multiple remotes exist, then read one from the user.
-If just one exists, use that without requiring confirmation.
-
-\(fn REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-tags "magit-remote" "\
-Push all tags to another repository.
-If only one remote exists, then push to that. Otherwise prompt
-for a remote, offering the remote configured for the current
-branch as default.
-
-\(fn REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-tag "magit-remote" "\
-Push a tag to another repository.
-
-\(fn TAG REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-implicitly "magit-remote" "\
-Push somewhere without using an explicit refspec.
-
-This command simply runs \"git push -v [ARGS]\". ARGS are the
-arguments specified in the popup buffer. No explicit refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?P
- 'magit-push-implicitly--desc
- 'magit-push-implicitly ?p t))
-
-The function `magit-push-implicitly--desc' attempts to predict
-what this command will do, the value it returns is displayed in
-the popup buffer.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-push-to-remote "magit-remote" "\
-Push to REMOTE without using an explicit refspec.
-The REMOTE is read in the minibuffer.
-
-This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
-are the arguments specified in the popup buffer. No refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?r
- 'magit-push-to-remote--desc
- 'magit-push-to-remote ?p t))
-
-\(fn REMOTE ARGS)" t nil)
- (autoload 'magit-patch-popup "magit-remote" nil t)
-
-(autoload 'magit-format-patch "magit-remote" "\
-Create patches for the commits in RANGE.
-When a single commit is given for RANGE, create a patch for the
-changes introduced by that commit (unlike 'git format-patch'
-which creates patches for all commits that are reachable from
-HEAD but not from the specified commit).
-
-\(fn RANGE ARGS)" t nil)
-
-(autoload 'magit-request-pull "magit-remote" "\
-Request upstream to pull from you public repository.
-
-URL is the url of your publically accessible repository.
-START is a commit that already is in the upstream repository.
-END is the last commit, usually a branch name, which upstream
-is asked to pull. START has to be reachable from that commit.
-
-\(fn URL START END)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-sequence" "magit-sequence.el" (22348
-;;;;;; 36366 0 0))
-;;; Generated autoloads from magit-sequence.el
-
-(autoload 'magit-sequencer-continue "magit-sequence" "\
-Resume the current cherry-pick or revert sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-sequencer-skip "magit-sequence" "\
-Skip the stopped at commit during a cherry-pick or revert sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-sequencer-abort "magit-sequence" "\
-Abort the current cherry-pick or revert sequence.
-This discards all changes made since the sequence started.
-
-\(fn)" t nil)
- (autoload 'magit-cherry-pick-popup "magit-sequence" nil t)
-
-(autoload 'magit-cherry-pick "magit-sequence" "\
-Cherry-pick COMMIT.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then pick all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
-
-(autoload 'magit-cherry-apply "magit-sequence" "\
-Apply the changes in COMMIT but do not commit them.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then apply all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
- (autoload 'magit-revert-popup "magit-sequence" nil t)
-
-(autoload 'magit-revert "magit-sequence" "\
-Revert COMMIT by creating a new commit.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
-
-(autoload 'magit-revert-no-commit "magit-sequence" "\
-Revert COMMIT by applying it in reverse to the worktree.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
- (autoload 'magit-am-popup "magit-sequence" nil t)
-
-(autoload 'magit-am-apply-patches "magit-sequence" "\
-Apply the patches FILES.
-
-\(fn &optional FILES ARGS)" t nil)
-
-(autoload 'magit-am-apply-maildir "magit-sequence" "\
-Apply the patches from MAILDIR.
-
-\(fn &optional MAILDIR ARGS)" t nil)
-
-(autoload 'magit-am-continue "magit-sequence" "\
-Resume the current patch applying sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-am-skip "magit-sequence" "\
-Skip the stopped at patch during a patch applying sequence.
-
-\(fn)" t nil)
-
-(autoload 'magit-am-abort "magit-sequence" "\
-Abort the current patch applying sequence.
-This discards all changes made since the sequence started.
-
-\(fn)" t nil)
- (autoload 'magit-rebase-popup "magit-sequence" nil t)
-
-(autoload 'magit-rebase-onto-pushremote "magit-sequence" "\
-Rebase the current branch onto `branch.<name>.pushRemote'.
-If that variable is unset, then rebase onto `remote.pushDefault'.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-rebase-onto-upstream "magit-sequence" "\
-Rebase the current branch onto its upstream branch.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-rebase "magit-sequence" "\
-Rebase the current branch onto a branch read in the minibuffer.
-All commits that are reachable from head but not from the
-selected branch TARGET are being rebased.
-
-\(fn TARGET ARGS)" t nil)
-
-(autoload 'magit-rebase-subset "magit-sequence" "\
-Rebase a subset of the current branches history onto a new base.
-Rebase commits from START to `HEAD' onto NEWBASE.
-START has to be selected from a list of recent commits.
-
-\(fn NEWBASE START ARGS)" t nil)
-
-(autoload 'magit-rebase-interactive "magit-sequence" "\
-Start an interactive rebase sequence.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-autosquash "magit-sequence" "\
-Combine squash and fixup commits with their intended targets.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-rebase-edit-commit "magit-sequence" "\
-Edit a single older commit using rebase.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-reword-commit "magit-sequence" "\
-Reword a single older commit using rebase.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-continue "magit-sequence" "\
-Restart the current rebasing operation.
-In some cases this pops up a commit message buffer for you do
-edit. With a prefix argument the old message is reused as-is.
-
-\(fn &optional NOEDIT)" t nil)
-
-(autoload 'magit-rebase-skip "magit-sequence" "\
-Skip the current commit and restart the current rebase operation.
-
-\(fn)" t nil)
-
-(autoload 'magit-rebase-edit "magit-sequence" "\
-Edit the todo list of the current rebase operation.
-
-\(fn)" t nil)
-
-(autoload 'magit-rebase-abort "magit-sequence" "\
-Abort the current rebase operation, restoring the original branch.
-
-\(fn)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-stash" "magit-stash.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-stash.el
- (autoload 'magit-stash-popup "magit-stash" nil t)
-
-(autoload 'magit-stash "magit-stash" "\
-Create a stash of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-index "magit-stash" "\
-Create a stash of the index only.
-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.
-
-\(fn MESSAGE)" t nil)
-
-(autoload 'magit-stash-worktree "magit-stash" "\
-Create a stash of unstaged changes in the working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-keep-index "magit-stash" "\
-Create a stash of the index and working tree, keeping index intact.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-snapshot "magit-stash" "\
-Create a snapshot of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-snapshot-index "magit-stash" "\
-Create a snapshot of the index only.
-Unstaged and untracked changes are not stashed.
-
-\(fn)" t nil)
-
-(autoload 'magit-snapshot-worktree "magit-stash" "\
-Create a snapshot of unstaged changes in the working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-apply "magit-stash" "\
-Apply a stash to the working tree.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index.
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-drop "magit-stash" "\
-Remove a stash from the stash list.
-When the region is active offer to drop all contained stashes.
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-clear "magit-stash" "\
-Remove all stashes saved in REF's reflog by deleting REF.
-
-\(fn REF)" t nil)
-
-(autoload 'magit-stash-branch "magit-stash" "\
-Create and checkout a new BRANCH from STASH.
-
-\(fn STASH BRANCH)" t nil)
-
-(autoload 'magit-stash-format-patch "magit-stash" "\
-Create a patch from STASH
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-list "magit-stash" "\
-List all stashes in a buffer.
-
-\(fn)" t nil)
-
-(autoload 'magit-stash-show "magit-stash" "\
-Show all diffs of a stash in a buffer.
-
-\(fn STASH &optional ARGS FILES)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-submodule" "magit-submodule.el" (22348
-;;;;;; 36366 0 0))
-;;; Generated autoloads from magit-submodule.el
- (autoload 'magit-submodule-popup "magit-submodule" nil t)
-
-(autoload 'magit-submodule-add "magit-submodule" "\
-Add the repository at URL as a submodule.
-
-Optional PATH is the path to the submodule relative to the root
-of the superproject. If it is nil, then the path is determined
-based on the URL.
-
-Optional NAME is the name of the submodule. If it is nil, then
-PATH also becomes the name.
-
-\(fn URL &optional PATH NAME)" t nil)
-
-(autoload 'magit-submodule-setup "magit-submodule" "\
-Clone and register missing submodules and checkout appropriate commits.
-
-\(fn)" t nil)
-
-(autoload 'magit-submodule-init "magit-submodule" "\
-Register submodules listed in \".gitmodules\" into \".git/config\".
-
-\(fn)" t nil)
-
-(autoload 'magit-submodule-update "magit-submodule" "\
-Clone missing submodules and checkout appropriate commits.
-With a prefix argument also register submodules in \".git/config\".
-
-\(fn &optional INIT)" t nil)
-
-(autoload 'magit-submodule-sync "magit-submodule" "\
-Update each submodule's remote URL according to \".gitmodules\".
-
-\(fn)" t nil)
-
-(autoload 'magit-submodule-fetch "magit-submodule" "\
-Fetch all submodules.
-With a prefix argument fetch all remotes.
-
-\(fn &optional ALL)" t nil)
-
-(autoload 'magit-submodule-deinit "magit-submodule" "\
-Unregister the submodule at PATH.
-
-\(fn PATH)" t nil)
-
-(autoload 'magit-insert-submodules "magit-submodule" "\
-Insert sections for all modules.
-For each section insert the path and the output of `git describe --tags'.
-
-\(fn)" nil nil)
-
-(autoload 'magit-insert-modules-unpulled-from-upstream "magit-submodule" "\
-Insert sections for modules that haven't been pulled from the upstream.
-These sections can be expanded to show the respective commits.
-
-\(fn)" nil nil)
-
-(autoload 'magit-insert-modules-unpulled-from-pushremote "magit-submodule" "\
-Insert sections for modules that haven't been pulled from the push-remote.
-These sections can be expanded to show the respective commits.
-
-\(fn)" nil nil)
-
-(autoload 'magit-insert-modules-unpushed-to-upstream "magit-submodule" "\
-Insert sections for modules that haven't been pushed to the upstream.
-These sections can be expanded to show the respective commits.
-
-\(fn)" nil nil)
-
-(autoload 'magit-insert-modules-unpushed-to-pushremote "magit-submodule" "\
-Insert sections for modules that haven't been pushed to the push-remote.
-These sections can be expanded to show the respective commits.
-
-\(fn)" nil nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-subtree" "magit-subtree.el" (22348 36366
-;;;;;; 0 0))
-;;; Generated autoloads from magit-subtree.el
- (autoload 'magit-subtree-popup "magit-subtree" nil t)
-
-(autoload 'magit-subtree-add "magit-subtree" "\
-Add COMMIT from REPOSITORY as a new subtree at PREFIX.
-
-\(fn PREFIX REPOSITORY COMMIT ARGS)" t nil)
-
-(autoload 'magit-subtree-add-commit "magit-subtree" "\
-Add COMMIT as a new subtree at PREFIX.
-
-\(fn PREFIX COMMIT ARGS)" t nil)
-
-(autoload 'magit-subtree-merge "magit-subtree" "\
-Merge COMMIT into the PREFIX subtree.
-
-\(fn PREFIX COMMIT ARGS)" t nil)
-
-(autoload 'magit-subtree-pull "magit-subtree" "\
-Pull COMMIT from REPOSITORY into the PREFIX subtree.
-
-\(fn PREFIX REPOSITORY COMMIT ARGS)" t nil)
-
-(autoload 'magit-subtree-push "magit-subtree" "\
-Extract the history of the subtree PREFIX and push it to REF on REPOSITORY.
-
-\(fn PREFIX REPOSITORY REF ARGS)" t nil)
-
-(autoload 'magit-subtree-split "magit-subtree" "\
-Extract the history of the subtree PREFIX.
-
-\(fn PREFIX COMMIT ARGS)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil "magit-wip" "magit-wip.el" (22348 36366 0 0))
-;;; Generated autoloads from magit-wip.el
-
-(defvar magit-wip-after-save-mode nil "\
-Non-nil if Magit-Wip-After-Save mode is enabled.
-See the command `magit-wip-after-save-mode' for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `magit-wip-after-save-mode'.")
-
-(custom-autoload 'magit-wip-after-save-mode "magit-wip" nil)
-
-(autoload 'magit-wip-after-save-mode "magit-wip" "\
-Toggle Magit-Wip-After-Save-Local mode in all buffers.
-With prefix ARG, enable Magit-Wip-After-Save mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Magit-Wip-After-Save-Local mode is enabled in all buffers where
-`magit-wip-after-save-local-mode-turn-on' would do it.
-See `magit-wip-after-save-local-mode' for more information on Magit-Wip-After-Save-Local mode.
-
-\(fn &optional ARG)" t nil)
-
-(defvar magit-wip-after-apply-mode nil "\
-Non-nil if Magit-Wip-After-Apply mode is enabled.
-See the command `magit-wip-after-apply-mode' for a description of this minor mode.")
-
-(custom-autoload 'magit-wip-after-apply-mode "magit-wip" nil)
-
-(autoload 'magit-wip-after-apply-mode "magit-wip" "\
-Commit to work-in-progress refs.
-
-After applying a change using any \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected files to the current wip refs. For each branch there
-may be two wip refs; one contains snapshots of the files as found
-in the worktree and the other contains snapshots of the entries
-in the index.
-
-\(fn &optional ARG)" t nil)
-
-(defvar magit-wip-before-change-mode nil "\
-Non-nil if Magit-Wip-Before-Change mode is enabled.
-See the command `magit-wip-before-change-mode' for a description of this minor mode.")
-
-(custom-autoload 'magit-wip-before-change-mode "magit-wip" nil)
-
-(autoload 'magit-wip-before-change-mode "magit-wip" "\
-Commit to work-in-progress refs before certain destructive changes.
-
-Before invoking a revert command or an \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected tracked files to the current wip refs. For each branch
-there may be two wip refs; one contains snapshots of the files
-as found in the worktree and the other contains snapshots of the
-entries in the index.
-
-Only changes to files which could potentially be affected by the
-command which is about to be called are committed.
-
-\(fn &optional ARG)" t nil)
-
-;;;***
-\f
-;;;### (autoloads nil nil ("magit-core.el" "magit-git.el" "magit-mode.el"
-;;;;;; "magit-pkg.el" "magit-process.el" "magit-section.el" "magit-utils.el")
-;;;;;; (22348 36366 237268 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; End:
-;;; magit-autoloads.el ends here
+++ /dev/null
-;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-git)
-
-(require 'autorevert)
-
-(defgroup magit-auto-revert nil
- "Revert buffers when files in repository change."
- :group 'auto-revert
- :group 'magit-extensions)
-
-(defcustom auto-revert-buffer-list-filter nil
- "Filter that determines which buffers `auto-revert-buffers' reverts.
-
-This option is provided by `magit', which also redefines
-`auto-revert-buffers' to respect it. Magit users who do not turn
-on the local mode `auto-revert-mode' themselves, are best served
-by setting the value to `magit-auto-revert-repository-buffers-p'.
-
-However the default is nil, to not disturb users who do use the
-local mode directly. If you experience delays when running Magit
-commands, then you should consider using one of the predicates
-provided by Magit - especially if you also use Tramp.
-
-Users who do turn on `auto-revert-mode' in buffers in which Magit
-doesn't do that for them, should likely not use any filter.
-Users who turn on `global-auto-revert-mode', do not have to worry
-about this option, because it is disregarded if the global mode
-is enabled."
- :package-version '(magit . "2.4.2")
- :group 'auto-revert
- :group 'magit-auto-revert
- :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
- "Whether `magit-auto-revert-mode' only reverts tracked files."
- :package-version '(magit . "2.4.0")
- :group 'magit-auto-revert
- :type 'boolean
- :set (lambda (var val)
- (set var val)
- (when (and (bound-and-true-p magit-auto-revert-mode)
- (featurep 'magit-autorevert))
- (magit-auto-revert-mode -1)
- (magit-auto-revert-mode))))
-
-(defcustom magit-auto-revert-immediately t
- "Whether Magit reverts buffers immediately.
-
-If this is non-nil and either `global-auto-revert-mode' or
-`magit-auto-revert-mode' is enabled, then Magit immediately
-reverts buffers by explicitly calling `auto-revert-buffers'
-after running git for side-effects.
-
-If `auto-revert-use-notify' is non-nil (and file notifications
-are actually supported), then `magit-auto-revert-immediately'
-does not have to be non-nil, because the reverts happen
-immediately anyway.
-
-If `magit-auto-revert-immediately' and `auto-revert-use-notify'
-are both nil, then reverts happen after `auto-revert-interval'
-seconds of user inactivity. That is not desirable."
- :package-version '(magit . "2.4.0")
- :group 'magit-auto-revert
- :type 'boolean)
-
-(defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
- (if file
- (--when-let (find-buffer-visiting file)
- (with-current-buffer it
- (magit-turn-on-auto-revert-mode-if-desired)))
- (when (and buffer-file-name
- (file-readable-p buffer-file-name)
- (magit-toplevel)
- (or (not magit-auto-revert-tracked-only)
- (magit-file-tracked-p buffer-file-name)))
- (auto-revert-mode))))
-
-;;;###autoload
-(defvar magit-revert-buffers t)
-(make-obsolete-variable 'magit-revert-buffers 'magit-auto-revert-mode
- "Magit 2.4.0")
-
-;;;###autoload
-(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
- magit-turn-on-auto-revert-mode-if-desired
- :package-version '(magit . "2.4.0")
- :group 'magit
- :group 'magit-auto-revert
- ;; When `global-auto-revert-mode' is enabled, then this mode is
- ;; redundant. When `magit-revert-buffers' is nil, then the user has
- ;; opted out of the automatic reverts while the old implementation
- ;; was still in use. In all other cases enable the mode because if
- ;; buffers are not automatically reverted that would make many very
- ;; common tasks much more cumbersome.
- :init-value (and magit-revert-buffers
- (not global-auto-revert-mode)
- (not noninteractive)))
-;; - Unfortunately `:init-value t' only sets the value of the mode
-;; variable but does not cause the mode function to be called.
-;; - I don't think it works like this on purpose, but since one usually
-;; should not enable global modes by default, it is understandable.
-;; - If the user has set the variable `magit-auto-revert-mode' to nil
-;; after loading magit (instead of doing so before loading magit or
-;; by using the function), then we should still respect that setting.
-;; - If the user has set the obsolete variable `magit-revert-buffers'
-;; to nil before or after loading magit, then we should still respect
-;; that setting.
-;; - If the user sets one of these variables after loading magit and
-;; after `after-init-hook' has run, then that won't have an effect
-;; and there is nothing we can do about it.
-(defun magit-auto-revert-mode--init-kludge ()
- "This is an internal kludge to be used on `after-init-hook'.
-Do not use this function elsewhere, and don't remove it from
-the `after-init-hook'. For more information see the comments
-and code surrounding the definition of this function."
- ;; `magit-revert-buffers' may have been set to nil before the alias
- ;; had been established, so consult the value of both variables.
- (if (and magit-auto-revert-mode magit-revert-buffers)
- (let ((start (current-time)))
- (magit-message "Turning on magit-auto-revert-mode...")
- (magit-auto-revert-mode 1)
- (magit-message
- "Turning on magit-auto-revert-mode...done%s"
- (let ((elapsed (float-time (time-subtract (current-time) start))))
- (if (> elapsed 0.2)
- (format " (%.3fs, %s buffers checked)" elapsed
- (length (buffer-list)))
- ""))))
- (magit-auto-revert-mode -1)))
-(if after-init-time
- ;; Since `after-init-hook' has already been
- ;; run, turn the mode on or off right now.
- (magit-auto-revert-mode--init-kludge)
- ;; By the time the init file has been fully loaded the
- ;; values of the relevant variables might have changed.
- (add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t))
-
-(put 'magit-auto-revert-mode 'function-documentation
- "Toggle Magit Auto Revert mode.
-With a prefix argument ARG, enable Magit Auto Revert mode if ARG
-is positive, and disable it otherwise. If called from Lisp,
-enable the mode if ARG is omitted or nil.
-
-Magit Auto Revert mode is a global minor mode that reverts
-buffers associated with a file that is located inside a Git
-repository when the file changes on disk. Use `auto-revert-mode'
-to revert a particular buffer. Or use `global-auto-revert-mode'
-to revert all file-visiting buffers, not just those that visit
-a file located inside a Git repository.
-
-This global mode works by turning on the buffer-local mode
-`auto-revert-mode' at the time a buffer is first created. The
-local mode is turned on if the visited file is being tracked in
-a Git repository at the time when the buffer is created.
-
-If `magit-auto-revert-tracked-only' is non-nil (the default),
-then only tracked files are reverted. But if you stage a
-previously untracked file using `magit-stage', then this mode
-notices that.
-
-Unlike `global-auto-revert-mode', this mode never reverts any
-buffers that are not visiting files.
-
-The behavior of this mode can be customized using the options
-in the `autorevert' and `magit-autorevert' groups.
-
-This function calls the hook `magit-auto-revert-mode-hook'.")
-
-(defun magit-auto-revert-buffers ()
- (when (and magit-auto-revert-immediately
- (or global-auto-revert-mode
- (and magit-auto-revert-mode auto-revert-buffer-list)))
- (let ((auto-revert-buffer-list-filter
- (or auto-revert-buffer-list-filter
- 'magit-auto-revert-repository-buffer-p)))
- (auto-revert-buffers))))
-
-(defvar magit-auto-revert-toplevel nil)
-
-(when (< emacs-major-version 25)
- (defvar auto-revert-buffers-counter 1
- "Incremented each time `auto-revert-buffers' is called"))
-
-(defun magit-auto-revert-buffer-p (buffer)
- "Return t if BUFFER visits a file inside the current repository.
-The current repository is the one in which `default-directory' is
-located. If there is no current repository, then return t for
-any BUFFER."
- (magit-auto-revert-repository-buffer-p buffer t))
-
-(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback)
- "Return t if BUFFER visits a file inside the current repository.
-The current repository is the one in which `default-directory' is
-located. If there is no current repository, then return FALLBACK
-\(which defaults to nil) for any BUFFER."
- ;; Call `magit-toplevel' just once per cycle.
- (unless (and magit-auto-revert-toplevel
- (= (cdr magit-auto-revert-toplevel)
- auto-revert-buffers-counter))
- (setq magit-auto-revert-toplevel
- (cons (or (magit-toplevel) 'no-repo)
- auto-revert-buffers-counter)))
- (let ((top (car magit-auto-revert-toplevel)))
- (if (eq top 'no-repo)
- fallback
- (let ((dir (with-current-buffer buffer default-directory)))
- (and (equal (file-remote-p dir)
- (file-remote-p top))
- ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
- (file-in-directory-p dir top))))))
-
-(defun auto-revert-buffers--buffer-list-filter ()
- (when (< emacs-major-version 25)
- (cl-incf auto-revert-buffers-counter))
- (when auto-revert-buffer-list-filter
- (setq auto-revert-buffer-list
- (--filter auto-revert-buffer-list-filter
- auto-revert-buffer-list))))
-
-(advice-add 'auto-revert-buffers :before
- 'auto-revert-buffers--buffer-list-filter)
-
-(custom-add-to-group 'magit 'auto-revert-check-vc-info 'custom-variable)
-
-;;; magit-autorevert.el ends soon
-(provide 'magit-autorevert)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-autorevert.el ends here
+++ /dev/null
-;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Use a binary search to find the commit that introduced a bug.
-
-;;; Code:
-
-(require 'magit)
-
-(defface magit-bisect-good
- '((t :foreground "DarkOliveGreen"))
- "Face for good bisect revisions."
- :group 'magit-faces)
-
-(defface magit-bisect-skip
- '((t :foreground "DarkGoldenrod"))
- "Face for skipped bisect revisions."
- :group 'magit-faces)
-
-(defface magit-bisect-bad
- '((t :foreground "IndianRed4"))
- "Face for bad bisect revisions."
- :group 'magit-faces)
-
-;;;###autoload (autoload 'magit-bisect-popup "magit-bisect" nil t)
-(magit-define-popup magit-bisect-popup
- "Popup console for bisect commands."
- 'magit-commands
- :man-page "git-bisect"
- :actions '((?B "Start" magit-bisect-start)
- (?s "Start script" magit-bisect-run))
- :sequence-actions '((?b "Bad" magit-bisect-bad)
- (?g "Good" magit-bisect-good)
- (?k "Skip" magit-bisect-skip)
- (?r "Reset" magit-bisect-reset)
- (?s "Run script" magit-bisect-run))
- :sequence-predicate 'magit-bisect-in-progress-p)
-
-;;;###autoload
-(defun magit-bisect-start (bad good)
- "Start a bisect session.
-
-Bisecting a bug means to find the commit that introduced it.
-This command starts such a bisect session by asking for a know
-good and a bad commit. To move the session forward use the
-other actions from the bisect popup (\
-\\<magit-status-mode-map>\\[magit-bisect-popup])."
- (interactive (if (magit-bisect-in-progress-p)
- (user-error "Already bisecting")
- (magit-bisect-start-read-args)))
- (magit-git-bisect "start" (list bad good) t))
-
-(defun magit-bisect-start-read-args ()
- (let ((b (magit-read-branch-or-commit "Start bisect with bad revision")))
- (list b (magit-read-other-branch-or-commit "Good revision" b))))
-
-;;;###autoload
-(defun magit-bisect-reset ()
- "After bisecting, cleanup bisection state and return to original `HEAD'."
- (interactive)
- (when (magit-confirm 'reset-bisect)
- (magit-run-git "bisect" "reset")
- (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT")))))
-
-;;;###autoload
-(defun magit-bisect-good ()
- "While bisecting, mark the current commit as good.
-Use this after you have asserted that the commit does not contain
-the bug in question."
- (interactive)
- (magit-git-bisect "good"))
-
-;;;###autoload
-(defun magit-bisect-bad ()
- "While bisecting, mark the current commit as bad.
-Use this after you have asserted that the commit does contain the
-bug in question."
- (interactive)
- (magit-git-bisect "bad"))
-
-;;;###autoload
-(defun magit-bisect-skip ()
- "While bisecting, skip the current commit.
-Use this if for some reason the current commit is not a good one
-to test. This command lets Git choose a different one."
- (interactive)
- (magit-git-bisect "skip"))
-
-;;;###autoload
-(defun magit-bisect-run (cmdline &optional bad good)
- "Bisect automatically by running commands after each step.
-
-Unlike `git bisect run' this can be used before bisecting has
-begun. In that case it behaves like `git bisect start; git
-bisect run'."
- (interactive (let ((args (and (not (magit-bisect-in-progress-p))
- (magit-bisect-start-read-args))))
- (cons (read-shell-command "Bisect shell command: ") args)))
- (when (and bad good)
- (magit-bisect-start bad good))
- (magit-git-bisect "run" (list cmdline)))
-
-(defun magit-git-bisect (subcommand &optional args no-assert)
- (unless (or no-assert (magit-bisect-in-progress-p))
- (user-error "Not bisecting"))
- (magit-with-toplevel
- (magit-run-git-with-logfile
- (magit-git-dir "BISECT_CMD_OUTPUT") "bisect" subcommand args)))
-
-(defun magit-bisect-in-progress-p ()
- (file-exists-p (magit-git-dir "BISECT_LOG")))
-
-(defun magit-insert-bisect-output ()
- "While bisecting, insert section with output from `git bisect'."
- (when (magit-bisect-in-progress-p)
- (let* ((lines
- (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT"))
- (list "Bisecting: (no saved bisect output)"
- "It appears you have invoked `git bisect' from a shell."
- "There is nothing wrong with that, we just cannot display"
- "anything useful here. Consult the shell output instead.")))
- (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))))
- (magit-insert-section ((eval (if bad-line 'commit 'bisect-output))
- (and bad-line (match-string 1 bad-line)))
- (magit-insert-heading
- (propertize (or bad-line (pop lines))
- 'face 'magit-section-heading))
- (dolist (line lines)
- (insert line "\n"))))
- (insert "\n")))
-
-(defun magit-insert-bisect-rest ()
- "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-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis)
- "bisect" "visualize" "git" "log"
- "--format=%h%d %s" "--decorate=full"))))
-
-(defun magit-insert-bisect-log ()
- "While bisecting, insert section logging bisect progress."
- (when (magit-bisect-in-progress-p)
- (magit-insert-section (bisect-log)
- (magit-insert-heading "Bisect Log:")
- (magit-git-wash #'magit-wash-bisect-log "bisect" "log")
- (insert ?\n))))
-
-(defun magit-wash-bisect-log (_args)
- (let (beg)
- (while (progn (setq beg (point-marker))
- (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t))
- (magit-bind-match-strings (heading) nil
- (magit-delete-match)
- (save-restriction
- (narrow-to-region beg (point))
- (goto-char (point-min))
- (magit-insert-section (bisect-log heading t)
- (insert (propertize heading 'face 'magit-section-secondary-heading))
- (magit-insert-heading)
- (magit-wash-sequence
- (apply-partially 'magit-log-wash-rev 'bisect-log
- (magit-abbrev-length)))
- (insert ?\n)))))
- (when (re-search-forward
- "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t)
- (magit-bind-match-strings (hash) nil
- (magit-delete-match)
- (magit-insert-section (bisect-log)
- (insert hash " is the first bad commit\n"))))))
-
-;;; magit-bisect.el ends soon
-(provide 'magit-bisect)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-bisect.el ends here
+++ /dev/null
-;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2012-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Annotates each line in file-visiting buffer with information from
-;; the revision which last modified the line.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defgroup magit-blame nil
- "Blame support for Magit."
- :group 'magit-extensions)
-
-(defcustom magit-blame-heading-format "%-20a %C %s"
- "Format string used for blame headings.
-
-The following placeholders are recognized:
-
- %H hash
- %s summary
- %a author
- %A author time
- %c committer
- %C committer time
-
-The author and committer time formats can be specified with
-`magit-blame-time-format'."
- :group 'magit-blame
- :type 'string)
-
-(defcustom magit-blame-time-format "%F %H:%M"
- "Format for time strings in blame headings."
- :group 'magit-blame
- :type 'string)
-
-(defcustom magit-blame-show-headings t
- "Whether to initially show blame block headings.
-The headings can also be toggled locally using command
-`magit-blame-toggle-headings'."
- :group 'magit-blame
- :type 'boolean)
-
-(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode)
- "List of modes not compatible with Magit-Blame mode.
-This modes are turned off when Magit-Blame mode is turned on,
-and then turned on again when turning off the latter."
- :group 'magit-blame
- :type '(repeat (symbol :tag "Mode")))
-
-(make-variable-buffer-local 'magit-blame-disabled-modes)
-
-(defcustom magit-blame-mode-lighter " Blame"
- "The mode-line lighter of the Magit-Blame mode."
- :group 'magit-blame
- :type '(choice (const :tag "No lighter" "") string))
-
-(unless (find-lisp-object-file-name 'magit-blame-goto-chunk-hook 'defvar)
- (add-hook 'magit-blame-goto-chunk-hook 'magit-blame-maybe-update-revision-buffer))
-(defcustom magit-blame-goto-chunk-hook '(magit-blame-maybe-update-revision-buffer)
- "Hook run by `magit-blame-next-chunk' and `magit-blame-previous-chunk'."
- :package-version '(magit . "2.1.0")
- :group 'magit-blame
- :type 'hook
- :options '(magit-blame-maybe-update-revision-buffer))
-
-(defface magit-blame-heading
- '((((class color) (background light))
- :background "grey80"
- :foreground "black")
- (((class color) (background dark))
- :background "grey25"
- :foreground "black"))
- "Face for blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-summary
- '((t :inherit magit-blame-heading))
- "Face used for commit summary in blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-hash
- '((t :inherit magit-blame-heading))
- "Face used for commit hash in blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-name
- '((t :inherit magit-blame-heading))
- "Face used for author and committer names in blame headings."
- :group 'magit-faces)
-
-(defface magit-blame-date
- '((t :inherit magit-blame-heading))
- "Face used for dates in blame headings."
- :group 'magit-faces)
-
-;;; Code
-
-(defvar magit-blame-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "\r" 'magit-show-commit)
- (define-key map "\s" 'magit-diff-show-or-scroll-up)
- (define-key map "\d" 'magit-diff-show-or-scroll-down)
- (define-key map "b" 'magit-blame-popup)
- (define-key map "n" 'magit-blame-next-chunk)
- (define-key map "N" 'magit-blame-next-chunk-same-commit)
- (define-key map "p" 'magit-blame-previous-chunk)
- (define-key map "P" 'magit-blame-previous-chunk-same-commit)
- (define-key map "q" 'magit-blame-quit)
- (define-key map "t" 'magit-blame-toggle-headings)
- (define-key map "\M-w" 'magit-blame-copy-hash)
- map)
- "Keymap for `magit-blame-mode'.")
-
-(defun magit-blame-put-keymap-before-view-mode ()
- "Put `magit-blame-mode' ahead of `view-mode' in `minor-mode-map-alist'."
- (--when-let (assq 'magit-blame-mode
- (cl-member 'view-mode minor-mode-map-alist :key #'car))
- (setq minor-mode-map-alist
- (cons it (delq it minor-mode-map-alist))))
- (remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode))
-
-(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)
-
-(defvar-local magit-blame-buffer-read-only nil)
-(defvar-local magit-blame-cache nil)
-(defvar-local magit-blame-process nil)
-(defvar-local magit-blame-recursive-p nil)
-(defvar-local magit-blame-separator nil)
-
-(define-minor-mode magit-blame-mode
- "Display blame information inline.
-\n\\{magit-blame-mode-map}"
- :lighter magit-blame-mode-lighter
- (cond (magit-blame-mode
- (when (called-interactively-p 'any)
- (setq magit-blame-mode nil)
- (user-error
- (concat "Don't call `magit-blame-mode' directly; "
- "instead use `magit-blame' or `magit-blame-popup'")))
- (setq magit-blame-buffer-read-only buffer-read-only)
- (read-only-mode 1)
- (dolist (mode magit-blame-disable-modes)
- (when (and (boundp mode) (symbol-value mode))
- (funcall mode -1)
- (push mode magit-blame-disabled-modes)))
- (setq magit-blame-separator (magit-blame-format-separator)))
- (t
- (unless magit-blame-buffer-read-only
- (read-only-mode -1))
- (dolist (mode magit-blame-disabled-modes)
- (funcall mode 1))
- (when (process-live-p magit-blame-process)
- (kill-process magit-blame-process))
- (save-excursion
- (save-restriction
- (widen)
- (dolist (ov (overlays-in (point-min) (point-max)))
- (when (overlay-get ov 'magit-blame)
- (delete-overlay ov))))))))
-
-(defun auto-revert-handler--unless-magit-blame-mode ()
- "If Magit-Blame mode is on, then do nothing. See #1731."
- magit-blame-mode)
-
-(advice-add 'auto-revert-handler :before-until
- 'auto-revert-handler--unless-magit-blame-mode)
-
-;;;###autoload (autoload 'magit-blame-popup "magit-blame" nil t)
-(magit-define-popup magit-blame-popup
- "Popup console for blame commands."
- 'magit-commands
- :man-page "git-blame"
- :switches '((?w "Ignore whitespace" "-w")
- (?r "Do not treat root commits as boundaries" "--root"))
- :options '((?C "Detect lines moved or copied within a file" "-C")
- (?M "Detect lines moved or copied between files" "-M"))
- :actions '((?b "Blame" magit-blame))
- :default-arguments '("-w")
- :default-action 'magit-blame)
-
-;;;###autoload
-(defun magit-blame (revision file &optional args line)
- "Display edit history of FILE up to REVISION.
-
-Interactively blame the file being visited in the current buffer.
-If the buffer visits a revision of that file, then blame up to
-that revision, otherwise blame the file's full history, including
-uncommitted changes.
-
-If Magit-Blame mode is already turned on then blame recursively, by
-visiting REVISION:FILE (using `magit-find-file'), where revision
-is the revision before the revision that added the lines at
-point.
-
-ARGS is a list of additional arguments to pass to `git blame';
-only arguments available from `magit-blame-popup' should be used.
-\n(fn REVISION FILE &optional ARGS)" ; LINE is for internal use
- (interactive
- (let ((args (magit-blame-arguments)))
- (if magit-blame-mode
- (--if-let (magit-blame-chunk-get :previous-hash)
- (list it (magit-blame-chunk-get :previous-file)
- args (magit-blame-chunk-get :previous-start))
- (user-error "Block has no further history"))
- (--if-let (magit-file-relative-name nil 'tracked)
- (list (or magit-buffer-refname magit-buffer-revision) it args)
- (if buffer-file-name
- (user-error "Buffer isn't visiting a tracked file")
- (user-error "Buffer isn't visiting a file"))))))
- (magit-with-toplevel
- (if revision
- (magit-find-file revision file)
- (let ((default-directory default-directory))
- (--if-let (find-buffer-visiting file)
- (progn (switch-to-buffer it)
- (save-buffer))
- (find-file file))))
- ;; ^ Make sure this doesn't affect the value used below. b640c6f
- (widen)
- (when line
- (setq magit-blame-recursive-p t)
- (goto-char (point-min))
- (forward-line (1- line)))
- (unless magit-blame-mode
- (setq magit-blame-cache (make-hash-table :test 'equal))
- (let ((show-headings magit-blame-show-headings))
- (magit-blame-mode 1)
- (setq-local magit-blame-show-headings show-headings))
- (message "Blaming...")
- (let ((magit-process-popup-time -1)
- (inhibit-magit-refresh t))
- (magit-run-git-async
- "blame" "--incremental" args
- "-L" (format "%s,%s"
- (line-number-at-pos (window-start))
- (line-number-at-pos (1- (window-end nil t))))
- revision "--" file))
- (setq magit-blame-process magit-this-process)
- (set-process-filter magit-this-process 'magit-blame-process-filter)
- (set-process-sentinel
- magit-this-process
- `(lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (magit-process-sentinel process event)
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (when magit-blame-mode
- (let ((magit-process-popup-time -1)
- (inhibit-magit-refresh t)
- (default-directory ,default-directory))
- (magit-run-git-async "blame" "--incremental" ,@args
- ,revision "--" ,file))
- (setq magit-blame-process magit-this-process)
- (set-process-filter
- magit-this-process 'magit-blame-process-filter)
- (set-process-sentinel
- magit-this-process 'magit-blame-process-sentinel)))))))))
-
-(defun magit-blame-process-sentinel (process event)
- (let ((status (process-status process)))
- (when (memq status '(exit signal))
- (magit-process-sentinel process event)
- (if (eq status 'exit)
- (message "Blaming...done")
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (magit-blame-mode -1))
- (message "Blaming...failed")))))
-
-(defvar magit-blame-log nil
- "Whether to log blame output to the process buffer.
-This is intended for debugging purposes.")
-
-(defun magit-blame-process-filter (process string)
- (when magit-blame-log
- (magit-process-filter process string))
- (--when-let (process-get process 'partial-line)
- (setq string (concat it string))
- (setf (process-get process 'partial-line) nil))
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (when magit-blame-mode
- (let ((chunk (process-get process 'chunk))
- (lines (split-string string "\n" t)))
- (unless (string-match-p "\n\\'" string)
- (process-put process 'chunk chunk)
- (process-put process 'partial-line (car (last lines)))
- (setq lines (butlast lines)))
- (dolist (line lines)
- (cond
- ((equal line ""))
- ((not chunk)
- (string-match
- "^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)" line)
- (setq chunk
- (list :hash (let ((hash (match-string 1 line)))
- (unless (equal hash (make-string 40 ?0))
- hash))
- :previous-start (string-to-number (match-string 2 line))
- :start (string-to-number (match-string 3 line))
- :lines (string-to-number (match-string 4 line)))))
- ((string-match "^filename \\(.+\\)" line)
- (let* ((hash (plist-get chunk :hash))
- (file (match-string 1 line)))
- (--if-let (gethash hash magit-blame-cache)
- (setq chunk (nconc chunk it))
- (plist-put chunk :filename file)
- (puthash hash chunk magit-blame-cache)))
- (magit-blame-make-overlay chunk)
- (setq chunk nil))
- ((string-match "^previous \\(.\\{40\\}\\) \\(.+\\)" line)
- (plist-put chunk :previous-hash (match-string 1 line))
- (plist-put chunk :previous-file (match-string 2 line)))
- ((string-match "^\\([^ ]+?-mail\\) <\\([^>]+\\)>" line)
- (plist-put chunk (intern (concat ":" (match-string 1 line)))
- (string-to-number (match-string 2 line))))
- ((string-match "^\\([^ ]+?-\\(?:time\\|tz\\)\\) \\(.+\\)" line)
- (plist-put chunk (intern (concat ":" (match-string 1 line)))
- (string-to-number (match-string 2 line))))
- ((string-match "^\\([^ ]+\\) \\(.+\\)" line)
- (plist-put chunk (intern (concat ":" (match-string 1 line)))
- (match-string 2 line))))
- (process-put process 'chunk chunk))))))
-
-(defun magit-blame-assert-buffer (process)
- (unless (buffer-live-p (process-get process 'command-buf))
- (kill-process process)
- (user-error "Buffer being blamed has been killed")))
-
-(defun magit-blame-make-overlay (chunk)
- (let ((ov (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (forward-line (1- (plist-get chunk :start)))
- (--when-let (--first (overlay-get it 'magit-blame)
- (overlays-at (point)))
- (delete-overlay it))
- (make-overlay (point)
- (progn (forward-line
- (plist-get chunk :lines))
- (point))))))
- (heading (magit-blame-format-heading chunk)))
- (overlay-put ov 'magit-blame chunk)
- (overlay-put ov 'magit-blame-heading heading)
- (overlay-put ov 'before-string
- (if magit-blame-show-headings
- heading
- magit-blame-separator))))
-
-(defun magit-blame-format-separator ()
- (propertize
- (concat (propertize " " 'display '(space :height (2)))
- (propertize "\n" 'line-height t))
- 'face (list :background (face-attribute 'magit-blame-heading :background))))
-
-(defun magit-blame-format-heading (chunk)
- (with-temp-buffer
- (insert (format-spec
- (concat magit-blame-heading-format "\n")
- `((?H . ,(propertize (or (plist-get chunk :hash) "")
- 'face 'magit-blame-hash))
- (?s . ,(propertize (or (plist-get chunk :summary) "")
- 'face 'magit-blame-summary))
- (?a . ,(propertize (or (plist-get chunk :author) "")
- 'face 'magit-blame-name))
- (?A . ,(propertize (magit-blame-format-time-string
- magit-blame-time-format
- (plist-get chunk :author-time)
- (plist-get chunk :author-tz))
- 'face 'magit-blame-date))
- (?c . ,(propertize (or (plist-get chunk :committer) "")
- 'face 'magit-blame-name))
- (?C . ,(propertize (magit-blame-format-time-string
- magit-blame-time-format
- (plist-get chunk :committer-time)
- (plist-get chunk :committer-tz))
- 'face 'magit-blame-date)))))
- (goto-char (point-min))
- (while (not (eobp))
- (let ((face (get-text-property (point) 'face))
- (next (or (next-single-property-change (point) 'face)
- (point-max))))
- (unless face
- (put-text-property (point) next 'face 'magit-blame-heading))
- (goto-char next)))
- (buffer-string)))
-
-(defun magit-blame-format-time-string (format time tz)
- (format-time-string
- format (seconds-to-time (+ time (* (/ tz 100) 60 60) (* (% tz 100) 60)))))
-
-(defun magit-blame-quit ()
- "Turn off Magit-Blame mode.
-If the buffer was created during a recursive blame,
-then also kill the buffer."
- (interactive)
- (if magit-blame-recursive-p
- (kill-buffer)
- (magit-blame-mode -1)))
-
-(defun magit-blame-next-chunk ()
- "Move to the next chunk."
- (interactive)
- (--if-let (next-single-char-property-change (point) 'magit-blame)
- (progn (goto-char it)
- (run-hooks 'magit-blame-goto-chunk-hook))
- (user-error "No more chunks")))
-
-(defun magit-blame-previous-chunk ()
- "Move to the previous chunk."
- (interactive)
- (--if-let (previous-single-char-property-change (point) 'magit-blame)
- (progn (goto-char it)
- (run-hooks 'magit-blame-goto-chunk-hook))
- (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)"
- (interactive)
- (-if-let (hash (magit-blame-chunk-get :hash))
- (let ((pos (point)) ov)
- (save-excursion
- (while (and (not ov)
- (not (= pos (if previous (point-min) (point-max))))
- (setq pos (funcall
- (if previous
- 'previous-single-char-property-change
- 'next-single-char-property-change)
- pos 'magit-blame)))
- (--when-let (magit-blame-overlay-at pos)
- (when (equal (magit-blame-chunk-get :hash pos) hash)
- (setq ov it)))))
- (if ov
- (goto-char (overlay-start ov))
- (user-error "No more chunks from same commit")))
- (user-error "This chunk hasn't been blamed yet")))
-
-(defun magit-blame-previous-chunk-same-commit ()
- "Move to the previous chunk from the same commit."
- (interactive)
- (magit-blame-next-chunk-same-commit 'previous-single-char-property-change))
-
-(defun magit-blame-toggle-headings ()
- "Show or hide blame chunk headings."
- (interactive)
- (setq-local magit-blame-show-headings (not magit-blame-show-headings))
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (while (not (eobp))
- (let ((next (next-single-char-property-change (point) 'magit-blame)))
- (--when-let (magit-blame-overlay-at (point))
- (overlay-put it 'before-string
- (if magit-blame-show-headings
- (overlay-get it 'magit-blame-heading)
- magit-blame-separator)))
- (goto-char (or next (point-max))))))))
-
-(defun magit-blame-copy-hash ()
- "Save hash of the current chunk's commit to the kill ring."
- (interactive)
- (if (use-region-p)
- (copy-region-as-kill nil nil 'region)
- (kill-new (message "%s" (magit-blame-chunk-get :hash)))))
-
-(defun magit-blame-chunk-get (key &optional pos)
- (--when-let (magit-blame-overlay-at pos)
- (plist-get (overlay-get it 'magit-blame) key)))
-
-(defun magit-blame-overlay-at (&optional pos)
- (--first (overlay-get it 'magit-blame)
- (overlays-at (or pos (point)))))
-
-(defun magit-blame-maybe-update-revision-buffer ()
- (unless magit--update-revision-buffer
- (setq magit--update-revision-buffer nil)
- (-when-let* ((commit (magit-blame-chunk-get :hash))
- (buffer (magit-mode-get-buffer 'magit-revision-mode nil t)))
- (setq magit--update-revision-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (-let [(rev buf) magit--update-revision-buffer]
- (setq magit--update-revision-buffer nil)
- (when (buffer-live-p buf)
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-show-commit rev (magit-diff-arguments))))))))))
-
-;;; magit-blame.el ends soon
-(provide 'magit-blame)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-blame.el ends here
+++ /dev/null
-;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements commands for creating Git commits. These
-;; commands just initiate the commit, support for writing the commit
-;; messages is implemented in `git-commit.el'.
-
-;;; Code:
-
-(require 'magit)
-(require 'magit-sequence)
-
-(eval-when-compile (require 'epa)) ; for `epa-protocol'
-(eval-when-compile (require 'epg))
-(declare-function epg-sub-key-id 'epg)
-(declare-function epg-key-sub-key-list 'epg)
-(declare-function epg-key-user-id-list 'epg)
-(declare-function epg-user-id-string 'epg)
-(declare-function epg-decode-dn 'epg)
-(declare-function epg-list-keys 'epg)
-
-;;; Options
-
-(defcustom magit-commit-arguments nil
- "The arguments used when committing."
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-commit-ask-to-stage 'verbose
- "Whether to ask to stage everything when committing and nothing is staged."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type '(choice (const :tag "Ask showing diff" verbose)
- (const :tag "Ask" t)
- (const :tag "Don't ask" nil)))
-
-(defcustom magit-commit-show-diff t
- "Whether the relevant diff is automatically shown when committing."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-extend-override-date t
- "Whether using `magit-commit-extend' changes the committer date."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-reword-override-date t
- "Whether using `magit-commit-reword' changes the committer date."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-squash-confirm t
- "Whether the commit targeted by squash and fixup has to be confirmed.
-When non-nil then the commit at point (if any) is used as default
-choice, otherwise it has to be confirmed. This option only
-affects `magit-commit-squash' and `magit-commit-fixup'. The
-\"instant\" variants always require confirmation because making
-an error while using those is harder to recover from."
- :package-version '(magit . "2.1.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Code
-
-(defun magit-commit-popup (&optional arg)
- "Popup console for commit commands."
- (interactive "P")
- (--if-let (magit-commit-message-buffer)
- (switch-to-buffer it)
- (magit-invoke-popup 'magit-commit-popup nil arg)))
-
-(defvar magit-commit-popup
- '(:variable magit-commit-arguments
- :man-page "git-commit"
- :switches ((?a "Stage all modified and deleted files" "--all")
- (?e "Allow empty commit" "--allow-empty")
- (?v "Show diff of changes to be committed" "--verbose")
- (?n "Bypass git hooks" "--no-verify")
- (?s "Add Signed-off-by line" "--signoff")
- (?R "Claim authorship and reset author date" "--reset-author"))
- :options ((?A "Override the author" "--author=")
- (?S "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key)
- (?C "Reuse commit message" "--reuse-message="))
- :actions ((?c "Commit" magit-commit)
- (?e "Extend" magit-commit-extend)
- (?f "Fixup" magit-commit-fixup)
- (?F "Instant Fixup" magit-commit-instant-fixup) nil
- (?w "Reword" magit-commit-reword)
- (?s "Squash" magit-commit-squash)
- (?S "Instant Squash" magit-commit-instant-squash) nil
- (?a "Amend" magit-commit-amend)
- (?A "Augment" magit-commit-augment))
- :max-action-columns 4
- :default-action magit-commit))
-
-(magit-define-popup-keys-deferred 'magit-commit-popup)
-
-(defun magit-commit-arguments nil
- (if (eq magit-current-popup 'magit-commit-popup)
- magit-current-popup-args
- magit-commit-arguments))
-
-(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)))))
-
-;;;###autoload
-(defun magit-commit (&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))))
- (when (setq args (magit-commit-assert args))
- (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-run-git-with-editor "commit" "--amend" args))
-
-;;;###autoload
-(defun magit-commit-extend (&optional args override-date)
- "Amend the last commit, without editing the 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)"
- (interactive (list (magit-commit-arguments)
- (if current-prefix-arg
- (not magit-commit-extend-override-date)
- magit-commit-extend-override-date)))
- (when (setq args (magit-commit-assert args (not override-date)))
- (let ((process-environment process-environment))
- (unless override-date
- (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
- (magit-run-git-with-editor "commit" "--amend" "--no-edit" args))))
-
-;;;###autoload
-(defun magit-commit-reword (&optional args override-date)
- "Reword the last commit, ignoring staged changes.
-
-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)"
- (interactive (list (magit-commit-arguments)
- (if current-prefix-arg
- (not magit-commit-reword-override-date)
- magit-commit-reword-override-date)))
- (let ((process-environment process-environment))
- (unless override-date
- (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
- (magit-run-git-with-editor "commit" "--amend" "--only" args)))
-
-;;;###autoload
-(defun magit-commit-fixup (&optional commit args)
- "Create a fixup commit.
-
-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'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--fixup" commit args))
-
-;;;###autoload
-(defun magit-commit-squash (&optional commit args)
- "Create a squash commit, without editing the squash 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'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args))
-
-;;;###autoload
-(defun magit-commit-augment (&optional commit args)
- "Create a squash commit, editing the squash 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'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args nil t))
-
-;;;###autoload
-(defun magit-commit-instant-fixup (&optional commit args)
- "Create a fixup commit targeting COMMIT and instantly rebase."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--fixup" commit args t))
-
-;;;###autoload
-(defun magit-commit-instant-squash (&optional commit args)
- "Create a squash commit targeting COMMIT and instantly rebase."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args t))
-
-(defun magit-commit-squash-internal
- (option commit &optional args rebase edit confirmed)
- (-when-let (args (magit-commit-assert args t))
- (if (and commit
- (or confirmed
- (not (or rebase
- current-prefix-arg
- magit-commit-squash-confirm))))
- (let ((magit-commit-show-diff nil))
- (push (concat option "=" commit) args)
- (unless edit
- (push "--no-edit" args))
- (if rebase
- (with-editor "GIT_EDITOR"
- (let ((magit-process-popup-time -1))
- (magit-call-git "commit" args)))
- (magit-run-git-with-editor "commit" args)))
- (magit-log-select
- `(lambda (commit)
- (magit-commit-squash-internal ,option commit ',args ,rebase ,edit t)
- ,@(when rebase
- `((magit-rebase-interactive-1 commit
- (list "--autosquash" "--autostash")
- "" "true"))))
- (format "Type %%p on a commit to %s into it,"
- (substring option 2)))
- (when magit-commit-show-diff
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-diff-staged nil (magit-diff-arguments)))))))
-
-(defun magit-commit-assert (args &optional strict)
- (cond
- ((or (magit-anything-staged-p)
- (and (magit-anything-unstaged-p)
- ;; ^ Everything of nothing is still nothing.
- (member "--all" args))
- (and (not strict)
- ;; ^ For amend variants that don't make sense otherwise.
- (or (member "--amend" args)
- (member "--allow-empty" args))))
- (or args (list "--")))
- ((and (magit-rebase-in-progress-p)
- (not (magit-anything-unstaged-p))
- (y-or-n-p "Nothing staged. Continue in-progress rebase? "))
- (magit-run-git-sequencer "rebase" "--continue")
- nil)
- ((and (file-exists-p (magit-git-dir "MERGE_MSG"))
- (not (magit-anything-unstaged-p)))
- (or args (list "--")))
- ((not (magit-anything-unstaged-p))
- (user-error "Nothing staged (or unstaged)"))
- (magit-commit-ask-to-stage
- (when (eq magit-commit-ask-to-stage 'verbose)
- (magit-diff-unstaged))
- (prog1 (when (y-or-n-p "Nothing staged. Stage and commit everything? ")
- (magit-run-git "add" "-u" ".")
- (or args (list "--")))
- (when (and (eq magit-commit-ask-to-stage 'verbose)
- (derived-mode-p 'magit-diff-mode))
- (magit-mode-bury-buffer))))
- (t
- (user-error "Nothing staged"))))
-
-(defun magit-commit-diff ()
- (-when-let (fn (and git-commit-mode
- magit-commit-show-diff
- (pcase last-command
- (`magit-commit
- (apply-partially 'magit-diff-staged nil))
- (`magit-commit-amend 'magit-diff-while-amending)
- (`magit-commit-reword 'magit-diff-while-amending))))
- (-when-let (diff-buffer (magit-mode-get-buffer 'magit-diff-mode))
- ;; This window just started displaying the commit message
- ;; buffer. Without this that buffer would immediately be
- ;; replaced with the diff buffer. See #2632.
- (unrecord-window-buffer nil diff-buffer))
- (condition-case nil
- (let ((magit-inhibit-save-previous-winconf 'unset)
- (magit-display-buffer-noselect t)
- (inhibit-quit nil))
- (message "Diffing changes to be committed (C-g to abort diffing)")
- (funcall fn (car (magit-diff-arguments))))
- (quit))))
-
-;; Mention `magit-diff-while-committing' because that's
-;; always what I search for when I try to find this line.
-(add-hook 'server-switch-hook 'magit-commit-diff)
-
-(add-to-list 'with-editor-server-window-alist
- (cons git-commit-filename-regexp 'switch-to-buffer))
-
-(defvar magit-gpg-secret-key-hist nil)
-
-(defun magit-read-gpg-secret-key (prompt &optional _initial-input)
- (require 'epa)
- (let ((keys (--map (list (epg-sub-key-id (car (epg-key-sub-key-list it)))
- (-when-let (id-obj (car (epg-key-user-id-list it)))
- (let ((id-str (epg-user-id-string id-obj)))
- (if (stringp id-str)
- id-str
- (epg-decode-dn id-obj)))))
- (epg-list-keys (epg-make-context epa-protocol) nil t))))
- (magit-completing-read prompt keys nil nil nil 'magit-gpg-secret-key-hist
- (car (or magit-gpg-secret-key-hist keys)))))
-
-(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert
- "Used by `magit-commit-add-log' to insert a single entry.")
-
-(defun magit-commit-add-log ()
- "Add a stub for the current change into the commit message buffer.
-If no commit is in progress, then initiate it. Use the function
-specified by variable `magit-commit-add-log-insert-function' to
-actually insert the entry."
- (interactive)
- (let ((hunk (magit-section-when 'hunk it))
- (log (magit-commit-message-buffer)) buf pos)
- (save-window-excursion
- (call-interactively #'magit-diff-visit-file)
- (setq buf (current-buffer)
- pos (point)))
- (unless log
- (unless (magit-commit-assert nil)
- (user-error "Abort"))
- (magit-commit)
- (while (not (setq log (magit-commit-message-buffer)))
- (sit-for 0.01)))
- (save-excursion
- (with-current-buffer buf
- (goto-char pos)
- (funcall magit-commit-add-log-insert-function log
- (magit-file-relative-name)
- (and hunk (add-log-current-defun)))))))
-
-(defun magit-commit-add-log-insert (buffer file defun)
- (with-current-buffer buffer
- (undo-boundary)
- (goto-char (point-max))
- (while (re-search-backward (concat "^" comment-start) nil t))
- (cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file)
- nil t)
- (when (equal (match-string 1) defun)
- (setq defun nil))
- (re-search-forward ": "))
- (t
- (when (re-search-backward "^[\\*(].+\n" nil t)
- (goto-char (match-end 0)))
- (while (re-search-forward "^[^\\*#\n].*\n" nil t))
- (if defun
- (progn (insert (format "* %s (%s): \n" file defun))
- (setq defun nil))
- (insert (format "* %s: \n" file)))
- (backward-char)
- (unless (looking-at "\n[\n\\']")
- (insert ?\n)
- (backward-char))))
- (when defun
- (forward-line)
- (let ((limit (save-excursion
- (and (re-search-forward "^\\*" nil t)
- (point)))))
- (unless (or (looking-back (format "(%s): " defun)
- (line-beginning-position))
- (re-search-forward (format "^(%s): " defun) limit t))
- (while (re-search-forward "^[^\\*#\n].*\n" limit t))
- (insert (format "(%s): \n" defun))
- (backward-char))))))
-
-;;; magit-commit.el ends soon
-(provide 'magit-commit)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-commit.el ends here
+++ /dev/null
-;;; magit-core.el --- core functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library requires several other libraries, so that yet other
-;; libraries can just require this one, instead of having to require
-;; all the other ones. In other words this separates the low-level
-;; stuff from the rest. It also defines some Custom groups.
-
-;;; Code:
-
-(require 'magit-utils)
-(require 'magit-section)
-(require 'magit-git)
-(require 'magit-mode)
-(require 'magit-popup)
-(require 'magit-process)
-(require 'magit-autorevert)
-
-(defgroup magit nil
- "Controlling Git from Emacs."
- :group 'tools)
-
-(defgroup magit-commands nil
- "Options controlling behavior of certain commands."
- :group 'magit)
-
-(defgroup magit-modes nil
- "Modes used or provided by Magit."
- :group 'magit)
-
-(defgroup magit-extensions nil
- "Extensions to Magit."
- :group 'magit)
-
-(defgroup magit-faces nil
- "Faces used by Magit."
- :group 'magit
- :group 'faces)
-
-(custom-add-to-group 'magit-modes 'magit-popup 'custom-group)
-(custom-add-to-group 'magit-faces 'magit-popup-faces 'custom-group)
-(custom-add-to-group 'magit-modes 'git-commit 'custom-group)
-(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group)
-(custom-add-to-group 'magit-modes 'git-rebase 'custom-group)
-(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group)
-(custom-add-to-group 'magit-process 'with-editor 'custom-group)
-
-(custom-add-to-group 'magit 'vc-follow-symlinks 'custom-variable)
-
-;;; magit-core.el ends soon
-(provide 'magit-core)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-core.el ends here
+++ /dev/null
-;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for looking at Git diffs and
-;; commits.
-
-;;; Code:
-
-(require 'git-commit)
-(require 'magit-core)
-
-;; For `magit-diff-popup'
-(declare-function magit-stash-show 'magit-stash)
-;; For `magit-diff-visit-file'
-(declare-function magit-dired-jump 'magit)
-(declare-function magit-find-file-noselect 'magit)
-(declare-function magit-status-internal 'magit)
-;; For `magit-diff-wash-revision'
-(declare-function magit-insert-tags-header 'magit)
-;; For `magit-diff-while-committing'
-(declare-function magit-commit-message-buffer 'magit)
-;; For `magit-insert-revision-gravatar'
-(defvar gravatar-size)
-;; For `magit-show-commit' and `magit-diff-show-or-scroll'
-(declare-function magit-blame-chunk-get 'magit-blame)
-(declare-function magit-blame-mode 'magit-blame)
-(defvar magit-blame-mode)
-(defvar git-rebase-line)
-
-(require 'diff-mode)
-(require 'smerge-mode)
-
-;;; Options
-;;;; Diff Mode
-
-(defgroup magit-diff nil
- "Inspect and manipulate Git diffs."
- :group 'magit-modes)
-
-(custom-add-to-group 'magit-diff 'smerge-refine-ignore-whitespace
- 'custom-variable)
-
-(defcustom magit-diff-mode-hook nil
- "Hook run after entering Magit-Diff mode."
- :group 'magit-diff
- :type 'hook)
-
-(defcustom magit-diff-sections-hook
- '(magit-insert-diff
- magit-insert-xref-buttons)
- "Hook run to insert sections into a `magit-diff-mode' buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'hook)
-
-(defcustom magit-diff-expansion-threshold 1.0
- "After how many seconds not to expand anymore diffs.
-
-Except in status buffers, diffs are usually start out fully
-expanded. Because that can take a long time, all diffs that
-haven't been fontified during a refresh before the threshold
-defined here are instead displayed with their bodies collapsed.
-
-Note that this can cause sections that were previously expanded
-to be collapsed. So you should not pick a very low value here.
-
-The hook function `magit-diff-expansion-threshold' has to be a
-member of `magit-section-set-visibility-hook' for this option
-to have any effect"
- :package-version '(magit . "2.1.0")
- :group 'magit-diff
- :type 'float)
-
-(defcustom magit-diff-highlight-hunk-body t
- "Whether to highlight bodies of selected hunk sections.
-This only has an effect if `magit-diff-highlight' is a
-member of `magit-section-highlight-hook', which see."
- :package-version '(magit . "2.1.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-show-lines-boundary t
- "Whether to delimit hunk-internal region with thin lines.
-
-When a hunk-internal region (used to stage just the lines that
-fall into the region instead of the complete hunk) only covers
-context lines, then these lines are the only visual indicator
-for the region. In character-only terminals it's not possible
-to draw thin lines."
- :package-version '(magit . "2.1.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-refine-hunk nil
- "Whether to show word-granularity differences within diff hunks.
-
-nil never show fine differences.
-t show fine differences for the current diff hunk only.
-`all' show fine differences for all displayed diff hunks."
- :group 'magit-diff
- :safe (lambda (val) (memq val '(nil t all)))
- :type '(choice (const :tag "Never" nil)
- (const :tag "Current" t)
- (const :tag "All" all)))
-
-(put 'magit-diff-refine-hunk 'permanent-local t)
-
-(defcustom magit-diff-paint-whitespace t
- "Specify where to highlight whitespace errors.
-See `magit-highlight-trailing-whitespace',
-`magit-highlight-indentation'. The symbol t means in all diffs,
-`status' means only in the status buffer, and nil means nowhere."
- :group 'magit-diff
- :safe (lambda (val) (memq val '(t nil status)))
- :type '(choice (const :tag "Always" t)
- (const :tag "Never" nil)
- (const :tag "In status buffer" status)))
-
-(defcustom magit-diff-highlight-trailing t
- "Whether to highlight whitespace at the end of a line in diffs.
-Used only when `magit-diff-paint-whitespace' is non-nil."
- :group 'magit-diff
- :safe 'booleanp
- :type 'boolean)
-
-(defcustom magit-diff-highlight-indentation nil
- "Highlight the \"wrong\" indentation style.
-Used only when `magit-diff-paint-whitespace' is non-nil.
-
-The value is a list of cons cells. The car is a regular
-expression, and the cdr is the value that applies to repositories
-whose directory matches the regular expression. If more than one
-element matches, then the *last* element in the list applies.
-The default value should therefore come first in the list.
-
-If the value is `tabs', highlight indentation with tabs. If the
-value is an integer, highlight indentation with at least that
-many spaces. Otherwise, highlight neither."
- :group 'magit-diff
- :type `(repeat (cons (string :tag "Directory regexp")
- (choice (const :tag "Tabs" tabs)
- (integer :tag "Spaces" :value ,tab-width)
- (const :tag "Neither" nil)))))
-
-(defcustom magit-diff-hide-trailing-cr-characters
- (and (memq system-type '(ms-dos windows-nt)) t)
- "Whether to hide ^M characters at the end of a line in diffs."
- :package-version '(magit . "2.6.0")
- :group 'magit-diff
- :type 'boolean)
-
-;;;; File Diff
-
-(defcustom magit-diff-buffer-file-locked t
- "Whether `magit-diff-buffer-file' uses a decicated buffer."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :group 'magit-diff
- :type 'boolean)
-
-;;;; Revision Mode
-
-(defgroup magit-revision nil
- "Inspect and manipulate Git commits."
- :group 'magit-modes)
-
-(defcustom magit-revision-mode-hook nil
- "Hook run after entering Magit-Revision mode."
- :group 'magit-revision
- :type 'hook)
-
-(defcustom magit-revision-sections-hook
- '(magit-insert-revision-tag
- magit-insert-revision-headers
- magit-insert-revision-message
- magit-insert-revision-notes
- magit-insert-revision-diff
- magit-insert-xref-buttons)
- "Hook run to insert sections into a `magit-revision-mode' buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'hook)
-
-(defcustom magit-revision-headers-format "\
-Author: %aN <%aE>
-AuthorDate: %ad
-Commit: %cN <%cE>
-CommitDate: %cd
-"
- "Format string used to insert headers in revision buffers.
-
-All headers in revision buffers are inserted by the section
-inserter `magit-insert-revision-headers'. Some of the headers
-are created by calling `git show --format=FORMAT' where FORMAT
-is the format specified here. Other headers are hard coded or
-subject to option `magit-revision-insert-related-refs'."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'string)
-
-(defcustom magit-revision-insert-related-refs t
- "Whether to show related refs in revision buffers."
- :package-version '(magit . "2.1.0")
- :group 'magit-revision
- :type 'boolean)
-
-(defcustom magit-revision-show-gravatars nil
- "Whether to show gravatar images in revision buffers.
-
-If non-nil, then the value has to be a cons-cell which specifies
-where the gravatar images for the author and/or the committer are
-inserted inside the text that was previously inserted according
-to `magit-revision-header-format'.
-
-Both cells are regular expressions. The car specifies where to
-insert the author gravatar image. The top halve of the image is
-inserted right after the matched text, the bottom halve on the
-next line at the same offset. The cdr specifies where to insert
-the committer image, accordingly. Either the car or the cdr may
-be nil."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type '(choice (const :tag "Don't show gravatars" nil)
- (cons :tag "Show gravatars"
- (regexp :tag "Author regexp" "^Author: ")
- (regexp :tag "Committer regexp" "^Commit: "))))
-
-(defcustom magit-revision-use-gravatar-kludge nil
- "Whether to work around a bug which affects display of gravatars.
-
-Gravatar images are spliced into two halves which are then
-displayed on separate lines. On OS X the splicing has a bug in
-some Emacs builds, which causes the top and bottom halves to be
-interchanged. Enabling this option works around this issue by
-interchanging the halves once more, which cancels out the effect
-of the bug.
-
-See https://github.com/magit/magit/issues/2265
-and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'boolean)
-
-;;; Faces
-
-(defface magit-diff-file-heading
- '((t :weight bold))
- "Face for diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-file-heading-highlight
- '((t :inherit (magit-diff-file-heading magit-section-highlight)))
- "Face for current diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-file-heading-selection
- '((((class color) (background light))
- :inherit magit-diff-file-heading-highlight
- :foreground "salmon4")
- (((class color) (background dark))
- :inherit magit-diff-file-heading-highlight
- :foreground "LightSalmon3"))
- "Face for selected diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading
- '((((class color) (background light))
- :background "grey80"
- :foreground "grey30")
- (((class color) (background dark))
- :background "grey25"
- :foreground "grey70"))
- "Face for diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading-highlight
- '((((class color) (background light))
- :background "grey75"
- :foreground "grey30")
- (((class color) (background dark))
- :background "grey35"
- :foreground "grey70"))
- "Face for current diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading-selection
- '((((class color) (background light))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "salmon4")
- (((class color) (background dark))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "LightSalmon3"))
- "Face for selected diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-lines-heading
- '((((class color) (background light))
- :inherit magit-diff-hunk-heading-highlight
- :background "LightSalmon3")
- (((class color) (background dark))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "grey80"
- :background "salmon4"))
- "Face for diff hunk heading when lines are marked."
- :group 'magit-faces)
-
-(defface magit-diff-lines-boundary
- '((t :inherit magit-diff-lines-heading))
- "Face for boundary of marked lines in diff hunk."
- :group 'magit-faces)
-
-(defface magit-diff-conflict-heading
- '((t :inherit magit-diff-hunk-heading))
- "Face for conflict markers."
- :group 'magit-faces)
-
-(defface magit-diff-added
- '((((class color) (background light))
- :background "#ddffdd"
- :foreground "#22aa22")
- (((class color) (background dark))
- :background "#335533"
- :foreground "#ddffdd"))
- "Face for lines in a diff that have been added."
- :group 'magit-faces)
-
-(defface magit-diff-removed
- '((((class color) (background light))
- :background "#ffdddd"
- :foreground "#aa2222")
- (((class color) (background dark))
- :background "#553333"
- :foreground "#ffdddd"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-our
- '((t :inherit magit-diff-removed))
- "Face for lines in a diff for our side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-base
- '((((class color) (background light))
- :background "#ffffcc"
- :foreground "#aaaa11")
- (((class color) (background dark))
- :background "#555522"
- :foreground "#ffffcc"))
- "Face for lines in a diff for the base side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-their
- '((t :inherit magit-diff-added))
- "Face for lines in a diff for their side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-context
- '((((class color) (background light)) :foreground "grey50")
- (((class color) (background dark)) :foreground "grey70"))
- "Face for lines in a diff that are unchanged."
- :group 'magit-faces)
-
-(defface magit-diff-added-highlight
- '((((class color) (background light))
- :background "#cceecc"
- :foreground "#22aa22")
- (((class color) (background dark))
- :background "#336633"
- :foreground "#cceecc"))
- "Face for lines in a diff that have been added."
- :group 'magit-faces)
-
-(defface magit-diff-removed-highlight
- '((((class color) (background light))
- :background "#eecccc"
- :foreground "#aa2222")
- (((class color) (background dark))
- :background "#663333"
- :foreground "#eecccc"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-our-highlight
- '((t :inherit magit-diff-removed-highlight))
- "Face for lines in a diff for our side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-base-highlight
- '((((class color) (background light))
- :background "#eeeebb"
- :foreground "#aaaa11")
- (((class color) (background dark))
- :background "#666622"
- :foreground "#eeeebb"))
- "Face for lines in a diff for the base side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-their-highlight
- '((t :inherit magit-diff-added-highlight))
- "Face for lines in a diff for their side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-context-highlight
- '((((class color) (background light))
- :background "grey95"
- :foreground "grey50")
- (((class color) (background dark))
- :background "grey20"
- :foreground "grey70"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-whitespace-warning
- '((t :inherit trailing-whitespace))
- "Face for highlighting whitespace errors added lines."
- :group 'magit-faces)
-
-(defface magit-diffstat-added
- '((((class color) (background light)) :foreground "#22aa22")
- (((class color) (background dark)) :foreground "#448844"))
- "Face for plus sign in diffstat."
- :group 'magit-faces)
-
-(defface magit-diffstat-removed
- '((((class color) (background light)) :foreground "#aa2222")
- (((class color) (background dark)) :foreground "#aa4444"))
- "Face for minus sign in diffstat."
- :group 'magit-faces)
-
-;;; Commands
-
-(defconst magit-diff-popup-common
- '(:variable magit-diff-arguments
- :man-page "git-diff"
- :options ((?f "Limit to files" "-- " magit-read-files)
- (?u "Context lines" "-U")
- (?m "Detect renames" "-M")
- (?c "Detect copies" "-C")
- (?a "Diff algorithm" "--diff-algorithm="
- magit-diff-select-algorithm))))
-
-(defvar magit-diff-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff")
- (?s "Show stats" "--stat"))
- :actions ((?d "Dwim" magit-diff-dwim)
- (?u "Diff unstaged" magit-diff-unstaged)
- (?c "Show commit" magit-show-commit)
- (?r "Diff range" magit-diff)
- (?s "Diff staged" magit-diff-staged)
- (?t "Show stash" magit-stash-show)
- (?p "Diff paths" magit-diff-paths)
- (?w "Diff worktree" magit-diff-working-tree))
- :default-action magit-diff-dwim
- :max-action-columns 3))
-
-(defvar magit-diff-refresh-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff"))
- :actions ((?g "Refresh" magit-diff-refresh)
- (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
- (?s "Set defaults" magit-diff-set-default-arguments) nil
- (?w "Save defaults" magit-diff-save-default-arguments))
- :max-action-columns 2))
-
-(defvar magit-diff-mode-refresh-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff")
- (?s "Show stats" "--stat"))
- :actions ((?g "Refresh" magit-diff-refresh)
- (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
- (?s "Set defaults" magit-diff-set-default-arguments)
- (?r "Switch range type" magit-diff-switch-range-type)
- (?w "Save defaults" magit-diff-save-default-arguments)
- (?f "Flip revisions" magit-diff-flip-revs))
- :max-action-columns 2))
-
-(defvar magit-revision-mode-refresh-popup
- `(,@magit-diff-popup-common
- :switches ((?f "Show surrounding functions" "--function-context")
- (?b "Ignore whitespace changes" "--ignore-space-change")
- (?w "Ignore all whitespace" "--ignore-all-space")
- (?x "Disallow external diff drivers" "--no-ext-diff")
- (?s "Show stats" "--stat"))
- :actions ((?g "Refresh" magit-diff-refresh)
- (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
- (?s "Set defaults" magit-diff-set-default-arguments) nil
- (?w "Save defaults" magit-diff-save-default-arguments))
- :max-action-columns 2))
-
-(magit-define-popup-keys-deferred 'magit-diff-popup)
-(magit-define-popup-keys-deferred 'magit-diff-refresh-popup)
-(magit-define-popup-keys-deferred 'magit-diff-mode-refresh-popup)
-(magit-define-popup-keys-deferred 'magit-revision-mode-refresh-popup)
-
-(defcustom magit-diff-arguments '("--stat" "--no-ext-diff")
- "The diff arguments used in buffers whose mode derives from `magit-diff-mode'."
- :group 'magit-diff
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-diff-section-arguments '("--no-ext-diff")
- "The diff arguments used in buffers that show other things besides diffs."
- :group 'magit-diff
- :group 'magit-status
- :type '(repeat (string :tag "Argument")))
-
-(defvar magit-diff-section-file-args nil)
-(put 'magit-diff-section-file-args 'permanent-local t)
-(put 'magit-diff-section-arguments 'permanent-local t)
-
-(defun magit-diff-arguments (&optional refresh)
- (cond ((memq magit-current-popup '(magit-diff-popup magit-diff-refresh-popup))
- (magit-popup-export-file-args magit-current-popup-args))
- ((derived-mode-p 'magit-diff-mode)
- (list (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args)))
- (refresh
- (list magit-diff-section-arguments
- magit-diff-section-file-args))
- (t
- (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
- (with-current-buffer buffer
- (list (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args)))
- (list (default-value 'magit-diff-arguments) nil)))))
-
-;;;###autoload
-(defun magit-diff-popup (arg)
- "Popup console for diff commands."
- (interactive "P")
- (let ((magit-diff-arguments
- ;; We cannot possibly know what suffix command the user is
- ;; about to invoke, so we also don't know from which buffer
- ;; we should get the current values. However it is much
- ;; more likely that we will end up updating the diff buffer,
- ;; and we therefore use the value from that buffer.
- (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
- (with-current-buffer buffer
- (magit-popup-import-file-args (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args)))
- (default-value 'magit-diff-arguments))))
- (magit-invoke-popup 'magit-diff-popup nil arg)))
-
-;;;###autoload
-(defun magit-diff-buffer-file-popup ()
- "Popup console for diff commands.
-
-This is a variant of `magit-diff-popup' which shows the same popup
-but which limits the diff to the file being visited in the current
-buffer."
- (interactive)
- (-if-let (file (magit-file-relative-name))
- (let ((magit-diff-arguments
- (magit-popup-import-file-args
- (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
- (with-current-buffer buffer
- (nth 3 magit-refresh-args))
- (default-value 'magit-diff-arguments))
- (list file))))
- (magit-invoke-popup 'magit-diff-popup nil nil))
- (user-error "Buffer isn't visiting a file")))
-
-(defun magit-diff-refresh-popup (arg)
- "Popup console for changing diff arguments in the current buffer."
- (interactive "P")
- (let ((magit-diff-refresh-popup
- (pcase major-mode
- (`magit-revision-mode magit-revision-mode-refresh-popup)
- (`magit-diff-mode magit-diff-mode-refresh-popup)
- (_ magit-diff-refresh-popup)))
- (magit-diff-arguments
- (if (derived-mode-p 'magit-diff-mode)
- (magit-popup-import-file-args (nth 2 magit-refresh-args)
- (nth 3 magit-refresh-args))
- (magit-popup-import-file-args magit-diff-section-arguments
- magit-diff-section-file-args))))
- (magit-invoke-popup 'magit-diff-refresh-popup nil arg)))
-
-(defun magit-diff-select-algorithm (&rest _ignore)
- (magit-read-char-case nil t
- (?d "[d]efault" "default")
- (?m "[m]inimal" "minimal")
- (?p "[p]atience" "patience")
- (?h "[h]istogram" "histogram")))
-
-;;;###autoload
-(defun magit-diff-dwim (&optional args files)
- "Show changes for the thing at point."
- (interactive (magit-diff-arguments))
- (pcase (magit-diff--dwim)
- (`unstaged (magit-diff-unstaged args files))
- (`staged (magit-diff-staged nil args files))
- (`(commit . ,value)
- (magit-diff (format "%s^..%s" value value) args files))
- (`(stash . ,value) (magit-stash-show value args))
- ((and range (pred stringp))
- (magit-diff range args files))
- (_
- (call-interactively #'magit-diff))))
-
-(defun magit-diff--dwim ()
- "Return information for performing DWIM diff.
-
-The information can be in three forms:
-1. TYPE
- A symbol describing a type of diff where no additional information
- is needed to generate the diff. Currently, this includes `staged'
- and `unstaged'.
-2. (TYPE . VALUE)
- Like #1 but the diff requires additional information, which is
- given by VALUE. Currently, this includes `commit' and `stash',
- where VALUE is the given commit or stash, respectively.
-3. RANGE
- A string indicating a diff range.
-
-If no DWIM context is found, nil is returned."
- (cond
- ((--when-let (magit-region-values 'commit 'branch)
- (deactivate-mark)
- (concat (car (last it)) ".." (car it))))
- (magit-buffer-refname
- (cons 'commit magit-buffer-refname))
- ((derived-mode-p 'magit-revision-mode)
- (cons 'commit (car magit-refresh-args)))
- ((derived-mode-p 'magit-diff-mode)
- (nth 0 magit-refresh-args))
- (t
- (magit-section-case
- ([* unstaged] 'unstaged)
- ([* staged] 'staged)
- (unpushed (magit-section-value it))
- (unpulled (magit-section-value it))
- (branch (let ((current (magit-get-current-branch))
- (atpoint (magit-section-value it)))
- (if (equal atpoint current)
- (--if-let (magit-get-upstream-branch)
- (format "%s...%s" it current)
- (if (magit-anything-modified-p)
- current
- (cons 'commit current)))
- (format "%s..%s" atpoint current))))
- (commit (cons 'commit (magit-section-value it)))
- (stash (cons 'stash (magit-section-value it)))))))
-
-(defun magit-diff-read-range-or-commit (prompt &optional secondary-default mbase)
- "Read range or revision with special diff range treatment.
-If MBASE is non-nil, prompt for which rev to place at the end of
-a \"revA...revB\" range. Otherwise, always construct
-\"revA..revB\" range."
- (--if-let (magit-region-values 'commit 'branch)
- (let ((revA (car (last it)))
- (revB (car it)))
- (deactivate-mark)
- (if mbase
- (let ((base (magit-git-string "merge-base" revA revB)))
- (cond
- ((string= (magit-rev-parse revA) base)
- (format "%s..%s" revA revB))
- ((string= (magit-rev-parse revB) base)
- (format "%s..%s" revB revA))
- (t
- (let ((main (magit-completing-read "View changes along"
- (list revA revB)
- nil t nil nil revB)))
- (format "%s...%s"
- (if (string= main revB) revA revB) main)))))
- (format "%s..%s" revA revB)))
- (magit-read-range prompt
- (or (pcase (magit-diff--dwim)
- (`(commit . ,value)
- (format "%s^..%s" value value))
- ((and range (pred stringp))
- range))
- secondary-default
- (magit-get-current-branch)))))
-
-(defun magit-diff-setup (rev-or-range const args files)
- (require 'magit)
- (magit-mode-setup #'magit-diff-mode rev-or-range const args files))
-
-;;;###autoload
-(defun magit-diff (rev-or-range &optional args files)
- "Show differences between two commits.
-
-REV-OR-RANGE should be a range or a single revision. If it is a
-revision, then show changes in the working tree relative to that
-revision. If it is a range, but one side is omitted, then show
-changes relative to `HEAD'.
-
-If the region is active, use the revisions on the first and last
-line of the region as the two sides of the range. With a prefix
-argument, instead of diffing the revisions, choose a revision to
-view changes along, starting at the common ancestor of both
-revisions (i.e., use a \"...\" range)."
- (interactive (cons (magit-diff-read-range-or-commit "Diff for range"
- nil current-prefix-arg)
- (magit-diff-arguments)))
- (magit-diff-setup rev-or-range nil args files))
-
-;;;###autoload
-(defun magit-diff-working-tree (&optional rev args files)
- "Show changes between the current working tree and the `HEAD' commit.
-With a prefix argument show changes between the working tree and
-a commit read from the minibuffer."
- (interactive
- (cons (and current-prefix-arg
- (magit-read-branch-or-commit "Diff working tree and commit"))
- (magit-diff-arguments)))
- (magit-diff-setup (or rev "HEAD") nil args files))
-
-;;;###autoload
-(defun magit-diff-staged (&optional rev args files)
- "Show changes between the index and the `HEAD' commit.
-With a prefix argument show changes between the index and
-a commit read from the minibuffer."
- (interactive
- (cons (and current-prefix-arg
- (magit-read-branch-or-commit "Diff index and commit"))
- (magit-diff-arguments)))
- (magit-diff-setup rev (list "--cached") args files))
-
-;;;###autoload
-(defun magit-diff-unstaged (&optional args files)
- "Show changes between the working tree and the index."
- (interactive (magit-diff-arguments))
- (magit-diff-setup nil nil args files))
-
-;;;###autoload
-(defun magit-diff-while-committing (&optional args files)
- "While committing, show the changes that are about to be committed.
-While amending, invoking the command again toggles between
-showing just the new changes or all the changes that will
-be committed."
- (interactive (magit-diff-arguments))
- (let ((toplevel (magit-toplevel))
- (diff-buf (magit-mode-get-buffer 'magit-diff-mode)))
- (if (magit-commit-message-buffer)
- (if (and (or ;; most likely an explicit amend
- (not (magit-anything-staged-p))
- ;; explicitly toggled from within diff
- (and (eq (current-buffer) diff-buf)))
- (or (not diff-buf)
- (with-current-buffer diff-buf
- (or ;; default to include last commit
- (not (equal (magit-toplevel) toplevel))
- ;; toggle to include last commit
- (not (car magit-refresh-args))))))
- (magit-diff-while-amending args files)
- (magit-diff-staged nil args files))
- (user-error "No commit in progress"))))
-
-(define-key git-commit-mode-map
- (kbd "C-c C-d") 'magit-diff-while-committing)
-
-(defun magit-diff-while-amending (&optional args files)
- (magit-diff-setup "HEAD^" (list "--cached") args files))
-
-;;;###autoload
-(defun magit-diff-buffer-file ()
- "Show diff for the blob or file visited in the current buffer."
- (interactive)
- (-if-let (file (magit-file-relative-name))
- (magit-mode-setup-internal #'magit-diff-mode
- (list (or magit-buffer-refname
- (magit-get-current-branch)
- "HEAD")
- nil
- (cadr (magit-diff-arguments))
- (list file))
- magit-diff-buffer-file-locked)
- (user-error "Buffer isn't visiting a file")))
-
-;;;###autoload
-(defun magit-diff-paths (a b)
- "Show changes between any two files on disk."
- (interactive (list (read-file-name "First file: " nil nil t)
- (read-file-name "Second file: " nil nil t)))
- (magit-diff-setup nil (list "--no-index")
- nil (list (expand-file-name a)
- (expand-file-name b))))
-
-;;;###autoload
-(defun magit-show-commit (rev &optional args files module)
- "Show the revision at point.
-If there is no revision at point or with a prefix argument prompt
-for a revision."
- (interactive
- (let* ((mcommit (magit-section-when module-commit))
- (atpoint (or (and (bound-and-true-p magit-blame-mode)
- (magit-blame-chunk-get :hash))
- mcommit
- (magit-branch-or-commit-at-point)
- (magit-tag-at-point))))
- (nconc (cons (or (and (not current-prefix-arg) atpoint)
- (magit-read-branch-or-commit "Show commit" atpoint))
- (magit-diff-arguments))
- (and mcommit (list (magit-section-parent-value
- (magit-current-section)))))))
- (require 'magit)
- (magit-with-toplevel
- (when module
- (setq default-directory
- (expand-file-name (file-name-as-directory module))))
- (unless (magit-rev-verify-commit rev)
- (user-error "%s is not a commit" rev))
- (-when-let (buffer (magit-mode-get-buffer 'magit-revision-mode))
- (with-current-buffer buffer
- (let ((prev (car magit-refresh-args)))
- (unless (equal rev prev)
- (dolist (child (cdr (magit-section-children magit-root-section)))
- (when (eq (magit-section-type child) 'file)
- (magit-section-cache-visibility child)))))))
- (magit-mode-setup #'magit-revision-mode rev nil args files)))
-
-(defun magit-diff-refresh (args files)
- "Set the local diff arguments for the current buffer."
- (interactive (magit-diff-arguments t))
- (cond ((derived-mode-p 'magit-diff-mode)
- (setcdr (cdr magit-refresh-args) (list args files)))
- (t
- (setq-local magit-diff-section-arguments args)
- (setq-local magit-diff-section-file-args files)))
- (magit-refresh))
-
-(defun magit-diff-set-default-arguments (args files)
- "Set the global diff arguments for the current buffer."
- (interactive (magit-diff-arguments t))
- (cond ((derived-mode-p 'magit-diff-mode)
- (customize-set-variable 'magit-diff-arguments args)
- (setcdr (cdr magit-refresh-args) (list args files)))
- (t
- (customize-set-variable 'magit-diff-section-arguments args)
- (kill-local-variable 'magit-diff-section-arguments)
- (kill-local-variable 'magit-diff-section-file-args)))
- (magit-refresh))
-
-(defun magit-diff-save-default-arguments (args files)
- "Set and save the global diff arguments for the current buffer."
- (interactive (magit-diff-arguments t))
- (cond ((derived-mode-p 'magit-diff-mode)
- (customize-save-variable 'magit-diff-arguments args)
- (setcdr (cdr magit-refresh-args) (list args files)))
- (t
- (customize-save-variable 'magit-diff-section-arguments args)
- (kill-local-variable 'magit-diff-section-arguments)
- (kill-local-variable 'magit-diff-section-file-args)))
- (magit-refresh))
-
-(defun magit-diff-switch-range-type ()
- "Convert diff range type.
-Change \"revA..revB\" to \"revB...revA\", or vice versa."
- (interactive)
- (let ((range (car magit-refresh-args)))
- (if (and range
- (derived-mode-p 'magit-diff-mode)
- (string-match magit-range-re range))
- (progn
- (setcar magit-refresh-args
- (concat (match-string 1 range)
- (if (string= (match-string 2 range) "..")
- "..."
- "..")
- (match-string 3 range)))
- (magit-refresh))
- (user-error "No range to change"))))
-
-(defun magit-diff-flip-revs ()
- "Swap revisions in diff range.
-Change \"revA..revB\" to \"revB..revA\"."
- (interactive)
- (let ((range (car magit-refresh-args)))
- (if (and range
- (derived-mode-p 'magit-diff-mode)
- (string-match magit-range-re range))
- (progn
- (setcar magit-refresh-args
- (concat (match-string 3 range)
- (match-string 2 range)
- (match-string 1 range)))
- (magit-refresh))
- (user-error "No range to swap"))))
-
-(defun magit-diff-less-context (&optional count)
- "Decrease the context for diff hunks by COUNT lines."
- (interactive "p")
- (magit-diff-set-context `(lambda (cur) (max 0 (- (or cur 0) ,count)))))
-
-(defun magit-diff-more-context (&optional count)
- "Increase the context for diff hunks by COUNT lines."
- (interactive "p")
- (magit-diff-set-context `(lambda (cur) (+ (or cur 0) ,count))))
-
-(defun magit-diff-default-context ()
- "Reset context for diff hunks to the default height."
- (interactive)
- (magit-diff-set-context #'ignore))
-
-(defun magit-diff-set-context (fn)
- (let* ((def (--if-let (magit-get "diff.context") (string-to-number it) 3))
- (val (car (magit-diff-arguments t)))
- (arg (--first (string-match "^-U\\([0-9]+\\)?$" it) val))
- (num (--if-let (and arg (match-string 1 arg)) (string-to-number it) def))
- (val (delete arg val))
- (num (funcall fn num))
- (arg (and num (not (= num def)) (format "-U%i" num)))
- (val (if arg (cons arg val) val)))
- (if (derived-mode-p 'magit-diff-mode)
- (setcar (cddr magit-refresh-args) val)
- (setq magit-diff-section-arguments val)))
- (magit-refresh))
-
-(defun magit-diff-context-p ()
- (--if-let (--first (string-match "^-U\\([0-9]+\\)$" it)
- (car (magit-diff-arguments t)))
- (not (equal "-U0" it))
- t))
-
-(defun magit-diff-toggle-refine-hunk (&optional style)
- "Turn diff-hunk refining on or off.
-
-If hunk refining is currently on, then hunk refining is turned off.
-If hunk refining is off, then hunk refining is turned on, in
-`selected' mode (only the currently selected hunk is refined).
-
-With a prefix argument, the \"third choice\" is used instead:
-If hunk refining is currently on, then refining is kept on, but
-the refining mode (`selected' or `all') is switched.
-If hunk refining is off, then hunk refining is turned on, in
-`all' mode (all hunks refined).
-
-Customize variable `magit-diff-refine-hunk' to change the default mode."
- (interactive "P")
- (setq-local magit-diff-refine-hunk
- (if style
- (if (eq magit-diff-refine-hunk 'all) t 'all)
- (not magit-diff-refine-hunk)))
- (magit-diff-update-hunk-refinement))
-
-(defun magit-diff-visit-file (file &optional other-window force-worktree)
- "From a diff, visit the corresponding file at the appropriate position.
-
-When the file is already being displayed in another window of the
-same frame, then just select that window and adjust point. With
-a prefix argument also display in another window.
-
-If the diff shows changes in the worktree, the index, or `HEAD',
-then visit the actual file. Otherwise when the diff is about
-an older commit, then visit the respective blob using
-`magit-find-file'. Also see `magit-diff-visit-file-worktree'
-which, as the name suggests always visits the actual file."
- (interactive (list (--if-let (magit-file-at-point)
- (expand-file-name it)
- (user-error "No file at point"))
- current-prefix-arg))
- (if (magit-file-accessible-directory-p file)
- (magit-diff-visit-directory file other-window)
- (let ((current (magit-current-section))
- (rev (cond (force-worktree nil)
- ((derived-mode-p 'magit-revision-mode)
- (car magit-refresh-args))
- ((derived-mode-p 'magit-diff-mode)
- (--when-let (car magit-refresh-args)
- (and (string-match "\\.\\.\\([^.].*\\)?[ \t]*\\'" it)
- (match-string 1 it))))))
- (unmerged-p (magit-anything-unmerged-p file))
- hunk line col buffer)
- (when (and rev (magit-rev-head-p rev))
- (setq rev nil))
- (setq hunk
- (pcase (magit-diff-scope)
- ((or `hunk `region) current)
- ((or `file `files) (car (magit-section-children current)))
- (`list (car (magit-section-children
- (car (magit-section-children current)))))))
- (when (and hunk
- ;; Currently the `hunk' type is also abused for file
- ;; mode changes. Luckily such sections have no value.
- (magit-section-value hunk))
- (setq line (magit-diff-hunk-line hunk)
- col (magit-diff-hunk-column hunk)))
- (setq buffer (if rev
- (magit-find-file-noselect rev file)
- (or (get-file-buffer file)
- (find-file-noselect file))))
- (magit-display-file-buffer buffer)
- (with-current-buffer buffer
- (when line
- (goto-char (point-min))
- (forward-line (1- line))
- (when col
- (move-to-column col)))
- (when unmerged-p
- (smerge-start-session))
- (run-hooks 'magit-diff-visit-file-hook)))))
-
-(defvar magit-display-file-buffer-function
- 'magit-display-file-buffer-traditional
- "The function used by `magit-diff-visit-file' to display blob buffers.
-
-Other commands such as `magit-find-file' do not use this
-function. Instead they use high-level functions to select the
-window to be used to display the buffer. This variable and the
-related functions are an experimental feature and should be
-treated as such.")
-
-(defun magit-display-file-buffer (buffer)
- (funcall magit-display-file-buffer-function buffer))
-
-(defun magit-display-file-buffer-traditional (buffer)
- (if (or current-prefix-arg (get-buffer-window buffer))
- (pop-to-buffer buffer)
- (switch-to-buffer buffer)))
-
-(defun magit-diff-visit-file-worktree (file &optional other-window)
- "From a diff, visit the corresponding file at the appropriate position.
-
-When the file is already being displayed in another window of the
-same frame, then just select that window and adjust point. With
-a prefix argument also display in another window.
-
-The actual file in the worktree is visited. The positions in the
-hunk headers get less useful the \"older\" the changes are, and
-as a result, jumping to the appropriate position gets less
-reliable.
-
-Also see `magit-diff-visit-file' which visits the respective
-blob, unless the diff shows changes in the worktree, the index,
-or `HEAD'."
- (interactive (list (or (magit-file-at-point)
- (user-error "No file at point"))
- current-prefix-arg))
- (magit-diff-visit-file file other-window t))
-
-(defun magit-diff-hunk-line (section)
- (let* ((value (magit-section-value section))
- (prefix (- (length value) 2))
- (cpos (marker-position (magit-section-content section)))
- (stop (line-number-at-pos))
- (cstart (save-excursion (goto-char cpos) (line-number-at-pos)))
- (line (car (last value))))
- (string-match "^\\+\\([0-9]+\\)" line)
- (setq line (string-to-number (match-string 1 line)))
- (when (> cstart stop)
- (save-excursion
- (goto-char cpos)
- (re-search-forward "^[-+]")
- (setq stop (line-number-at-pos))))
- (save-excursion
- (goto-char cpos)
- (while (< (line-number-at-pos) stop)
- (unless (string-match-p
- "-" (buffer-substring (point) (+ (point) prefix)))
- (cl-incf line))
- (forward-line)))
- line))
-
-(defun magit-diff-hunk-column (section)
- (if (or (< (point) (magit-section-content section))
- (save-excursion (beginning-of-line) (looking-at-p "-")))
- 0
- (max 0 (- (+ (current-column) 2)
- (length (magit-section-value section))))))
-
-(defun magit-diff-visit-directory (directory &optional other-window)
- (if (equal (magit-toplevel directory)
- (magit-toplevel))
- (magit-dired-jump other-window)
- (let ((display-buffer-overriding-action
- (if other-window
- '(nil (inhibit-same-window t))
- '(display-buffer-same-window))))
- (magit-status-internal directory))))
-
-(defun magit-diff-show-or-scroll-up ()
- "Update the commit or diff buffer for the thing at point.
-
-Either show the commit or stash at point in the appropriate
-buffer, or if that buffer is already being displayed in the
-current frame and contains information about that commit or
-stash, then instead scroll the buffer up. If there is no
-commit or stash at point, then prompt for a commit."
- (interactive)
- (magit-diff-show-or-scroll 'scroll-up))
-
-(defun magit-diff-show-or-scroll-down ()
- "Update the commit or diff buffer for the thing at point.
-
-Either show the commit or stash at point in the appropriate
-buffer, or if that buffer is already being displayed in the
-current frame and contains information about that commit or
-stash, then instead scroll the buffer down. If there is no
-commit or stash at point, then prompt for a commit."
- (interactive)
- (magit-diff-show-or-scroll 'scroll-down))
-
-(defun magit-diff-show-or-scroll (fn)
- (let (rev cmd buf win)
- (cond
- (magit-blame-mode
- (setq rev (magit-blame-chunk-get :hash)
- cmd 'magit-show-commit
- buf (magit-mode-get-buffer 'magit-revision-mode)))
- ((derived-mode-p 'git-rebase-mode)
- (save-excursion
- (goto-char (line-beginning-position))
- (--if-let (and (looking-at git-rebase-line)
- (match-string 2))
- (setq rev it
- cmd 'magit-show-commit
- buf (magit-mode-get-buffer 'magit-revision-mode))
- (user-error "No commit on this line"))))
- (t
- (magit-section-case
- ((commit branch)
- (setq rev (magit-section-value it)
- cmd 'magit-show-commit
- buf (magit-mode-get-buffer 'magit-revision-mode)))
- (stash
- (setq rev (magit-section-value it)
- cmd 'magit-stash-show
- buf (magit-mode-get-buffer 'magit-stash-mode))))))
- (if rev
- (if (and buf
- (setq win (get-buffer-window buf))
- (with-current-buffer buf
- (equal rev (car magit-refresh-args))))
- (with-selected-window win
- (condition-case nil
- (funcall fn)
- (error
- (goto-char (pcase fn
- (`scroll-up (point-min))
- (`scroll-down (point-max)))))))
- (let ((magit-display-buffer-noselect t))
- (if (eq cmd 'magit-show-commit)
- (apply #'magit-show-commit rev (magit-diff-arguments))
- (funcall cmd rev))))
- (call-interactively #'magit-show-commit))))
-
-;;; Diff Mode
-
-(defvar magit-diff-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-c\C-d" 'magit-diff-while-committing)
- (define-key map "\C-c\C-b" 'magit-go-backward)
- (define-key map "\C-c\C-f" 'magit-go-forward)
- (define-key map "\s" 'scroll-up)
- (define-key map "\d" 'scroll-down)
- (define-key map "j" 'magit-jump-to-diffstat-or-diff)
- map)
- "Keymap for `magit-diff-mode'.")
-
-(define-derived-mode magit-diff-mode magit-mode "Magit Diff"
- "Mode for looking at a Git diff.
-
-This mode is documented in info node `(magit)Diff buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] to visit the hunk or file at point.
-
-Staging and applying changes is documented in info node
-`(magit)Staging and unstaging' and info node `(magit)Applying'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\{magit-diff-mode-map}"
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-diff-refresh-buffer (rev-or-range const _args files)
- "Refresh the current `magit-diff-mode' buffer.
-
-In such buffers the buffer-local value of `magit-refresh-args'
-has the same form as the arguments of this function. The value
-is set in `magit-mode-setup'."
- (setq header-line-format
- (propertize
- (if (member "--no-index" const)
- (apply #'format " Differences between %s and %s" files)
- (concat (if rev-or-range
- (if (string-match-p "\\.\\." rev-or-range)
- (format " Changes in %s" rev-or-range)
- (format " Changes from %s to working tree" rev-or-range))
- (if (member "--cached" const)
- " Staged changes"
- " Unstaged changes"))
- (pcase (length files)
- (0)
- (1 (concat " in file " (car files)))
- (_ (concat " in files "
- (mapconcat #'identity files ", "))))))
- 'face 'magit-header-line))
- (magit-insert-section (diffbuf)
- (run-hook-with-args 'magit-diff-sections-hook rev-or-range)))
-
-(defun magit-insert-diff (rev-or-range)
- "Insert the diff into this `magit-diff-mode' buffer."
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" rev-or-range "-p" "--no-prefix"
- (and (member "--stat" (nth 2 magit-refresh-args)) "--numstat")
- (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args) "--"
- (nth 3 magit-refresh-args)))
-
-(defvar magit-file-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [C-return] 'magit-diff-visit-file-worktree)
- (define-key map "\C-j" 'magit-diff-visit-file-worktree)
- (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "a" 'magit-apply)
- (define-key map "C" 'magit-commit-add-log)
- (define-key map "K" 'magit-file-untrack)
- (define-key map "R" 'magit-file-rename)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for `file' sections.")
-
-(defvar magit-hunk-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [C-return] 'magit-diff-visit-file-worktree)
- (define-key map "\C-j" 'magit-diff-visit-file-worktree)
- (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "a" 'magit-apply)
- (define-key map "C" 'magit-commit-add-log)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for `hunk' sections.")
-
-(defconst magit-diff-headline-re
- (concat "^\\(@@@?\\|diff\\|Submodule\\|"
- "\\* Unmerged path\\|merged\\|changed in both\\|"
- "added in remote\\|removed in remote\\)"))
-
-(defconst magit-diff-statline-re
- (concat "^ ?"
- "\\(.*\\)" ; file
- "\\( +| +\\)" ; separator
- "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?"
- "\\(\\+*\\)" ; add
- "\\(-*\\)$")) ; del
-
-(defun magit-diff-wash-diffs (args &optional limit)
- (when (member "--stat" args)
- (magit-diff-wash-diffstat))
- (when (re-search-forward magit-diff-headline-re limit t)
- (goto-char (line-beginning-position))
- (magit-wash-sequence (apply-partially 'magit-diff-wash-diff args))
- (insert ?\n)))
-
-(defun magit-jump-to-diffstat-or-diff ()
- "Jump to the diffstat or diff.
-When point is on a file inside the diffstat section, then jump
-to the respective diff section, otherwise jump to the diffstat
-section or a child thereof."
- (interactive)
- (--if-let (magit-get-section
- (append (magit-section-case
- ([file diffstat] `((file . ,(magit-section-value it))))
- (file `((file . ,(magit-section-value it)) (diffstat)))
- (t '((diffstat))))
- (magit-section-ident magit-root-section)))
- (magit-section-goto it)
- (user-error "No diffstat in this buffer")))
-
-(defun magit-diff-wash-diffstat ()
- (let (heading (beg (point)))
- (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t)
- (setq heading (match-string 1))
- (magit-delete-match)
- (goto-char beg)
- (magit-insert-section it (diffstat)
- (insert (propertize heading 'face 'magit-diff-file-heading))
- (magit-insert-heading)
- (let (files)
- (while (looking-at "^[-0-9]+\t[-0-9]+\t\\(.+\\)$")
- (push (magit-decode-git-path (match-string 1)) files)
- (magit-delete-line))
- (setq files (nreverse files))
- (while (looking-at magit-diff-statline-re)
- (magit-bind-match-strings (file sep cnt add del) nil
- (magit-delete-line)
- (when (string-match " +$" file)
- (setq sep (concat (match-string 0 file) sep))
- (setq file (substring file 0 (match-beginning 0))))
- (let ((le (length file)) ld)
- (setq file (magit-decode-git-path file))
- (setq ld (length file))
- (when (> le ld)
- (setq sep (concat (make-string (- le ld) ?\s) sep))))
- (magit-insert-section (file (pop files))
- (insert (propertize file 'face 'magit-filename) sep cnt " ")
- (when add
- (insert (propertize add 'face 'magit-diffstat-added)))
- (when del
- (insert (propertize del 'face 'magit-diffstat-removed)))
- (insert "\n")))))
- (if (looking-at "^$") (forward-line) (insert "\n"))))))
-
-(defun magit-diff-wash-diff (args)
- (cond
- ((looking-at "^Submodule")
- (magit-diff-wash-submodule))
- ((looking-at "^\\* Unmerged path \\(.*\\)")
- (let ((file (magit-decode-git-path (match-string 1))))
- (magit-delete-line)
- (unless (and (derived-mode-p 'magit-status-mode)
- (not (member "--cached" args)))
- (magit-insert-section (file file)
- (insert (propertize
- (format "unmerged %s%s" file
- (pcase (cddr (car (magit-file-status file)))
- (`(?D ?D) " (both deleted)")
- (`(?D ?U) " (deleted by us)")
- (`(?U ?D) " (deleted by them)")
- (`(?A ?A) " (both added)")
- (`(?A ?U) " (added by us)")
- (`(?U ?A) " (added by them)")
- (`(?U ?U) "")))
- 'face 'magit-diff-file-heading))
- (insert ?\n))))
- t)
- ((looking-at (concat "^\\(merged\\|changed in both\\|"
- "added in remote\\|removed in remote\\)"))
- (let ((status (pcase (match-string 1)
- ("merged" "merged")
- ("changed in both" "conflict")
- ("added in remote" "new file")
- ("removed in remote" "deleted")))
- file orig base modes)
- (magit-delete-line)
- (while (looking-at
- "^ \\([^ ]+\\) +[0-9]\\{6\\} \\([a-z0-9]\\{40\\}\\) \\(.+\\)$")
- (magit-bind-match-strings (side _blob name) nil
- (pcase side
- ("result" (setq file name))
- ("our" (setq orig name))
- ("their" (setq file name))
- ("base" (setq base name))))
- (magit-delete-line))
- (when orig (setq orig (magit-decode-git-path orig)))
- (when file (setq file (magit-decode-git-path file)))
- (magit-diff-insert-file-section (or file base) orig status modes nil)))
- ((looking-at
- "^diff --\\(?:\\(git\\) \\(?:\\(.+?\\) \\2\\)?\\|\\(cc\\|combined\\) \\(.+\\)\\)")
- (let ((status (cond ((equal (match-string 1) "git") "modified")
- ((derived-mode-p 'magit-revision-mode) "resolved")
- (t "unmerged")))
- (file (or (match-string 2) (match-string 4)))
- (beg (point))
- orig header modes)
- (save-excursion
- (forward-line 1)
- (setq header (buffer-substring
- beg (if (re-search-forward magit-diff-headline-re nil t)
- (match-beginning 0)
- (point-max)))))
- (magit-delete-line)
- (while (not (or (eobp) (looking-at magit-diff-headline-re)))
- (if (looking-at "^old mode \\([^\n]+\\)\nnew mode \\([^\n]+\\)\n")
- (progn (setq modes (match-string 0))
- (magit-delete-match))
- (cond
- ((looking-at "^--- \\([^/].*?\\)\t?$") ; i.e. not /dev/null
- (setq orig (match-string 1)))
- ((looking-at "^\\+\\+\\+ \\([^/].*?\\)\t?$")
- (setq file (match-string 1)))
- ((looking-at "^\\(copy\\|rename\\) from \\(.+\\)$")
- (setq orig (match-string 2)))
- ((looking-at "^\\(copy\\|rename\\) to \\(.+\\)$")
- (setq file (match-string 2))
- (setq status (if (equal (match-string 1) "copy") "new file" "renamed")))
- ((looking-at "^\\(new file\\|deleted\\)")
- (setq status (match-string 1))))
- (magit-delete-line)))
- (when orig
- (setq orig (magit-decode-git-path orig)))
- (setq file (magit-decode-git-path file))
- ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used.
- (when (and (derived-mode-p 'magit-log-mode)
- (--first (string-match-p "\\`-L" it)
- (nth 1 magit-refresh-args)))
- (setq file (substring file 2))
- (when orig
- (setq orig (substring orig 2))))
- (magit-diff-insert-file-section file orig status modes header)))))
-
-(defun magit-diff-insert-file-section (file orig status modes header)
- (magit-insert-section section
- (file file (or (equal status "deleted")
- (derived-mode-p 'magit-status-mode)))
- (insert (propertize (format "%-10s %s\n" status
- (if (or (not orig) (equal orig file))
- file
- (format "%s -> %s" orig file)))
- 'face 'magit-diff-file-heading))
- (magit-insert-heading)
- (unless (equal orig file)
- (setf (magit-section-source section) orig))
- (setf (magit-section-diff-header section) header)
- (when modes
- (magit-insert-section (hunk)
- (insert modes)))
- (magit-wash-sequence #'magit-diff-wash-hunk)))
-
-(defun magit-diff-wash-submodule ()
- ;; See `show_submodule_summary' in submodule.c and "this" commit.
- (when (looking-at "^Submodule \\([^ ]+\\)")
- (let ((module (match-string 1))
- untracked modified)
- (when (looking-at "^Submodule [^ ]+ contains untracked content$")
- (magit-delete-line)
- (setq untracked t))
- (when (looking-at "^Submodule [^ ]+ contains modified content$")
- (magit-delete-line)
- (setq modified t))
- (cond
- ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ :]+\\)\\( (rewind)\\)?:$")
- (equal (match-string 1) module))
- (magit-bind-match-strings (_module range rewind) nil
- (magit-delete-line)
- (while (looking-at "^ \\([<>]\\) \\(.+\\)$")
- (magit-delete-line))
- (when rewind
- (setq range (replace-regexp-in-string "[^.]\\(\\.\\.\\)[^.]"
- "..." range t t 1)))
- (magit-insert-section (file module t)
- (magit-insert-heading
- (concat (propertize (concat "modified " module)
- 'face 'magit-diff-file-heading)
- " ("
- (cond (rewind "rewind")
- ((string-match-p "\\.\\.\\." range) "non-ff")
- (t "new commits"))
- (and (or modified untracked)
- (concat ", "
- (and modified "modified")
- (and modified untracked " and ")
- (and untracked "untracked")
- " content"))
- ")"))
- (let ((default-directory
- (file-name-as-directory
- (expand-file-name module (magit-toplevel)))))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'module)
- "log" "--oneline" "--left-right" range)
- (delete-char -1)))))
- ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ ]+\\) (\\([^)]+\\))$")
- (equal (match-string 1) module))
- (magit-bind-match-strings (_module _range msg) nil
- (magit-delete-line)
- (magit-insert-section (file module)
- (magit-insert-heading
- (concat (propertize (concat "submodule " module)
- 'face 'magit-diff-file-heading)
- " (" msg ")")))))
- (t
- (magit-insert-section (file module)
- (magit-insert-heading
- (concat (propertize (concat "modified " module)
- 'face 'magit-diff-file-heading)
- " ("
- (and modified "modified")
- (and modified untracked " and ")
- (and untracked "untracked")
- " content)"))))))))
-
-(defun magit-diff-wash-hunk ()
- (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?")
- (let ((heading (match-string 0))
- (value (cons (match-string 2) (split-string (match-string 1)))))
- (magit-delete-line)
- (magit-insert-section it (hunk value)
- (insert (propertize (concat heading "\n") 'face 'magit-diff-hunk-heading))
- (magit-insert-heading)
- (while (not (or (eobp) (looking-at "^[^-+\s\\]")))
- (forward-line))
- (setf (magit-section-end it) (point))
- (setf (magit-section-washer it) #'magit-diff-paint-hunk)))
- t))
-
-(defun magit-diff-expansion-threshold (section)
- "Keep new diff sections collapsed if washing takes too long."
- (and (memq (magit-section-type section) '(file))
- (> (float-time (time-subtract (current-time) magit-refresh-start-time))
- magit-diff-expansion-threshold)
- 'hide))
-
-;;; Revision Mode
-
-(define-derived-mode magit-revision-mode magit-diff-mode "Magit Rev"
- "Mode for looking at a Git commit.
-
-This mode is documented in info node `(magit)Revision buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] to visit the hunk or file at point.
-
-Staging and applying changes is documented in info node
-`(magit)Staging and unstaging' and info node `(magit)Applying'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\{magit-revision-mode-map}"
- :group 'magit-revision
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-revision-refresh-buffer (rev __const _args files)
- (setq header-line-format
- (propertize (concat " " (capitalize (magit-object-type rev))
- " " rev
- (pcase (length files)
- (0)
- (1 (concat " in file " (car files)))
- (_ (concat " in files "
- (mapconcat #'identity files ", ")))))
- 'face 'magit-header-line))
- (magit-insert-section (commitbuf)
- (run-hook-with-args 'magit-revision-sections-hook rev)))
-
-(defun magit-insert-revision-diff (rev)
- "Insert the diff into this `magit-revision-mode' buffer."
- ;; Before v2.2.0, "--format=" did not mean "no output".
- ;; Instead the default format was used. So use "--format=%n"
- ;; and then delete the empty lines.
- (magit-git-wash (lambda (args)
- (delete-region (point) (progn (forward-line 3) (point)))
- (magit-diff-wash-diffs args))
- "show" "-p" "--cc" "--format=%n" "--no-prefix"
- (and (member "--stat" (nth 2 magit-refresh-args)) "--numstat")
- (nth 2 magit-refresh-args) (concat rev "^{commit}") "--"
- (nth 3 magit-refresh-args)))
-
-(defun magit-insert-revision-tag (rev)
- "Insert tag message and headers into a revision buffer.
-This function only inserts anything when `magit-show-commit' is
-called with a tag as argument, when that is called with a commit
-or a ref which is not a branch, then it inserts nothing."
- (when (equal (magit-object-type rev) "tag")
- (magit-insert-section (taginfo)
- (let ((beg (point)))
- (magit-git-insert "cat-file" "tag" rev)
- (goto-char beg)
- (forward-line 3)
- (delete-region beg (point)))
- (looking-at "^tagger \\([^<]+\\) <\\([^>]+\\)")
- (let ((heading (format "Tagger: %s <%s>"
- (match-string 1)
- (match-string 2))))
- (magit-delete-line)
- (insert (propertize heading 'face 'magit-section-secondary-heading)))
- (magit-insert-heading)
- (goto-char (point-max))
- (insert ?\n))))
-
-(defun magit-insert-revision-message (rev)
- "Insert the commit message into a revision buffer."
- (magit-insert-section (message)
- (let ((beg (point)))
- (magit-rev-insert-format "%B" rev)
- (if (= (point) (+ beg 2))
- (progn (backward-delete-char 2)
- (insert "(no message)\n"))
- (goto-char beg)
- (while (search-forward "\r\n" nil t) ; Remove trailing CRs.
- (delete-region (match-beginning 0) (1+ (match-beginning 0))))
- (goto-char beg)
- (forward-line)
- (put-text-property beg (point) 'face 'magit-section-secondary-heading)
- (magit-insert-heading)
- (goto-char (point-max))))))
-
-(defun magit-insert-revision-notes (rev)
- "Insert commit notes into a revision buffer."
- (magit-insert-section (notes)
- (let ((beg (point)))
- (magit-git-insert "notes" "show" rev)
- (if (= (point) beg)
- (magit-cancel-section)
- (goto-char beg)
- (forward-line)
- (put-text-property beg (point) 'face 'magit-section-secondary-heading)
- (magit-insert-heading)
- (goto-char (point-max))
- (insert ?\n)))))
-
-(defun magit-insert-revision-headers (rev)
- "Insert headers about the commit into a revision buffer."
- (magit-insert-section (headers)
- ;; Before v2.2.0, "%D" was not supported.
- (--when-let (magit-rev-format "%d" rev "--decorate=full")
- (insert (magit-format-ref-labels (substring it 2 -1)) ?\s))
- (insert (propertize (magit-rev-parse (concat rev "^{commit}"))
- 'face 'magit-hash))
- (magit-insert-heading)
- (let ((beg (point)))
- (magit-rev-insert-format magit-revision-headers-format rev)
- (magit-insert-revision-gravatars rev beg))
- (when magit-revision-insert-related-refs
- (dolist (parent (magit-commit-parents rev))
- (magit-insert-section (commit parent)
- (let ((line (magit-rev-format "%h %s" parent)))
- (string-match "^\\([^ ]+\\) \\(.*\\)" line)
- (magit-bind-match-strings (hash msg) line
- (insert "Parent: ")
- (insert (propertize hash 'face 'magit-hash))
- (insert " " msg "\n")))))
- (-when-let (merged (magit-list-merged-branches rev))
- (insert "Merged: ")
- (let (branch)
- (while (and (< (+ (- (point) (line-beginning-position))
- (length (car merged)) 9)
- (window-width))
- (setq branch (pop merged)))
- (insert ?\s)
- (magit-insert-section (branch branch)
- (insert (propertize branch 'face 'magit-branch-local)))))
- (when merged
- (insert (format " (%s more)" (length merged))))
- (insert ?\n))
- (-when-let (containing (magit-list-containing-branches rev))
- (insert "Containing:")
- (let (branch)
- (while (and (< (+ (- (point) (line-beginning-position))
- (length (car containing)) 9)
- (window-width))
- (setq branch (pop containing)))
- (insert ?\s)
- (magit-insert-section (branch branch)
- (insert (propertize branch 'face 'magit-branch-local)))))
- (when containing
- (insert (format " (%s more)" (length containing))))
- (insert ?\n))
- (-when-let (follows (magit-get-current-tag rev t))
- (let ((tag (car follows))
- (cnt (cadr follows)))
- (magit-insert-section (tag tag)
- (insert (format "Follows: %s (%s)\n"
- (propertize tag 'face 'magit-tag)
- (propertize (number-to-string cnt)
- 'face 'magit-branch-local))))))
- (-when-let (precedes (magit-get-next-tag rev t))
- (let ((tag (car precedes))
- (cnt (cadr precedes)))
- (magit-insert-section (tag tag)
- (insert (format "Precedes: %s (%s)\n"
- (propertize tag 'face 'magit-tag)
- (propertize (number-to-string cnt)
- 'face 'magit-tag))))))
- (insert ?\n))))
-
-(defun magit-insert-revision-gravatars (rev beg)
- (when (and magit-revision-show-gravatars (window-system))
- (require 'gravatar)
- (magit-insert-revision-gravatar beg (magit-rev-format "%aE" rev)
- (car magit-revision-show-gravatars))
- (magit-insert-revision-gravatar beg (magit-rev-format "%cE" rev)
- (cdr magit-revision-show-gravatars))
- (goto-char (point-max))))
-
-(defun magit-insert-revision-gravatar (beg email regexp)
- (when (and email (goto-char beg) (re-search-forward regexp nil t))
- (ignore-errors
- (let* ((offset (length (match-string 0)))
- (font-obj (query-font (font-at (point) (get-buffer-window))))
- (size (* 2 (+ (aref font-obj 4) (aref font-obj 5))))
- (align-to (+ offset (ceiling (/ size (aref font-obj 7) 1.0))))
- (gravatar-size (- size 2))
- (slice1 '(slice .0 .0 1.0 0.5))
- (slice2 '(slice .0 .5 1.0 1.0)))
- (gravatar-retrieve
- email
- (lambda (image offset align-to slice1 slice2)
- (unless (eq image 'error)
- (insert (propertize " " 'display `((,@image :ascent center :relief 1)
- ,slice1)))
- (insert (propertize " " 'display `((space :align-to ,align-to))))
- (forward-line)
- (forward-char offset)
- (insert (propertize " " 'display `((,@image :ascent center :relief 1)
- ,slice2)))
- (insert (propertize " " 'display `((space :align-to ,align-to))))))
- (list offset align-to
- (if magit-revision-use-gravatar-kludge slice2 slice1)
- (if magit-revision-use-gravatar-kludge slice1 slice2)))))))
-
-;;; Diff Sections
-
-(defvar magit-unstaged-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-unstaged)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for the `unstaged' section.")
-
-(magit-define-section-jumper magit-jump-to-unstaged "Unstaged changes" unstaged)
-
-(defun magit-insert-unstaged-changes ()
- "Insert section showing unstaged changes."
- (magit-insert-section (unstaged)
- (magit-insert-heading "Unstaged changes:")
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" magit-diff-section-arguments "--no-prefix"
- "--" magit-diff-section-file-args)))
-
-(defvar magit-staged-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-staged)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for the `staged' section.")
-
-(magit-define-section-jumper magit-jump-to-staged "Staged changes" staged)
-
-(defun magit-insert-staged-changes ()
- "Insert section showing staged changes."
- (magit-insert-section (staged)
- (magit-insert-heading "Staged changes:")
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" "--cached" magit-diff-section-arguments "--no-prefix"
- "--" magit-diff-section-file-args)))
-
-;;; Diff Type
-
-(defun magit-diff-type (&optional section)
- "Return the diff type of SECTION.
-
-The returned type is one of the symbols `staged', `unstaged',
-`committed', or `undefined'. This type serves a similar purpose
-as the general type common to all sections (which is stored in
-the `type' slot of the corresponding `magit-section' struct) but
-takes additional information into account. When the SECTION
-isn't related to diffs and the buffer containing it also isn't
-a diff-only buffer, then return nil.
-
-Currently the type can also be one of `tracked' and `untracked'
-but these values are not handled explicitly everywhere they
-should be and a possible fix could be to just return nil here.
-
-The section has to be a `diff' or `hunk' section, or a section
-whose children are of type `diff'. If optional SECTION is nil,
-return the diff type for the current section. In buffers whose
-major mode is `magit-diff-mode' SECTION is ignored and the type
-is determined using other means. In `magit-revision-mode'
-buffers the type is always `committed'.
-
-Do not confuse this with `magit-diff-scope' (which see)."
- (--when-let (or section (magit-current-section))
- (cond ((derived-mode-p 'magit-revision-mode 'magit-stash-mode) 'committed)
- ((derived-mode-p 'magit-diff-mode)
- (let ((range (nth 0 magit-refresh-args))
- (const (nth 1 magit-refresh-args)))
- (cond ((member "--no-index" const) 'undefined)
- ((not range)
- (if (member "--cached" const)
- 'staged
- 'unstaged))
- ((member "--cached" const)
- (if (magit-rev-head-p range)
- 'staged
- 'undefined)) ; i.e. committed and staged
- (t 'committed))))
- ((derived-mode-p 'magit-status-mode)
- (let ((stype (magit-section-type it)))
- (if (memq stype '(staged unstaged tracked untracked))
- stype
- (pcase stype
- (`file (let* ((parent (magit-section-parent it))
- (type (magit-section-type parent)))
- (if (eq type 'file)
- (magit-diff-type parent)
- type)))
- (`hunk (-> it magit-section-parent magit-section-parent
- magit-section-type))))))
- ((derived-mode-p 'magit-log-mode)
- (if (or (and (magit-section-match 'commit section)
- (magit-section-children section))
- (magit-section-match [* file commit] section))
- 'committed
- 'undefined))
- (t 'undefined))))
-
-(cl-defun magit-diff-scope (&optional (section nil ssection) strict)
- "Return the diff scope of SECTION or the selected section(s).
-
-A diff's \"scope\" describes what part of a diff is selected, it is
-a symbol, one of `region', `hunk', `hunks', `file', `files', or
-`list'. Do not confuse this with the diff \"type\", as returned by
-`magit-diff-type'.
-
-If optional SECTION is non-nil, then return the scope of that,
-ignoring the sections selected by the region. Otherwise return
-the scope of the current section, or if the region is active and
-selects a valid group of diff related sections, the type of these
-sections, i.e. `hunks' or `files'. If SECTION, or if that is nil
-the current section, is a `hunk' section; and the region region
-starts and ends inside the body of a that section, then the type
-is `region'.
-
-If optional STRICT is non-nil then return nil if the diff type of
-the section at point is `untracked' or the section at point is not
-actually a `diff' but a `diffstat' section."
- (let ((siblings (and (not ssection) (magit-region-sections))))
- (setq section (or section (car siblings) (magit-current-section)))
- (when (and section
- (or (not strict)
- (and (not (eq (magit-diff-type section) 'untracked))
- (not (eq (--when-let (magit-section-parent section)
- (magit-section-type it))
- 'diffstat)))))
- (pcase (list (magit-section-type section)
- (and siblings t)
- (and (region-active-p) t)
- ssection)
- (`(hunk nil t ,_)
- (if (magit-section-internal-region-p section) 'region 'hunk))
- (`(hunk t t nil) 'hunks)
- (`(hunk ,_ ,_ ,_) 'hunk)
- (`(file t t nil) 'files)
- (`(file ,_ ,_ ,_) 'file)
- (`(,(or `staged `unstaged `untracked)
- nil ,_ ,_) 'list)))))
-
-;;; Diff Highlight
-
-(defun magit-diff-unhighlight (section selection)
- "Remove the highlighting of the diff-related SECTION."
- (when (eq (magit-section-type section) 'hunk)
- (magit-diff-paint-hunk section selection nil)
- t))
-
-(defun magit-diff-highlight (section selection)
- "Highlight the diff-related SECTION and return t.
-If SECTION is not a diff-related section, then do nothing and
-return nil. If SELECTION is non-nil then it is a list of sections
-selected by the region, including SECTION. All of these sections
-are highlighted."
- (if (and (magit-section-match 'commit section)
- (magit-section-children section))
- (progn (if selection
- (dolist (section selection)
- (magit-diff-highlight-list section selection))
- (magit-diff-highlight-list section))
- t)
- (-when-let (scope (magit-diff-scope section t))
- (cond ((eq scope 'region)
- (magit-diff-paint-hunk section selection t))
- (selection
- (dolist (section selection)
- (magit-diff-highlight-recursive section selection)))
- (t
- (magit-diff-highlight-recursive section)))
- t)))
-
-(defun magit-diff-highlight-recursive (section &optional selection)
- (pcase (magit-diff-scope section)
- (`list (magit-diff-highlight-list section selection))
- (`file (magit-diff-highlight-file section selection))
- (`hunk (magit-diff-highlight-heading section selection)
- (magit-diff-paint-hunk section selection t))
- (_ (magit-section-highlight section nil))))
-
-(defun magit-diff-highlight-list (section &optional selection)
- (let ((beg (magit-section-start section))
- (cnt (magit-section-content section))
- (end (magit-section-end section)))
- (unless (and (region-active-p)
- (= end (1+ (region-end))))
- (magit-section-make-overlay beg cnt 'magit-section-highlight)
- (unless (magit-section-hidden section)
- (dolist (child (magit-section-children section))
- (magit-diff-highlight-recursive child selection))))
- (when magit-diff-highlight-hunk-body
- (magit-section-make-overlay (1- end) end 'magit-section-highlight))))
-
-(defun magit-diff-highlight-file (section &optional selection)
- (magit-diff-highlight-heading section selection)
- (unless (magit-section-hidden section)
- (dolist (child (magit-section-children section))
- (magit-diff-highlight-recursive child selection))))
-
-(defun magit-diff-highlight-heading (section &optional selection)
- (magit-section-make-overlay
- (magit-section-start section)
- (or (magit-section-content section)
- (magit-section-end section))
- (pcase (list (magit-section-type section)
- (and (member section selection) t))
- (`(file t) 'magit-diff-file-heading-selection)
- (`(file nil) 'magit-diff-file-heading-highlight)
- (`(hunk t) 'magit-diff-hunk-heading-selection)
- (`(hunk nil) 'magit-diff-hunk-heading-highlight))))
-
-;;; Hunk Paint
-
-(cl-defun magit-diff-paint-hunk
- (section &optional selection
- (highlight (magit-section-selected-p section selection)))
- (let (paint)
- (unless magit-diff-highlight-hunk-body
- (setq highlight nil))
- (cond (highlight
- (unless (magit-section-hidden section)
- (add-to-list 'magit-section-highlighted-sections section)
- (cond ((memq section magit-section-unhighlight-sections)
- (setq magit-section-unhighlight-sections
- (delq section magit-section-unhighlight-sections)))
- (magit-diff-highlight-hunk-body
- (setq paint t)))))
- (t
- (cond ((and (magit-section-hidden section)
- (memq section magit-section-unhighlight-sections))
- (add-to-list 'magit-section-highlighted-sections section)
- (setq magit-section-unhighlight-sections
- (delq section magit-section-unhighlight-sections)))
- (t
- (setq paint t)))))
- (when paint
- (save-excursion
- (goto-char (magit-section-start section))
- (let ((end (magit-section-end section))
- (merging (looking-at "@@@"))
- (stage nil))
- (forward-line)
- (while (< (point) end)
- (when (and magit-diff-hide-trailing-cr-characters
- (char-equal ?\r (char-before (line-end-position))))
- (put-text-property (1- (line-end-position)) (line-end-position)
- 'invisible t))
- (put-text-property
- (point) (1+ (line-end-position)) 'face
- (cond
- ((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}")
- (setq stage (pcase (list (match-string 1) highlight)
- (`("<" nil) 'magit-diff-our)
- (`("<" t) 'magit-diff-our-highlight)
- (`("|" nil) 'magit-diff-base)
- (`("|" t) 'magit-diff-base-highlight)
- (`("=" nil) 'magit-diff-their)
- (`("=" t) 'magit-diff-their-highlight)
- (`(">" nil) nil)))
- 'magit-diff-conflict-heading)
- ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+"))
- (magit-diff-paint-whitespace merging)
- (or stage
- (if highlight 'magit-diff-added-highlight 'magit-diff-added)))
- ((looking-at (if merging "^\\(-\\| -\\)" "^-"))
- (if highlight 'magit-diff-removed-highlight 'magit-diff-removed))
- (t
- (if highlight 'magit-diff-context-highlight 'magit-diff-context))))
- (forward-line))))))
- (magit-diff-update-hunk-refinement section))
-
-(defun magit-diff-paint-whitespace (merging)
- (when (and magit-diff-paint-whitespace
- (or (derived-mode-p 'magit-status-mode)
- (not (eq magit-diff-paint-whitespace 'status))))
- (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+]"))
- (indent
- (if (local-variable-p 'magit-diff-highlight-indentation)
- magit-diff-highlight-indentation
- (setq-local
- magit-diff-highlight-indentation
- (cdr (--first (string-match-p (car it) default-directory)
- (nreverse
- (default-value
- 'magit-diff-highlight-indentation))))))))
- (when (and magit-diff-highlight-trailing
- (looking-at (concat prefix ".*?\\([ \t]+\\)$")))
- (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
- (overlay-put ov 'face 'magit-diff-whitespace-warning)
- (overlay-put ov 'evaporate t)))
- (when (or (and (eq indent 'tabs)
- (looking-at (concat prefix "\\( *\t[ \t]*\\)")))
- (and (integerp indent)
- (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)"
- prefix indent))))
- (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
- (overlay-put ov 'face 'magit-diff-whitespace-warning)
- (overlay-put ov 'evaporate t))))))
-
-(defun magit-diff-update-hunk-refinement (&optional section)
- (if section
- (unless (magit-section-hidden section)
- (pcase (list magit-diff-refine-hunk
- (magit-section-refined section)
- (eq section (magit-current-section)))
- ((or `(all nil ,_) `(t nil t))
- (setf (magit-section-refined section) t)
- (save-excursion
- (goto-char (magit-section-start section))
- ;; `diff-refine-hunk' does not handle combined diffs.
- (unless (looking-at "@@@")
- (diff-refine-hunk))))
- ((or `(nil t ,_) `(t t nil))
- (setf (magit-section-refined section) nil)
- (remove-overlays (magit-section-start section)
- (magit-section-end section)
- 'diff-mode 'fine))))
- (cl-labels ((recurse (section)
- (if (magit-section-match 'hunk section)
- (magit-diff-update-hunk-refinement section)
- (--each (magit-section-children section)
- (recurse it)))))
- (recurse magit-root-section))))
-
-
-;;; Highlight Region
-
-(defvar magit-diff-unmarked-lines-keep-foreground t)
-
-(defun magit-diff-update-hunk-region (section)
- (when (and (eq (magit-diff-scope section t) 'region)
- (not (and (eq this-command 'mouse-drag-region)
- (eq (mark) (point)))))
- (let ((sbeg (magit-section-start section))
- (cbeg (magit-section-content section))
- (rbeg (save-excursion (goto-char (region-beginning))
- (line-beginning-position)))
- (rend (save-excursion (goto-char (region-end))
- (line-end-position)))
- (send (magit-section-end section))
- (face (if magit-diff-highlight-hunk-body
- 'magit-diff-context-highlight
- 'magit-diff-context)))
- (when magit-diff-unmarked-lines-keep-foreground
- (setq face (list :background (face-attribute face :background))))
- (cl-flet ((ov (start end &rest args)
- (let ((ov (make-overlay start end nil t)))
- (overlay-put ov 'evaporate t)
- (while args (overlay-put ov (pop args) (pop args)))
- (push ov magit-region-overlays)
- ov)))
- (ov sbeg cbeg 'face 'magit-diff-lines-heading
- 'display (concat (magit-diff-hunk-region-header section) "\n"))
- (ov cbeg rbeg 'face face 'priority 2)
- (when (and (window-system) magit-diff-show-lines-boundary)
- (ov rbeg (1+ rbeg) 'before-string
- (propertize (concat (propertize "\s" 'display '(space :height (1)))
- (propertize "\n" 'line-height t))
- 'face 'magit-diff-lines-boundary))
- (ov rend (1+ rend) 'after-string
- (propertize (concat (propertize "\s" 'display '(space :height (1)))
- (propertize "\n" 'line-height t))
- 'face 'magit-diff-lines-boundary)))
- (ov (1+ rend) send 'face face 'priority 2)))))
-
-;;; Diff Extract
-
-(defun magit-diff-file-header (section)
- (when (eq (magit-section-type section) 'hunk)
- (setq section (magit-section-parent section)))
- (when (eq (magit-section-type section) 'file)
- (magit-section-diff-header section)))
-
-(defun magit-diff-hunk-region-header (section)
- (let ((patch (magit-diff-hunk-region-patch section)))
- (string-match "\n" patch)
- (substring patch 0 (1- (match-end 0)))))
-
-(defun magit-diff-hunk-region-patch (section &optional args)
- (let ((op (if (member "--reverse" args) "+" "-"))
- (sbeg (magit-section-start section))
- (rbeg (save-excursion
- (goto-char (region-beginning))
- (line-beginning-position)))
- (rend (region-end))
- (send (magit-section-end section))
- (patch nil))
- (save-excursion
- (goto-char sbeg)
- (while (< (point) send)
- (looking-at "\\(.\\)\\([^\n]*\n\\)")
- (cond ((or (string-match-p "[@ ]" (match-string-no-properties 1))
- (and (>= (point) rbeg)
- (<= (point) rend)))
- (push (match-string-no-properties 0) patch))
- ((equal op (match-string-no-properties 1))
- (push (concat " " (match-string-no-properties 2)) patch)))
- (forward-line)))
- (with-temp-buffer
- (insert (mapconcat 'identity (reverse patch) ""))
- (diff-fixup-modifs (point-min) (point-max))
- (setq patch (buffer-string)))
- patch))
-
-;;; magit-diff.el ends soon
-(provide 'magit-diff)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-diff.el ends here
+++ /dev/null
-;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library provides basic support for Ediff.
-
-;;; Code:
-
-(require 'magit)
-
-(require 'ediff)
-(require 'smerge-mode)
-
-(defvar smerge-ediff-buf)
-(defvar smerge-ediff-windows)
-
-(defgroup magit-ediff nil
- "Ediff support for Magit."
- :group 'magit-extensions)
-
-(unless (find-lisp-object-file-name 'magit-ediff-quit-hook 'defvar)
- (add-hook 'magit-ediff-quit-hook 'magit-ediff-restore-previous-winconf)
- (add-hook 'magit-ediff-quit-hook 'magit-ediff-cleanup-auxiliary-buffers))
-(defcustom magit-ediff-quit-hook
- '(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.
-The `ediff-quit-hook' is ignored by Ediff sessions which were
-invoked using Magit."
- :package-version '(magit . "2.2.0")
- :group 'magit-ediff
- :type 'hook
- :options '(magit-ediff-cleanup-auxiliary-buffers
- magit-ediff-restore-previous-winconf))
-
-(defcustom magit-ediff-dwim-show-on-hunks nil
- "Whether `magit-ediff-dwim' runs show variants on hunks.
-If non-nil, `magit-ediff-show-staged' or
-`magit-ediff-show-unstaged' are called based on what section the
-hunk is in. Otherwise, `magit-ediff-dwim' runs
-`magit-ediff-stage' when point is on an uncommitted hunk."
- :package-version '(magit . "2.2.0")
- :group 'magit-ediff
- :type 'boolean)
-
-(defcustom magit-ediff-show-stash-with-index t
- "Whether `magit-ediff-show-stash' shows the state of the index.
-
-If non-nil, use a third Ediff buffer to distinguish which changes
-in the stash were staged. In cases where the stash contains no
-staged changes, fall back to a two-buffer Ediff.
-
-More specificaly, a stash is a merge commit, stash@{N}, with
-potentially three parents.
-
-* stash@{N}^1 represents the HEAD commit at the time the stash
- was created.
-
-* stash@{N}^2 records any changes that were staged when the stash
- was made.
-
-* stash@{N}^3, if it exists, contains files that were untracked
- when stashing.
-
-If this option is non-nil, `magit-ediff-show-stash' will run
-Ediff on a file using three buffers: one for stash@{N}, another
-for stash@{N}^1, and a third for stash@{N}^2.
-
-Otherwise, Ediff uses two buffers, comparing
-stash@{N}^1..stash@{N}. Along with any unstaged changes, changes
-in the index commit, stash@{N}^2, will be shown in this
-comparison unless they conflicted with changes in the working
-tree at the time of stashing."
- :package-version '(magit . "2.6.0")
- :group 'magit-ediff
- :type 'boolean)
-
-(defvar magit-ediff-previous-winconf nil)
-
-;;;###autoload (autoload 'magit-ediff-popup "magit-ediff" nil t)
-(magit-define-popup magit-ediff-popup
- "Popup console for ediff commands."
- 'magit-diff nil nil
- :actions '((?E "Dwim" magit-ediff-dwim)
- (?u "Show unstaged" magit-ediff-show-unstaged)
- (?s "Stage" magit-ediff-stage)
- (?i "Show staged" magit-ediff-show-staged)
- (?m "Resolve" magit-ediff-resolve)
- (?w "Show worktree" magit-ediff-show-working-tree)
- (?r "Diff range" magit-ediff-compare)
- (?c "Show commit" magit-ediff-show-commit) nil
- (?z "Show stash" magit-ediff-show-stash))
- :max-action-columns 2)
-
-;;;###autoload
-(defun magit-ediff-resolve (file)
- "Resolve outstanding conflicts in FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-In the rare event that you want to manually resolve all
-conflicts, including those already resolved by Git, use
-`ediff-merge-revisions-with-ancestor'."
- (interactive
- (let ((current (magit-current-file))
- (unmerged (magit-unmerged-files)))
- (unless unmerged
- (user-error "There are no unresolved conflicts"))
- (list (magit-completing-read "Resolve file" unmerged nil t nil nil
- (car (member current unmerged))))))
- (magit-with-toplevel
- (with-current-buffer (find-file-noselect file)
- (smerge-ediff)
- (setq-local
- ediff-quit-hook
- (lambda ()
- (let ((bufC ediff-buffer-C)
- (bufS smerge-ediff-buf))
- (with-current-buffer bufS
- (when (yes-or-no-p (format "Conflict resolution finished; save %s?"
- buffer-file-name))
- (erase-buffer)
- (insert-buffer-substring bufC)
- (save-buffer))))
- (when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A))
- (when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B))
- (when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C))
- (when (buffer-live-p ediff-ancestor-buffer)
- (kill-buffer ediff-ancestor-buffer))
- (let ((magit-ediff-previous-winconf smerge-ediff-windows))
- (run-hooks 'magit-ediff-quit-hook)))))))
-
-;;;###autoload
-(defun magit-ediff-stage (file)
- "Stage and unstage changes to FILE using Ediff.
-FILE has to be relative to the top directory of the repository."
- (interactive
- (list (magit-completing-read "Selectively stage file" nil
- (magit-tracked-files) nil nil nil
- (magit-current-file))))
- (magit-with-toplevel
- (let* ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-buffer (concat file ".~{index}~")))
- (bufBrw (and bufB (with-current-buffer bufB (not buffer-read-only))))
- (bufC (get-file-buffer file)))
- (ediff-buffers3
- (or bufA (magit-find-file-noselect "HEAD" file))
- (with-current-buffer (magit-find-file-index-noselect file t)
- (setq buffer-read-only nil)
- (current-buffer))
- (or bufC (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- (and (buffer-live-p ediff-buffer-B)
- (buffer-modified-p ediff-buffer-B)
- (with-current-buffer ediff-buffer-B
- (magit-update-index)))
- (and (buffer-live-p ediff-buffer-C)
- (buffer-modified-p ediff-buffer-C)
- (with-current-buffer ediff-buffer-C
- (when (y-or-n-p
- (format "Save file %s? " buffer-file-name))
- (save-buffer))))
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(if bufB
- (unless bufBrw '((with-current-buffer ediff-buffer-B
- (setq buffer-read-only t))))
- '((ediff-kill-buffer-carefully ediff-buffer-B)))
- ,@(unless bufC '((ediff-kill-buffer-carefully ediff-buffer-C)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers3))))
-
-;;;###autoload
-(defun magit-ediff-compare (revA revB fileA fileB)
- "Compare REVA:FILEA with REVB:FILEB using Ediff.
-
-FILEA and FILEB have to be relative to the top directory of the
-repository. If REVA or REVB is nil then this stands for the
-working tree state.
-
-If the region is active, use the revisions on the first and last
-line of the region. With a prefix argument, instead of diffing
-the revisions, choose a revision to view changes along, starting
-at the common ancestor of both revisions (i.e., use a \"...\"
-range)."
- (interactive (-let [(revA revB) (magit-ediff-compare--read-revisions
- nil current-prefix-arg)]
- (nconc (list revA revB)
- (magit-ediff-read-files revA revB))))
- (magit-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (if revA
- (magit-get-revision-buffer revA fileA)
- (get-file-buffer fileA)))
- (bufB (if revB
- (magit-get-revision-buffer revB fileB)
- (get-file-buffer fileB))))
- (ediff-buffers
- (or bufA (if revA
- (magit-find-file-noselect revA fileA)
- (find-file-noselect fileA)))
- (or bufB (if revB
- (magit-find-file-noselect revB fileB)
- (find-file-noselect fileB)))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-revision))))
-
-(defun magit-ediff-compare--read-revisions (&optional arg mbase)
- (let ((input (or arg (magit-diff-read-range-or-commit "Compare range or commit"
- nil mbase)))
- revA revB)
- (if (string-match magit-range-re input)
- (progn (setq revA (or (match-string 1 input) "HEAD")
- revB (or (match-string 3 input) "HEAD"))
- (when (string= (match-string 2 input) "...")
- (setq revA (magit-git-string "merge-base" revA revB))))
- (setq revA input))
- (list revA revB)))
-
-(defun magit-ediff-read-files (revA revB &optional fileB)
- "Read file in REVB, return it and the corresponding file in REVA.
-When FILEB is non-nil, use this as REVB's file instead of
-prompting for it."
- (unless fileB
- (setq fileB (magit-read-file-choice
- (format "File to compare between %s and %s"
- revA (or revB "the working tree"))
- (magit-changed-files revA revB)
- (format "No changed files between %s and %s"
- revA (or revB "the working tree")))))
- (list (or (car (member fileB (magit-revision-files revA)))
- (cdr (assoc fileB (magit-renamed-files revB revA)))
- (magit-read-file-choice
- (format "File in %s to compare with %s in %s"
- revA fileB (or revB "the working tree"))
- (magit-changed-files revB revA)
- (format "No files have changed between %s and %s"
- revA revB)))
- fileB))
-
-;;;###autoload
-(defun magit-ediff-dwim ()
- "Compare, stage, or resolve using Ediff.
-This command tries to guess what file, and what commit or range
-the user wants to compare, stage, or resolve using Ediff. It
-might only be able to guess either the file, or range or commit,
-in which case the user is asked about the other. It might not
-always guess right, in which case the appropriate `magit-ediff-*'
-command has to be used explicitly. If it cannot read the user's
-mind at all, then it asks the user for a command to run."
- (interactive)
- (magit-section-case
- (hunk (save-excursion
- (goto-char (magit-section-start (magit-section-parent it)))
- (magit-ediff-dwim)))
- (t
- (let ((range (magit-diff--dwim))
- (file (magit-current-file))
- command revA revB)
- (pcase range
- ((and (guard (not magit-ediff-dwim-show-on-hunks))
- (or `unstaged `staged))
- (setq command (if (magit-anything-unmerged-p)
- #'magit-ediff-resolve
- #'magit-ediff-stage)))
- (`unstaged (setq command #'magit-ediff-show-unstaged))
- (`staged (setq command #'magit-ediff-show-staged))
- (`(commit . ,value)
- (setq command #'magit-ediff-show-commit
- revB value))
- (`(stash . ,value)
- (setq command #'magit-ediff-show-stash
- revB value))
- ((pred stringp)
- (-let [(a b) (magit-ediff-compare--read-revisions range)]
- (setq command #'magit-ediff-compare
- revA a
- revB b)))
- (_
- (when (derived-mode-p 'magit-diff-mode)
- (pcase (magit-diff-type)
- (`committed (-let [(a b) (magit-ediff-compare--read-revisions
- (car magit-refresh-args))]
- (setq revA a revB b)))
- ((guard (not magit-ediff-dwim-show-on-hunks))
- (setq command #'magit-ediff-stage))
- (`unstaged (setq command #'magit-ediff-show-unstaged))
- (`staged (setq command #'magit-ediff-show-staged))
- (`undefined (setq command nil))
- (_ (setq command nil))))))
- (cond ((not command)
- (call-interactively
- (magit-read-char-case
- "Failed to read your mind; do you want to " t
- (?c "[c]ommit" 'magit-ediff-show-commit)
- (?r "[r]ange" 'magit-ediff-compare)
- (?s "[s]tage" 'magit-ediff-stage)
- (?v "resol[v]e" 'magit-ediff-resolve))))
- ((eq command 'magit-ediff-compare)
- (apply 'magit-ediff-compare revA revB
- (magit-ediff-read-files revA revB file)))
- ((eq command 'magit-ediff-show-commit)
- (magit-ediff-show-commit revB))
- ((eq command 'magit-ediff-show-stash)
- (magit-ediff-show-stash revB))
- (file
- (funcall command file))
- (t
- (call-interactively command)))))))
-
-;;;###autoload
-(defun magit-ediff-show-staged (file)
- "Show staged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository."
- (interactive
- (list (magit-read-file-choice "Show staged changes for file"
- (magit-staged-files)
- "No staged files")))
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-buffer (concat file ".~{index}~"))))
- (ediff-buffers
- (or bufA (magit-find-file-noselect "HEAD" file))
- (or bufB (magit-find-file-index-noselect file t))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers)))
-
-;;;###autoload
-(defun magit-ediff-show-unstaged (file)
- "Show unstaged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository."
- (interactive
- (list (magit-read-file-choice "Show unstaged changes for file"
- (magit-modified-files)
- "No unstaged files")))
- (magit-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (get-buffer (concat file ".~{index}~")))
- (bufB (get-file-buffer file)))
- (ediff-buffers
- (or bufA (magit-find-file-index-noselect file t))
- (or bufB (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers))))
-
-;;;###autoload
-(defun magit-ediff-show-working-tree (file)
- "Show changes between HEAD and working tree using Ediff.
-FILE must be relative to the top directory of the repository."
- (interactive
- (list (magit-read-file-choice "Show changes in file"
- (magit-changed-files "HEAD")
- "No changed files")))
- (magit-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-file-buffer file)))
- (ediff-buffers
- (or bufA (magit-find-file-noselect "HEAD" file))
- (or bufB (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers))))
-
-;;;###autoload
-(defun magit-ediff-show-commit (commit)
- "Show changes introduced by COMMIT using Ediff."
- (interactive (list (magit-read-branch-or-commit "Revision")))
- (let ((revA (concat commit "^"))
- (revB commit))
- (apply #'magit-ediff-compare
- revA revB
- (magit-ediff-read-files revA revB (magit-current-file)))))
-
-;;;###autoload
-(defun magit-ediff-show-stash (stash)
- "Show changes introduced by STASH using Ediff.
-`magit-ediff-show-stash-with-index' controls whether a
-three-buffer Ediff is used in order to distinguish changes in the
-stash that were staged."
- (interactive (list (magit-read-stash "Stash")))
- (-let* ((revA (concat stash "^1"))
- (revB (concat stash "^2"))
- (revC stash)
- ((fileA fileC) (magit-ediff-read-files revA revC))
- (fileB fileC))
- (if (and magit-ediff-show-stash-with-index
- (member fileA (magit-changed-files revB revA)))
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer revA fileA))
- (bufB (magit-get-revision-buffer revB fileB))
- (bufC (magit-get-revision-buffer revC fileC)))
- (ediff-buffers3
- (or bufA (magit-find-file-noselect revA fileA))
- (or bufB (magit-find-file-noselect revB fileB))
- (or bufC (magit-find-file-noselect revC fileC))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA
- '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB
- '((ediff-kill-buffer-carefully ediff-buffer-B)))
- ,@(unless bufC
- '((ediff-kill-buffer-carefully ediff-buffer-C)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers3))
- (magit-ediff-compare revA revC fileA fileC))))
-
-(defun magit-ediff-cleanup-auxiliary-buffers ()
- (let* ((ctl-buf ediff-control-buffer)
- (ctl-win (ediff-get-visible-buffer-window ctl-buf))
- (ctl-frm ediff-control-frame)
- (main-frame (cond ((window-live-p ediff-window-A)
- (window-frame ediff-window-A))
- ((window-live-p ediff-window-B)
- (window-frame ediff-window-B)))))
- (ediff-kill-buffer-carefully ediff-diff-buffer)
- (ediff-kill-buffer-carefully ediff-custom-diff-buffer)
- (ediff-kill-buffer-carefully ediff-fine-diff-buffer)
- (ediff-kill-buffer-carefully ediff-tmp-buffer)
- (ediff-kill-buffer-carefully ediff-error-buffer)
- (ediff-kill-buffer-carefully ediff-msg-buffer)
- (ediff-kill-buffer-carefully ediff-debug-buffer)
- (when (boundp 'ediff-patch-diagnostics)
- (ediff-kill-buffer-carefully ediff-patch-diagnostics))
- (cond ((and (ediff-window-display-p)
- (frame-live-p ctl-frm))
- (delete-frame ctl-frm))
- ((window-live-p ctl-win)
- (delete-window ctl-win)))
- (unless (ediff-multiframe-setup-p)
- (ediff-kill-bottom-toolbar))
- (ediff-kill-buffer-carefully ctl-buf)
- (when (frame-live-p main-frame)
- (select-frame main-frame))))
-
-(defun magit-ediff-restore-previous-winconf ()
- (set-window-configuration magit-ediff-previous-winconf))
-
-;;; magit-ediff.el ends soon
-(provide 'magit-ediff)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-ediff.el ends here
+++ /dev/null
-;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Additional functionality for Magit.
-
-;;; Code:
-
-(require 'magit)
-
-(defgroup magit-extras nil
- "Additional functionality for Magit."
- :group 'magit-extensions)
-
-;;; External Tools
-
-(defcustom magit-gitk-executable
- (or (and (eq system-type 'windows-nt)
- (let ((exe (expand-file-name
- "gitk" (file-name-nondirectory magit-git-executable))))
- (and (file-executable-p exe) exe)))
- (executable-find "gitk") "gitk")
- "The Gitk executable."
- :group 'magit-extras
- :set-after '(magit-git-executable)
- :type 'string)
-
-;;;###autoload
-(defun magit-run-git-gui ()
- "Run `git gui' for the current git repository."
- (interactive)
- (magit-with-toplevel
- (call-process magit-git-executable nil 0 nil "gui")))
-
-;;;###autoload
-(defun magit-run-git-gui-blame (commit filename &optional linenum)
- "Run `git gui blame' on the given FILENAME and COMMIT.
-Interactively run it for the current file and the HEAD, with a
-prefix or when the current file cannot be determined let the user
-choose. When the current buffer is visiting FILENAME instruct
-blame to center around the line point is on."
- (interactive
- (let (revision filename)
- (when (or current-prefix-arg
- (not (setq revision "HEAD"
- filename (magit-file-relative-name nil 'tracked))))
- (setq revision (magit-read-branch-or-commit "Blame from revision")
- filename (magit-read-file-from-rev revision "Blame file")))
- (list revision filename
- (and (equal filename
- (ignore-errors
- (magit-file-relative-name buffer-file-name)))
- (line-number-at-pos)))))
- (magit-with-toplevel
- (apply #'call-process magit-git-executable nil 0 nil "gui" "blame"
- `(,@(and linenum (list (format "--line=%d" linenum)))
- ,commit
- ,filename))))
-
-;;;###autoload
-(defun magit-run-gitk ()
- "Run `gitk' in the current repository."
- (interactive)
- (call-process magit-gitk-executable nil 0))
-
-;;;###autoload
-(defun magit-run-gitk-branches ()
- "Run `gitk --branches' in the current repository."
- (interactive)
- (call-process magit-gitk-executable nil 0 nil "--branches"))
-
-;;;###autoload
-(defun magit-run-gitk-all ()
- "Run `gitk --all' in the current repository."
- (interactive)
- (call-process magit-gitk-executable nil 0 nil "--all"))
-
-;;; Clean
-
-;;;###autoload
-(defun magit-clean (&optional arg)
- "Remove untracked files from the working tree.
-With a prefix argument also remove ignored files,
-with two prefix arguments remove ignored files only.
-\n(git clean -f -d [-x|-X])"
- (interactive "p")
- (when (yes-or-no-p (format "Remove %s files? "
- (pcase arg
- (1 "untracked")
- (4 "untracked and ignored")
- (_ "ignored"))))
- (magit-wip-commit-before-change)
- (magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X")))))
-
-(put 'magit-clean 'disabled t)
-
-;;; Gitignore
-
-;;;###autoload
-(defun magit-gitignore (file-or-pattern &optional local)
- "Instruct Git to ignore FILE-OR-PATTERN.
-With a prefix argument only ignore locally."
- (interactive (list (magit-gitignore-read-pattern current-prefix-arg)
- current-prefix-arg))
- (let ((gitignore
- (if local
- (magit-git-dir (convert-standard-filename "info/exclude"))
- (expand-file-name ".gitignore" (magit-toplevel)))))
- (make-directory (file-name-directory gitignore) t)
- (with-temp-buffer
- (when (file-exists-p gitignore)
- (insert-file-contents gitignore))
- (goto-char (point-max))
- (unless (bolp)
- (insert "\n"))
- (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" file-or-pattern))
- (insert "\n")
- (write-region nil nil gitignore))
- (if local
- (magit-refresh)
- (magit-run-git "add" ".gitignore"))))
-
-;;;###autoload
-(defun magit-gitignore-locally (file-or-pattern)
- "Instruct Git to locally ignore FILE-OR-PATTERN."
- (interactive (list (magit-gitignore-read-pattern t)))
- (magit-gitignore file-or-pattern t))
-
-(defun magit-gitignore-read-pattern (local)
- (let* ((default (magit-current-file))
- (choices
- (delete-dups
- (--mapcat
- (cons (concat "/" it)
- (-when-let (ext (file-name-extension it))
- (list (concat "/" (file-name-directory "foo") "*." ext)
- (concat "*." ext))))
- (magit-untracked-files)))))
- (when default
- (setq default (concat "/" default))
- (unless (member default choices)
- (setq default (concat "*." (file-name-extension default)))
- (unless (member default choices)
- (setq default nil))))
- (magit-completing-read (concat "File or pattern to ignore"
- (and local " locally"))
- choices nil nil nil nil default)))
-
-;;; ChangeLog
-
-;;;###autoload
-(defun magit-add-change-log-entry (&optional whoami file-name other-window)
- "Find change log file and add date entry and item for current change.
-This differs from `add-change-log-entry' (which see) in that
-it acts on the current hunk in a Magit buffer instead of on
-a position in a file-visiting buffer."
- (interactive (list current-prefix-arg
- (prompt-for-change-log-name)))
- (let (buf pos)
- (save-window-excursion
- (call-interactively #'magit-diff-visit-file)
- (setq buf (current-buffer)
- pos (point)))
- (save-excursion
- (with-current-buffer buf
- (goto-char pos)
- (add-change-log-entry whoami file-name other-window)))))
-
-;;;###autoload
-(defun magit-add-change-log-entry-other-window (&optional whoami file-name)
- "Find change log file in other window and add entry and item.
-This differs from `add-change-log-entry-other-window' (which see)
-in that it acts on the current hunk in a Magit buffer instead of
-on a position in a file-visiting buffer."
- (interactive (and current-prefix-arg
- (list current-prefix-arg
- (prompt-for-change-log-name))))
- (magit-add-change-log-entry whoami file-name t))
-
-;;; magit-extras.el ends soon
-(provide 'magit-extras)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-extras.el ends here
+++ /dev/null
-;;; magit-git.el --- Git functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements wrappers for various Git plumbing commands.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-utils)
-(require 'magit-section)
-
-(declare-function magit-process-buffer 'magit-process)
-(declare-function magit-process-file 'magit-process)
-(declare-function magit-process-insert-section 'magit-process)
-(defvar magit-process-error-message-re)
-(defvar magit-refresh-args) ; from `magit-mode' for `magit-current-file'
-(defvar magit-branch-prefer-remote-upstream)
-
-(defvar magit-tramp-process-environment nil)
-
-(require 'crm)
-
-;;; Options
-
-;; For now this is shared between `magit-process' and `magit-git'.
-(defgroup magit-process nil
- "Git and other external processes used by Magit."
- :group 'magit)
-
-(defvar magit-git-environment nil
- "Prepended to `process-environment' while running git.")
-
-(defcustom magit-git-executable
- ;; Git might be installed in a different location on a remote, so
- ;; it is better not to use the full path to the executable, except
- ;; on Window were we would otherwise end up using one one of the
- ;; wrappers "cmd/git.exe" or "cmd/git.cmd", which are much slower
- ;; than using "bin/git.exe" directly.
- (or (and (eq system-type 'windows-nt)
- (--when-let (executable-find "git.exe")
- (or (ignore-errors
- ;; Git for Windows 2.x provides cygpath so we can
- ;; ask it for native paths. Using an upper case
- ;; alias makes this fail on 1.x (which is good,
- ;; because we would not want to end up using some
- ;; other cygpath).
- (prog1 (car
- (process-lines
- it "-c"
- "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
- "X" "git"))
- (setq magit-git-environment
- (list (concat "PATH="
- (car (process-lines
- it "-c"
- "alias.P=!cygpath -wp \"$PATH\""
- "P")))))))
- ;; For 1.x, we search for bin/ next to cmd/.
- (let ((alt (directory-file-name (file-name-directory it))))
- (if (and (equal (file-name-nondirectory alt) "cmd")
- (setq alt (expand-file-name
- (convert-standard-filename "bin/git.exe")
- (file-name-directory alt)))
- (file-executable-p alt))
- alt
- it)))))
- "git")
- "The Git executable used by Magit."
- :group 'magit-process
- :type 'string)
-
-(defcustom magit-git-global-arguments
- '("--no-pager" "--literal-pathspecs" "-c" "core.preloadindex=true")
- "Global git arguments.
-
-The arguments set here are used every time the git executable is
-run as a subprocess. They are placed right after the executable
-itself and before the git command - as in `git HERE... COMMAND
-REST'. See the manpage `git(1)' for valid arguments.
-
-Be careful what you add here, especially if you are using Tramp
-to connect to servers with ancient Git versions. Never remove
-anything that is part of the default value, unless you really
-know what you are doing. And think very hard before adding
-something; it will be used every time Magit runs Git for any
-purpose."
- :package-version '(magit . "2.1.0")
- :group 'magit
- :type '(repeat string))
-
-(define-obsolete-variable-alias 'magit-git-standard-options
- 'magit-git-global-arguments "2.1.0")
-
-(defcustom magit-git-debug nil
- "Whether to enable additional reporting of git errors.
-
-Magit basically calls git for one of these two reasons: for
-side-effects or to do something with its standard output.
-
-When git is run for side-effects then its output, including error
-messages, go into the process buffer which is shown when using \
-\\<magit-status-mode-map>\\[magit-process].
-
-When git's output is consumed in some way, then it would be too
-expensive to also insert it into this buffer, but when this
-option is non-nil and git returns with a non-zero exit status,
-then at least its standard error is inserted into this buffer.
-
-This is only intended for debugging purposes. Do not enable this
-permanently, that would negatively affect performance"
- :group 'magit
- :group 'magit-process
- :type 'boolean)
-
-(defcustom magit-ref-namespaces
- '(("^@$" magit-head nil)
- ("^refs/tags/\\(.+\\)" magit-tag nil)
- ("^refs/heads/\\(.+\\)" magit-branch-local nil)
- ("^refs/remotes/\\(.+\\)" magit-branch-remote nil)
- ("^refs/bisect/\\(bad\\)" magit-bisect-bad nil)
- ("^refs/bisect/\\(skip.*\\)" magit-bisect-skip nil)
- ("^refs/bisect/\\(good.*\\)" magit-bisect-good nil)
- ("^refs/stash$" magit-refname-stash nil)
- ("^refs/wip/\\(.+\\)" magit-refname-wip nil)
- ("^\\(bad\\):" magit-bisect-bad nil)
- ("^\\(skip\\):" magit-bisect-skip nil)
- ("^\\(good\\):" magit-bisect-good nil)
- ("\\(.+\\)" magit-refname nil))
- "How refs are formatted for display.
-
-Each entry controls how a certain type of ref is displayed, and
-has the form (REGEXP FACE FORMATTER). REGEXP is a regular
-expression used to match full refs. The first entry whose REGEXP
-matches the reference is used. The first regexp submatch becomes
-the \"label\" that represents the ref and is propertized with
-font FONT. If FORMATTER is non-nil it should be a function that
-takes two arguments, the full ref and the face. It is supposed
-to return a propertized label that represents the ref."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type '(repeat
- (list regexp
- face
- (choice (const :tag "first submatch is label" nil)
- (function :tag "format using function")))))
-
-(defcustom magit-prefer-remote-upstream nil
- "Whether to favor remote branches when reading the upstream branch.
-
-This controls whether commands that read a branch from the user
-and then set it as the upstream branch, offer a local or a remote
-branch as default completion candidate, when they have the choice.
-
-This affects all commands that use `magit-read-upstream-branch'
-or `magit-read-starting-point', which includes all commands that
-change the upstream and many which create new branches."
- :package-version '(magit . "2.4.2")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Git
-
-(defvar magit--refresh-cache nil)
-
-(defmacro magit--with-refresh-cache (key &rest body)
- (declare (indent 1) (debug (form body)))
- (let ((k (cl-gensym)))
- `(if magit--refresh-cache
- (let ((,k ,key))
- (--if-let (assoc ,k (cdr magit--refresh-cache))
- (progn (cl-incf (caar magit--refresh-cache))
- (cdr it))
- (cl-incf (cdar magit--refresh-cache))
- (let ((value ,(macroexp-progn body)))
- (push (cons ,k value)
- (cdr magit--refresh-cache))
- value)))
- ,@body)))
-
-(defun magit-process-git-arguments (args)
- "Prepare ARGS for a function that invokes Git.
-
-Magit has many specialized functions for running Git; they all
-pass arguments through this function before handing them to Git,
-to do the following.
-
-* Flatten ARGS, removing nil arguments.
-* Prepend `magit-git-global-arguments' to ARGS."
- (append magit-git-global-arguments (-flatten args)))
-
-(defun magit-git-exit-code (&rest args)
- "Execute Git with ARGS, returning its exit code."
- (apply #'magit-process-file magit-git-executable nil nil nil
- (magit-process-git-arguments args)))
-
-(defun magit-git-success (&rest args)
- "Execute Git with ARGS, returning t if its exit code is 0."
- (= (magit-git-exit-code args) 0))
-
-(defun magit-git-failure (&rest args)
- "Execute Git with ARGS, returning t if its exit code is 1."
- (= (magit-git-exit-code args) 1))
-
-(defun magit-git-str (&rest args)
- "Execute Git with ARGS, returning the first line of its output.
-If there is no output return nil. If the output begins with a
-newline return an empty string. Like `magit-git-string' but
-ignore `magit-git-debug'."
- (setq args (-flatten args))
- (magit--with-refresh-cache (cons default-directory args)
- (with-temp-buffer
- (apply #'magit-process-file magit-git-executable nil (list t nil) nil
- (magit-process-git-arguments args))
- (unless (bobp)
- (goto-char (point-min))
- (buffer-substring-no-properties (point) (line-end-position))))))
-
-(defun magit-git-true (&rest args)
- "Execute Git with ARGS, returning t if it prints \"true\".
-Return t if the first (and usually only) output line is the
-string \"true\", otherwise return nil."
- (equal (magit-git-str args) "true"))
-
-(defun magit-git-false (&rest args)
- "Execute Git with ARGS, returning t if it prints \"false\".
-Return t if the first (and usually only) output line is the
-string \"false\", otherwise return nil."
- (equal (magit-git-str args) "false"))
-
-(defun magit-git-insert (&rest args)
- "Execute Git with ARGS, inserting its output at point.
-If Git exits with a non-zero exit status, then show a message and
-add a section in the respective process buffer."
- (setq args (magit-process-git-arguments args))
- (if magit-git-debug
- (let (log)
- (unwind-protect
- (progn
- (setq log (make-temp-file "magit-stderr"))
- (delete-file log)
- (let ((exit (apply #'magit-process-file magit-git-executable
- nil (list t log) nil args)))
- (when (> exit 0)
- (let ((msg "Git failed"))
- (when (file-exists-p log)
- (setq msg (with-temp-buffer
- (insert-file-contents log)
- (goto-char (point-max))
- (and (re-search-backward
- magit-process-error-message-re nil t)
- (match-string 1))))
- (let ((magit-git-debug nil))
- (with-current-buffer (magit-process-buffer t)
- (magit-process-insert-section default-directory
- magit-git-executable
- args exit log))))
- (message "%s" msg)))
- exit))
- (ignore-errors (delete-file log))))
- (apply #'magit-process-file magit-git-executable
- nil (list t nil) nil args)))
-
-(defun magit-git-string (&rest args)
- "Execute Git with ARGS, returning the first line of its output.
-If there is no output return nil. If the output begins with a
-newline return an empty string."
- (setq args (-flatten args))
- (magit--with-refresh-cache (cons default-directory args)
- (with-temp-buffer
- (apply #'magit-git-insert args)
- (unless (bobp)
- (goto-char (point-min))
- (buffer-substring-no-properties (point) (line-end-position))))))
-
-(defun magit-git-lines (&rest args)
- "Execute Git with ARGS, returning its output as a list of lines.
-Empty lines anywhere in the output are omitted.
-
-If Git exits with a non-zero exit status, then report show a
-message and add a section in the respective process buffer."
- (with-temp-buffer
- (apply #'magit-git-insert args)
- (split-string (buffer-string) "\n" t)))
-
-(defun magit-git-items (&rest args)
- "Execute Git with ARGS, returning its null-separated output as a list.
-Empty items anywhere in the output are omitted.
-
-If Git exits with a non-zero exit status, then report show a
-message and add a section in the respective process buffer."
- (with-temp-buffer
- (apply #'magit-git-insert args)
- (split-string (buffer-string) "\0" t)))
-
-(defun magit-git-wash (washer &rest args)
- "Execute Git with ARGS, inserting washed output at point.
-Actually first insert the raw output at point. If there is no
-output call `magit-cancel-section'. Otherwise temporarily narrow
-the buffer to the inserted text, move to its beginning, and then
-call function WASHER with no argument."
- (declare (indent 1))
- (let ((beg (point)))
- (setq args (-flatten args))
- (magit-git-insert args)
- (if (= (point) beg)
- (magit-cancel-section)
- (unless (bolp)
- (insert "\n"))
- (save-restriction
- (narrow-to-region beg (point))
- (goto-char beg)
- (funcall washer args))
- (when (or (= (point) beg)
- (= (point) (1+ beg)))
- (magit-cancel-section)))))
-
-(defun magit-git-version (&optional raw)
- (--when-let (let (magit-git-global-arguments)
- (ignore-errors (substring (magit-git-string "version") 12)))
- (if raw it (and (string-match "^\\([0-9]+\\.[0-9]+\\.[0-9]+\\)" it)
- (match-string 1 it)))))
-
-;;; Files
-
-(defun magit--safe-default-directory (&optional file)
- (catch 'unsafe-default-dir
- (let ((dir (file-name-as-directory
- (expand-file-name (or file default-directory))))
- (previous nil))
- (while (not (magit-file-accessible-directory-p dir))
- (setq dir (file-name-directory (directory-file-name dir)))
- (when (equal dir previous)
- (throw 'unsafe-default-dir nil))
- (setq previous dir))
- dir)))
-
-(defmacro magit--with-safe-default-directory (file &rest body)
- (declare (indent 1) (debug (form body)))
- `(-when-let (default-directory (magit--safe-default-directory ,file))
- ,@body))
-
-(defun magit-git-dir (&optional path)
- "Return absolute path to the control directory of the current repository.
-
-All symlinks are followed. If optional PATH is non-nil, then
-it has to be a path relative to the control directory and its
-absolute path is returned."
- (magit--with-refresh-cache (list default-directory 'magit-git-dir path)
- (magit--with-safe-default-directory nil
- (--when-let (magit-rev-parse-safe "--git-dir")
- (setq it (file-name-as-directory (magit-expand-git-file-name it)))
- (if path (expand-file-name (convert-standard-filename path) it) it)))))
-
-(defun magit-toplevel (&optional directory)
- "Return the absolute path to the toplevel of the current repository.
-
-From within the working tree or control directory of a repository
-return the absolute path to the toplevel directory of the working
-tree. As a special case, from within a bare repository return
-the control directory instead. When called outside a repository
-then return nil.
-
-When optional DIRECTORY is non-nil then return the toplevel for
-that directory instead of the one for `default-directory'.
-
-Try to respect the option `find-file-visit-truename', i.e. when
-the value of that option is nil, then avoid needlessly returning
-the truename. When a symlink to a sub-directory of the working
-tree is involved, or when called from within a sub-directory of
-the gitdir or from the toplevel of a gitdir, which itself is not
-located within the working tree, then it is not possible to avoid
-returning the truename."
- (magit--with-refresh-cache
- (cons (or directory default-directory) 'magit-toplevel)
- (magit--with-safe-default-directory directory
- (-if-let (topdir (magit-rev-parse-safe "--show-toplevel"))
- (let (updir)
- (setq topdir (magit-expand-git-file-name topdir))
- (if (and
- ;; Always honor these settings.
- (not find-file-visit-truename)
- (not (getenv "GIT_WORK_TREE"))
- ;; `--show-cdup' is the relative path to the toplevel
- ;; from `(file-truename default-directory)'. Here we
- ;; pretend it is relative to `default-directory', and
- ;; go to that directory. Then we check whether
- ;; `--show-toplevel' still returns the same value and
- ;; whether `--show-cdup' now is the empty string. If
- ;; both is the case, then we are at the toplevel of
- ;; the same working tree, but also avoided needlessly
- ;; following any symlinks.
- (progn
- (setq updir (file-name-as-directory
- (magit-rev-parse-safe "--show-cdup")))
- (setq updir (if (file-name-absolute-p updir)
- (concat (file-remote-p default-directory) updir)
- (expand-file-name updir)))
- (let ((default-directory updir))
- (and (string-equal (magit-rev-parse-safe "--show-cdup") "")
- (--when-let (magit-rev-parse-safe "--show-toplevel")
- (string-equal (magit-expand-git-file-name it)
- topdir))))))
- updir
- (concat (file-remote-p default-directory)
- (file-name-as-directory topdir))))
- (-when-let (gitdir (magit-rev-parse-safe "--git-dir"))
- (setq gitdir (file-name-as-directory
- (if (file-name-absolute-p gitdir)
- ;; We might have followed a symlink.
- (concat (file-remote-p default-directory)
- (magit-expand-git-file-name gitdir))
- (expand-file-name gitdir))))
- (if (magit-bare-repo-p)
- gitdir
- (let* ((link (expand-file-name "gitdir" gitdir))
- (wtree (and (file-exists-p link)
- (magit-file-line link))))
- (if (and wtree
- ;; Ignore .git/gitdir files that result from a
- ;; Git bug. See #2364.
- (not (equal wtree ".git")))
- ;; Return the linked working tree.
- (file-name-directory wtree)
- ;; Step outside the control directory to enter the working tree.
- (file-name-directory (directory-file-name gitdir))))))))))
-
-(defmacro magit-with-toplevel (&rest body)
- (declare (indent defun) (debug (body)))
- (let ((toplevel (cl-gensym "toplevel")))
- `(let ((,toplevel (magit-toplevel)))
- (if ,toplevel
- (let ((default-directory ,toplevel))
- ,@body)
- (error "Not inside a Git repository: %s" default-directory)))))
-
-(defun magit-inside-gitdir-p ()
- "Return t if `default-directory' is below a repository directory."
- (magit-rev-parse-p "--is-inside-git-dir"))
-
-(defun magit-inside-worktree-p ()
- "Return t if `default-directory' is below the work tree of a repository."
- (magit-rev-parse-p "--is-inside-work-tree"))
-
-(defun magit-bare-repo-p ()
- "Return t if the current repository is bare."
- (magit-rev-parse-p "--is-bare-repository"))
-
-(defun magit-git-repo-p (directory &optional non-bare)
- "Return t if DIRECTORY is a Git repository.
-When optional NON-BARE is non-nil also return nil if DIRECTORY is
-a bare repositories."
- (or (file-regular-p (expand-file-name ".git" directory))
- (file-directory-p (expand-file-name ".git" directory))
- (and (not non-bare)
- (file-regular-p (expand-file-name "HEAD" directory))
- (file-directory-p (expand-file-name "refs" directory))
- (file-directory-p (expand-file-name "objects" directory)))))
-
-(defvar-local magit-buffer-revision nil)
-(defvar-local magit-buffer-refname nil)
-(defvar-local magit-buffer-file-name nil)
-(put 'magit-buffer-revision 'permanent-local t)
-(put 'magit-buffer-refname 'permanent-local t)
-(put 'magit-buffer-file-name 'permanent-local t)
-
-(defun magit-file-relative-name (&optional file tracked)
- "Return the path of FILE relative to the repository root.
-
-If optional FILE is nil or omitted return the relative path of
-the file being visited in the current buffer, if any, else nil.
-If the file is not inside a Git repository then return nil.
-
-If TRACKED is non-nil, return the path only if it matches a
-tracked file."
- (unless file
- (with-current-buffer (or (buffer-base-buffer)
- (current-buffer))
- (setq file (or magit-buffer-file-name buffer-file-name))))
- (when (and file (or (not tracked)
- (magit-file-tracked-p (file-relative-name file))))
- (--when-let (magit-toplevel
- (magit--safe-default-directory
- (directory-file-name (file-name-directory file))))
- (file-relative-name file it))))
-
-(defun magit-file-tracked-p (file)
- (magit-git-success "ls-files" "--error-unmatch" file))
-
-(defun magit-list-files (&rest args)
- (apply #'magit-git-items "ls-files" "-z" "--full-name" args))
-
-(defun magit-tracked-files ()
- (magit-list-files "--cached"))
-
-(defun magit-untracked-files (&optional all files)
- (magit-list-files "--other" (unless all "--exclude-standard") "--" files))
-
-(defun magit-modified-files (&optional nomodules)
- (magit-git-items "diff-files" "-z" "--name-only"
- (and nomodules "--ignore-submodules")))
-
-(defun magit-staged-files (&optional nomodules files)
- (magit-git-items "diff-index" "-z" "--name-only" "--cached"
- (and nomodules "--ignore-submodules")
- (magit-headish) "--" files))
-
-(defun magit-unstaged-files (&optional nomodules files)
- (magit-git-items "diff-index" "-z" "--name-only"
- (and nomodules "--ignore-submodules")
- (magit-headish) "--" files))
-
-(defun magit-staged-binary-files ()
- (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it)
- (list (match-string 1 it)))
- (magit-git-items "diff" "-z" "--cached"
- "--numstat" "--ignore-submodules")))
-
-(defun magit-unmerged-files ()
- (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U"))
-
-(defun magit-revision-files (rev)
- (magit-with-toplevel
- (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev)))
-
-(defun magit-changed-files (rev-or-range &optional other-rev)
- "Return list of files the have changed between two revisions.
-If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a
-range. Otherwise, it can be any revision or range accepted by
-\"git diff\" (i.e., <rev>, <revA>..<revB>, or <revA>...<revB>)."
- (magit-with-toplevel
- (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev)))
-
-(defun magit-renamed-files (revA revB)
- (--map (cons (nth 1 it) (nth 2 it))
- (-partition 3 (magit-git-items
- "diff-tree" "-r" "--diff-filter=R" "-z" "-M"
- revA revB))))
-
-(defun magit-file-status (&rest args)
- (with-temp-buffer
- (save-excursion (magit-git-insert "status" "-z" args))
- (let ((pos (point)) status)
- (while (> (skip-chars-forward "[:print:]") 0)
- (let ((x (char-after pos))
- (y (char-after (1+ pos)))
- (file (buffer-substring (+ pos 3) (point))))
- (forward-char)
- (if (memq x '(?R ?C))
- (progn
- (setq pos (point))
- (skip-chars-forward "[:print:]")
- (push (list file (buffer-substring pos (point)) x y) status)
- (forward-char))
- (push (list file nil x y) status)))
- (setq pos (point)))
- status)))
-
-(defcustom magit-cygwin-mount-points
- (when (eq system-type 'windows-nt)
- (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it)
- (cons (file-name-as-directory (match-string 2 it))
- (file-name-as-directory (match-string 1 it)))
- (lwarn '(magit) :error
- "Failed to parse Cygwin mount: %S" it))
- ;; If --exec-path is not a native Windows path,
- ;; then we probably have a cygwin git.
- (let ((process-environment
- (append magit-git-environment process-environment)))
- (and (not (string-match-p
- "\\`[a-zA-Z]:"
- (car (process-lines
- magit-git-executable "--exec-path"))))
- (ignore-errors (process-lines "mount")))))
- #'> :key (-lambda ((cyg . _win)) (length cyg))))
- "Alist of (CYGWIN . WIN32) directory names.
-Sorted from longest to shortest CYGWIN name."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(alist :key-type string :value-type directory))
-
-(defun magit-expand-git-file-name (filename)
- (unless (file-name-absolute-p filename)
- (setq filename (expand-file-name filename)))
- (-if-let ((cyg . win)
- (cl-assoc filename magit-cygwin-mount-points
- :test (lambda (f cyg) (string-prefix-p cyg f))))
- (concat win (substring filename (length cyg)))
- filename))
-
-(defun magit-convert-git-filename (filename)
- (-if-let ((cyg . win)
- (cl-rassoc filename magit-cygwin-mount-points
- :test (lambda (f win) (string-prefix-p win f))))
- (concat cyg (substring filename (length win)))
- filename))
-
-(defun magit-decode-git-path (path)
- (if (eq (aref path 0) ?\")
- (string-as-multibyte (read path))
- path))
-
-(defun magit-file-at-point ()
- (magit-section-case
- (file (magit-section-value it))
- (hunk (magit-section-parent-value it))))
-
-(defun magit-current-file ()
- (or (magit-file-relative-name)
- (magit-file-at-point)
- (and (derived-mode-p 'magit-log-mode)
- (car (nth 2 magit-refresh-args)))))
-
-;;; Predicates
-
-(defun magit-no-commit-p ()
- "Return t if there is no commit in the current Git repository."
- (not (magit-rev-verify "HEAD")))
-
-(defun magit-anything-staged-p (&optional ignore-submodules &rest files)
- "Return t if there are any staged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (magit-git-failure "diff" "--quiet" "--cached"
- (and ignore-submodules "--ignore-submodules")
- "--" files))
-
-(defun magit-anything-unstaged-p (&optional ignore-submodules &rest files)
- "Return t if there are any unstaged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (magit-git-failure "diff" "--quiet"
- (and ignore-submodules "--ignore-submodules")
- "--" files))
-
-(defun magit-anything-modified-p (&optional ignore-submodules &rest files)
- "Return t if there are any staged or unstaged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (or (apply 'magit-anything-staged-p ignore-submodules files)
- (apply 'magit-anything-unstaged-p ignore-submodules files)))
-
-(defun magit-anything-unmerged-p (&rest files)
- "Return t if there are any merge conflicts.
-If optional FILES is non-nil, then only conflicts in those files
-are considered."
- (and (magit-git-string "ls-files" "--unmerged" files) t))
-
-;;; Revisions and References
-
-(defun magit-rev-parse (&rest args)
- "Execute `git rev-parse ARGS', returning first line of output.
-If there is no output return nil."
- (apply #'magit-git-string "rev-parse" args))
-
-(defun magit-rev-parse-safe (&rest args)
- "Execute `git rev-parse ARGS', returning first line of output.
-If there is no output return nil. Like `magit-rev-parse' but
-ignore `magit-git-debug'."
- (apply #'magit-git-str "rev-parse" args))
-
-(defun magit-rev-parse-p (&rest args)
- "Execute `git rev-parse ARGS', returning t if it prints \"true\".
-Return t if the first (and usually only) output line is the
-string \"true\", otherwise return nil."
- (magit-git-true "rev-parse" args))
-
-(defun magit-rev-verify (rev)
- (magit-rev-parse-safe "--verify" rev))
-
-(defun magit-rev-verify-commit (rev)
- "Return full hash for REV if it names an existing commit."
- (magit-rev-verify (concat rev "^{commit}")))
-
-(defun magit-rev-equal (a b)
- (magit-git-success "diff" "--quiet" a b))
-
-(defun magit-rev-eq (a b)
- (equal (magit-rev-verify a)
- (magit-rev-verify b)))
-
-(defun magit-rev-ancestor-p (a b)
- "Return non-nil if commit A is an ancestor of commit B."
- (magit-git-success "merge-base" "--is-ancestor" a b))
-
-(defun magit-rev-head-p (rev)
- (or (equal rev "HEAD")
- (and rev
- (not (string-match-p "\\.\\." rev))
- (equal (magit-rev-parse rev)
- (magit-rev-parse "HEAD")))))
-
-(defun magit-rev-name (rev &optional pattern)
- (magit-git-string "name-rev" "--name-only" "--no-undefined"
- (and pattern (concat "--refs=" pattern))
- rev))
-
-(defun magit-rev-branch (rev)
- (--when-let (magit-rev-name rev "refs/heads/*")
- (unless (string-match-p "~" it) it)))
-
-(defun magit-get-shortname (rev)
- (let ((fn (apply-partially 'magit-git-string "name-rev"
- "--name-only" "--no-undefined" rev)))
- (setq rev (or (funcall fn "--refs=refs/tags/*")
- (funcall fn "--refs=refs/heads/*")
- (funcall fn "--refs=refs/remotes/*" "--always")))
- (if (and (string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" rev)
- (magit-ref-fullname (match-string 1 rev)))
- (match-string 1 rev)
- rev)))
-
-(defun magit-name-branch (rev &optional lax)
- (or (magit-name-local-branch rev)
- (magit-name-remote-branch rev)
- (and lax (or (magit-name-local-branch rev t)
- (magit-name-remote-branch rev t)))))
-
-(defun magit-name-local-branch (rev &optional lax)
- (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
- "--refs=refs/heads/*" rev)
- (and (or lax (not (string-match-p "~" it))) it)))
-
-(defun magit-name-remote-branch (rev &optional lax)
- (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
- "--refs=refs/remotes/*" rev)
- (and (or lax (not (string-match-p "~" it)))
- (substring it 8))))
-
-(defun magit-name-tag (rev &optional lax)
- (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
- "--refs=refs/tags/*" rev)
- (and (or lax (not (string-match-p "~" it)))
- (substring it 5))))
-
-(defun magit-ref-fullname (name)
- (magit-rev-parse "--symbolic-full-name" name))
-
-(defun magit-ref-exists-p (ref)
- (magit-git-success "show-ref" "--verify" ref))
-
-(defun magit-headish ()
- "Return \"HEAD\" or if that doesn't exist the hash of the empty tree."
- (if (magit-no-commit-p)
- (magit-git-string "mktree")
- "HEAD"))
-
-(defun magit-branch-at-point ()
- (magit-section-case
- (branch (magit-section-value it))
- (commit (magit-name-branch (magit-section-value it)))))
-
-(defun magit-local-branch-at-point ()
- (magit-section-case
- (branch (let ((branch (magit-section-value it)))
- (when (member branch (magit-list-local-branch-names))
- branch)))
- (commit (magit-name-local-branch (magit-section-value it)))))
-
-(defun magit-remote-branch-at-point ()
- (magit-section-case
- (branch (let ((branch (magit-section-value it)))
- (when (member branch (magit-list-remote-branch-names))
- branch)))
- (commit (magit-name-remote-branch (magit-section-value it)))))
-
-(defun magit-commit-at-point ()
- (or (magit-section-when commit)
- (and (derived-mode-p 'magit-revision-mode)
- (car magit-refresh-args))))
-
-(defun magit-branch-or-commit-at-point ()
- (or (magit-section-case
- (branch (magit-section-value it))
- (commit (let ((rev (magit-section-value it)))
- (or (magit-get-shortname rev) rev))))
- (and (derived-mode-p 'magit-revision-mode)
- (car magit-refresh-args))))
-
-(defun magit-tag-at-point ()
- (magit-section-case
- (tag (magit-section-value it))
- (commit (magit-name-tag (magit-section-value it)))))
-
-(defun magit-stash-at-point ()
- (magit-section-when stash))
-
-(defun magit-remote-at-point ()
- (magit-section-case
- (remote (magit-section-value it))
- (branch (magit-section-parent-value it))))
-
-(defun magit-get-current-branch ()
- "Return the refname of the currently checked out branch.
-Return nil if no branch is currently checked out."
- (magit-git-string "symbolic-ref" "--short" "HEAD"))
-
-(defun magit-get-previous-branch ()
- "Return the refname of the previously checked out branch.
-Return nil if no branch can be found in the `HEAD' reflog
-which is different from the current branch and still exists."
- (let ((current (magit-get-current-branch))
- (i 1) prev)
- (while (and (setq prev (magit-rev-verify (format "@{-%i}" i)))
- (or (not (setq prev (magit-rev-branch prev)))
- (equal prev current)))
- (cl-incf i))
- prev))
-
-(cl-defun magit-get-upstream-ref
- (&optional (branch (magit-get-current-branch)))
- (when branch
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (when (and remote merge)
- (cond ((string-equal remote ".") merge)
- ((string-prefix-p "refs/heads/" merge)
- (concat "refs/remotes/" remote "/" (substring merge 11))))))))
-
-(cl-defun magit-get-upstream-branch
- (&optional (branch (magit-get-current-branch)))
- (when branch
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (when (and remote merge (string-prefix-p "refs/heads/" merge))
- (setq merge (substring merge 11))
- (if (string-equal remote ".")
- (propertize merge 'face 'magit-branch-local)
- (propertize (concat remote "/" merge) 'face 'magit-branch-remote))))))
-
-(defun magit-get-indirect-upstream-branch (branch &optional force)
- (let ((remote (magit-get "branch" branch "remote")))
- (and remote (not (equal remote "."))
- ;; The user has opted in...
- (or force (member branch magit-branch-prefer-remote-upstream))
- ;; and local BRANCH tracks a remote branch...
- (let ((upstream (magit-get-upstream-branch branch)))
- ;; whose upstream...
- (and upstream
- ;; has the same name as BRANCH and...
- (equal (substring upstream (1+ (length remote))) branch)
- ;; and can be fast-forwarded to BRANCH.
- (magit-rev-ancestor-p upstream branch)
- upstream)))))
-
-(cl-defun magit-get-upstream-remote
- (&optional (branch (magit-get-current-branch)))
- (when branch
- (magit-get "branch" branch "remote")))
-
-(cl-defun magit-get-push-remote
- (&optional (branch (magit-get-current-branch)))
- (or (and branch (magit-get "branch" branch "pushRemote"))
- (magit-get "remote.pushDefault")))
-
-(cl-defun magit-get-push-branch
- (&optional (branch (magit-get-current-branch)))
- (-when-let (remote (and branch (magit-get-push-remote branch)))
- (concat remote "/" branch)))
-
-(defun magit-get-@{push}-branch (&optional branch)
- (let ((ref (magit-rev-parse "--symbolic-full-name"
- (concat branch "@{push}"))))
- (when (and ref (string-prefix-p "refs/remotes/" ref))
- (substring ref 13))))
-
-(defun magit-get-remote (&optional branch)
- (when (or branch (setq branch (magit-get-current-branch)))
- (let ((remote (magit-get "branch" branch "remote")))
- (unless (equal remote ".")
- remote))))
-
-(defun magit-split-branch-name (branch)
- (cond ((member branch (magit-list-local-branch-names))
- (cons "." branch))
- ((string-match "/" branch)
- (let ((remote (substring branch 0 (match-beginning 0))))
- (if (save-match-data (member remote (magit-list-remotes)))
- (cons remote (substring branch (match-end 0)))
- (error "Invalid branch name %s" branch))))))
-
-(defun magit-get-current-tag (&optional rev with-distance)
- "Return the closest tag reachable from REV.
-
-If optional REV is nil then default to \"HEAD\".
-If optional WITH-DISTANCE is non-nil then return (TAG COMMITS),
-if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number
-of commits in \"HEAD\" but not in TAG and DIRTY is t if there are
-uncommitted changes, nil otherwise."
- (--when-let (magit-git-str "describe" "--long" "--tags"
- (and (eq with-distance 'dirty) "--dirty") rev)
- (save-match-data
- (string-match
- "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" it)
- (if with-distance
- `(,(match-string 1 it)
- ,(string-to-number (or (match-string 2 it) "0"))
- ,@(and (match-string 3 it) (list t)))
- (match-string 1 it)))))
-
-(defun magit-get-next-tag (&optional rev with-distance)
- "Return the closest tag from which REV is reachable.
-
-If optional REV is nil then default to \"HEAD\".
-If no such tag can be found or if the distance is 0 (in which
-case it is the current tag, not the next) return nil instead.
-If optional WITH-DISTANCE is non-nil then return (TAG COMMITS)
-where COMMITS is the number of commits in TAG but not in REV."
- (--when-let (magit-git-str "describe" "--contains" (or rev "HEAD"))
- (save-match-data
- (when (string-match "^[^^~]+" it)
- (setq it (match-string 0 it))
- (unless (equal it (magit-get-current-tag rev))
- (if with-distance
- (list it (car (magit-rev-diff-count it rev)))
- it))))))
-
-(defvar magit-list-refs-namespaces
- '("refs/heads" "refs/remotes" "refs/tags" "refs/pull"))
-
-(defun magit-list-refs (&rest args)
- (magit-git-lines "for-each-ref" "--format=%(refname)"
- (or args magit-list-refs-namespaces)))
-
-(defun magit-list-branches ()
- (magit-list-refs "refs/heads" "refs/remotes"))
-
-(defun magit-list-local-branches ()
- (magit-list-refs "refs/heads"))
-
-(defun magit-list-remote-branches (&optional remote)
- (magit-list-refs (concat "refs/remotes/" remote)))
-
-(defun magit-list-containing-branches (&optional commit)
- (--filter (not (string-match-p "\\`(HEAD" it))
- (--map (substring it 2)
- (magit-git-lines "branch" "--contains" commit))))
-
-(defun magit-list-merged-branches (&optional commit)
- (--filter (not (string-match-p "\\`(HEAD" it))
- (--map (substring it 2)
- (magit-git-lines "branch" "--merged" commit))))
-
-(defun magit-list-unmerged-branches (&optional commit)
- (--filter (not (string-match-p "\\`(HEAD" it))
- (--map (substring it 2)
- (magit-git-lines "branch" "--no-merged" commit))))
-
-(defun magit-list-unmerged-to-upstream-branches ()
- (--filter (-when-let (upstream (magit-get-upstream-branch it))
- (member it (magit-list-unmerged-branches upstream)))
- (magit-list-local-branch-names)))
-
-(defun magit-list-refnames (&rest args)
- (magit-git-lines "for-each-ref" "--format=%(refname:short)"
- (or args magit-list-refs-namespaces)))
-
-(defun magit-list-branch-names ()
- (magit-list-refnames "refs/heads" "refs/remotes"))
-
-(defun magit-list-local-branch-names ()
- (magit-list-refnames "refs/heads"))
-
-(defun magit-list-remote-branch-names (&optional remote relative)
- (if (and remote relative)
- (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote)))
- (--mapcat (when (string-match regexp it)
- (list (match-string 1 it)))
- (magit-list-remote-branches remote)))
- (magit-list-refnames (concat "refs/remotes/" remote))))
-
-(defun magit-format-refs (format &rest args)
- (let ((lines (magit-git-lines
- "for-each-ref" (concat "--format=" format)
- (or args (list "refs/heads" "refs/remotes" "refs/tags")))))
- (if (string-match-p "\f" format)
- (--map (split-string it "\f") lines)
- lines)))
-
-(defun magit-list-remotes ()
- (magit-git-lines "remote"))
-
-(defun magit-list-tags ()
- (magit-git-lines "tag"))
-
-(defun magit-list-notes-refnames ()
- (--map (substring it 6) (magit-list-refnames "refs/notes")))
-
-(defun magit-remote-list-tags (remote)
- (--keep (and (not (string-match-p "\\^{}$" it))
- (substring it 51))
- (magit-git-lines "ls-remote" "--tags" remote)))
-
-(defun magit-remote-list-branches (remote)
- (--keep (and (not (string-match-p "\\^{}$" it))
- (substring it 52))
- (magit-git-lines "ls-remote" "--heads" remote)))
-
-(defun magit-remote-list-refs (remote)
- (--keep (and (not (string-match-p "\\^{}$" it))
- (substring it 41))
- (magit-git-lines "ls-remote" remote)))
-
-(defun magit-get-submodules ()
- (--mapcat (and (string-match "^160000 [0-9a-z]\\{40\\} 0\t\\(.+\\)$" it)
- (list (match-string 1 it)))
- (magit-git-items "ls-files" "-z" "--stage")))
-
-(defun magit-list-worktrees ()
- (let (worktrees worktree)
- (dolist (line (let ((magit-git-standard-options
- ;; KLUDGE At least in v2.8.3 this triggers a segfault.
- (remove "--no-pager" magit-git-standard-options)))
- (magit-git-lines "worktree" "list" "--porcelain")))
- (cond ((string-prefix-p "worktree" line)
- (push (setq worktree (list (substring line 9) nil nil nil))
- worktrees))
- ((string-equal line "bare")
- (let* ((default-directory (car worktree))
- (wt (and (not (magit-get-boolean "core.bare"))
- (magit-get "core.worktree"))))
- (if (and wt (file-exists-p (expand-file-name wt)))
- (progn (setf (nth 0 worktree) (expand-file-name wt))
- (setf (nth 2 worktree) (magit-rev-parse "HEAD"))
- (setf (nth 3 worktree) (magit-get-current-branch)))
- (setf (nth 1 worktree) t))))
- ((string-prefix-p "HEAD" line)
- (setf (nth 2 worktree) (substring line 5)))
- ((string-prefix-p "branch" line)
- (setf (nth 3 worktree) (substring line 18)))
- ((string-equal line "detached"))))
- (nreverse worktrees)))
-
-(defun magit-ref-p (rev)
- (or (car (member rev (magit-list-refs)))
- (car (member rev (magit-list-refnames)))))
-
-(defun magit-branch-p (rev)
- (or (car (member rev (magit-list-branches)))
- (car (member rev (magit-list-branch-names)))))
-
-(defun magit-local-branch-p (rev)
- (or (car (member rev (magit-list-local-branches)))
- (car (member rev (magit-list-local-branch-names)))))
-
-(defun magit-branch-set-face (branch)
- (propertize branch 'face (if (magit-local-branch-p branch)
- 'magit-branch-local
- 'magit-branch-remote)))
-
-(defun magit-tag-p (rev)
- (car (member rev (magit-list-tags))))
-
-(defun magit-remote-p (string)
- (car (member string (magit-list-remotes))))
-
-(defun magit-rev-diff-count (a b)
- "Return the commits in A but not B and vice versa.
-Return a list of two integers: (A>B B>A)."
- (mapcar 'string-to-number
- (split-string (magit-git-string "rev-list"
- "--count" "--left-right"
- (concat a "..." b))
- "\t")))
-
-(defun magit-abbrev-length ()
- (string-to-number (or (magit-get "core.abbrev") "7")))
-
-(defun magit-abbrev-arg (&optional arg)
- (format "--%s=%d" (or arg "abbrev") (magit-abbrev-length)))
-
-(defun magit-rev-abbrev (rev)
- (magit-rev-parse (magit-abbrev-arg "short") rev))
-
-(defun magit-commit-children (commit &optional args)
- (-map #'car
- (--filter (member commit (cdr it))
- (--map (split-string it " ")
- (magit-git-lines
- "log" "--format=%H %P"
- (or args (list "--branches" "--tags" "--remotes"))
- "--not" commit)))))
-
-(defun magit-commit-parents (commit)
- (--when-let (magit-git-string "rev-list" "-1" "--parents" commit)
- (cdr (split-string it))))
-
-(defun magit-assert-one-parent (commit command)
- (when (> (length (magit-commit-parents commit)) 1)
- (user-error "Cannot %s a merge commit" command)))
-
-(defun magit-patch-id (rev)
- (with-temp-buffer
- (magit-process-file
- shell-file-name nil '(t nil) nil shell-command-switch
- (let ((exec (shell-quote-argument magit-git-executable)))
- (format "%s diff-tree -u %s | %s patch-id" exec rev exec)))
- (car (split-string (buffer-string)))))
-
-(defun magit-rev-format (format &optional rev args)
- (let ((str (magit-git-string "show" "--no-patch"
- (concat "--format=" format) args
- (if rev (concat rev "^{commit}") "HEAD") "--")))
- (unless (string-equal str "")
- str)))
-
-(defun magit-rev-insert-format (format &optional rev args)
- (magit-git-insert "show" "--no-patch"
- (concat "--format=" format) args
- (if rev (concat rev "^{commit}") "HEAD") "--"))
-
-(defun magit-format-rev-summary (rev)
- (--when-let (magit-rev-format "%h %s" rev)
- (string-match " " it)
- (put-text-property 0 (match-beginning 0) 'face 'magit-hash it)
- it))
-
-(defun magit-format-ref-label (ref &optional head)
- (-let [(_re face fn)
- (--first (string-match (car it) ref) magit-ref-namespaces)]
- (if fn
- (funcall fn ref face)
- (propertize (or (match-string 1 ref) ref)
- 'face (if (equal ref head) 'magit-branch-current face)))))
-
-(defun magit-format-ref-labels (string)
- (save-match-data
- (let ((regexp "\\(, \\|tag: \\| -> \\|[()]\\)") head names)
- (if (and (derived-mode-p 'magit-log-mode)
- (member "--simplify-by-decoration" (cadr magit-refresh-args)))
- (let ((branches (magit-list-local-branch-names))
- (re (format "^%s/.+" (regexp-opt (magit-list-remotes)))))
- (setq names
- (--map (cond ((string-equal it "HEAD") it)
- ((string-prefix-p "refs/" it) it)
- ((member it branches) (concat "refs/heads/" it))
- ((string-match re it) (concat "refs/remotes/" it))
- (t (concat "refs/" it)))
- (split-string
- (replace-regexp-in-string "tag: " "refs/tags/" string)
- regexp t))))
- (setq names (split-string string regexp t)))
- (when (member "HEAD" names)
- (setq head (magit-git-string "symbolic-ref" "HEAD")
- names (cons (or head "@") (delete head (delete "HEAD" names)))))
- (mapconcat (lambda (it) (magit-format-ref-label it head)) names " "))))
-
-(defun magit-object-type (object)
- (magit-git-string "cat-file" "-t" object))
-
-(defmacro magit-with-blob (commit file &rest body)
- (declare (indent 2)
- (debug (form form body)))
- `(with-temp-buffer
- (let ((buffer-file-name ,file))
- (save-excursion
- (magit-git-insert "cat-file" "-p"
- (concat ,commit ":" buffer-file-name)))
- (decode-coding-inserted-region
- (point-min) (point-max) buffer-file-name t nil nil t)
- ,@body)))
-
-(defmacro magit-with-temp-index (tree arg &rest body)
- (declare (indent 2) (debug (form form body)))
- (let ((file (cl-gensym "file")))
- `(let ((,file (magit-convert-git-filename
- (make-temp-name (magit-git-dir "index.magit.")))))
- (setq ,file (or (file-remote-p ,file 'localname) ,file))
- (unwind-protect
- (progn (--when-let ,tree
- (or (magit-git-success "read-tree" ,arg it
- (concat "--index-output=" ,file))
- (error "Cannot read tree %s" it)))
- (if (file-remote-p default-directory)
- (let ((magit-tramp-process-environment
- (cons (concat "GIT_INDEX_FILE=" ,file)
- magit-tramp-process-environment)))
- ,@body)
- (let ((process-environment
- (cons (concat "GIT_INDEX_FILE=" ,file)
- process-environment)))
- ,@body)))
- (ignore-errors
- (delete-file (concat (file-remote-p default-directory) ,file)))))))
-
-(defun magit-commit-tree (message &optional tree &rest parents)
- (magit-git-string "commit-tree" "--no-gpg-sign" "-m" message
- (--mapcat (list "-p" it) (delq nil parents))
- (or tree (magit-git-string "write-tree"))))
-
-(defun magit-commit-worktree (message &optional arg &rest other-parents)
- (magit-with-temp-index "HEAD" arg
- (and (magit-update-files (magit-modified-files))
- (apply #'magit-commit-tree message nil "HEAD" other-parents))))
-
-(defun magit-update-files (files)
- (magit-git-success "update-index" "--add" "--remove" "--" files))
-
-(defun magit-update-ref (ref message rev &optional stashish)
- (or (if (not (version< (magit-git-version) "2.6.0"))
- (magit-git-success "update-ref" "--create-reflog"
- "-m" message ref rev
- (or (magit-rev-verify ref) ""))
- ;; `--create-reflog' didn't exist before v2.6.0
- (let ((oldrev (magit-rev-verify ref))
- (logfile (magit-git-dir (concat "logs/" ref))))
- (unless (file-exists-p logfile)
- (when oldrev
- (magit-git-success "update-ref" "-d" ref oldrev))
- (make-directory (file-name-directory logfile) t)
- (with-temp-file logfile)
- (when (and oldrev (not stashish))
- (magit-git-success "update-ref" "-m" "enable reflog"
- ref oldrev ""))))
- (magit-git-success "update-ref" "-m" message ref rev
- (or (magit-rev-verify ref) "")))
- (error "Cannot update %s with %s" ref rev)))
-
-(defconst magit-range-re
- (concat "\\`\\([^ \t]*[^.]\\)?" ; revA
- "\\(\\.\\.\\.?\\)" ; range marker
- "\\([^.][^ \t]*\\)?\\'")) ; revB
-
-;;; Completion
-
-(defvar magit-revision-history nil)
-
-(defun magit-read-branch (prompt &optional default)
- (magit-completing-read prompt (magit-list-branch-names)
- nil t nil 'magit-revision-history
- (or (magit-branch-at-point)
- default (magit-get-current-branch))))
-
-(defun magit-read-branch-or-commit (prompt &optional secondary-default)
- (or (magit-completing-read prompt (cons "HEAD" (magit-list-refnames))
- nil nil nil 'magit-revision-history
- (or (magit-branch-or-commit-at-point)
- secondary-default
- (magit-get-current-branch)))
- (user-error "Nothing selected")))
-
-(defun magit-read-range-or-commit (prompt &optional secondary-default)
- (magit-read-range
- prompt
- (or (--when-let (magit-region-values 'commit 'branch)
- (deactivate-mark)
- (concat (car (last it)) ".." (car it)))
- (magit-branch-or-commit-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-range (prompt &optional default)
- (let* ((choose-completion-string-functions
- '(crm--choose-completion-string))
- (minibuffer-completion-table #'crm--collection-fn)
- (minibuffer-completion-confirm t)
- (crm-completion-table (magit-list-refnames))
- (crm-separator "\\.\\.\\.?")
- (input (read-from-minibuffer
- (concat prompt (and default (format " (%s)" default)) ": ")
- nil crm-local-completion-map
- nil 'magit-revision-history
- default)))
- (when (string-equal input "")
- (or (setq input default)
- (user-error "Nothing selected")))
- input))
-
-(defun magit-read-remote-branch
- (prompt &optional remote default local-branch require-match)
- (let ((choice (magit-completing-read
- prompt
- (-union (and local-branch
- (if remote
- (concat remote "/" local-branch)
- (--map (concat it "/" local-branch)
- (magit-list-remotes))))
- (magit-list-remote-branch-names remote t))
- nil require-match nil 'magit-revision-history default)))
- (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice))
- choice
- (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice))))
-
-(defun magit-read-refspec (prompt remote)
- (magit-completing-read prompt
- (prog2 (message "Determining available refs...")
- (magit-remote-list-refs remote)
- (message "Determining available refs...done"))))
-
-(defun magit-read-local-branch (prompt &optional secondary-default)
- (magit-completing-read prompt (magit-list-local-branch-names)
- nil t nil 'magit-revision-history
- (or (magit-local-branch-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-local-branch-or-commit (prompt)
- (let ((branches (magit-list-local-branch-names))
- (commit (magit-commit-at-point)))
- (or (magit-completing-read prompt
- (if commit (cons commit branches) branches)
- nil nil nil 'magit-revision-history
- (or (magit-local-branch-at-point) commit))
- (user-error "Nothing selected"))))
-
-(defun magit-read-local-branch-or-ref (prompt &optional secondary-default)
- (magit-completing-read prompt (nconc (magit-list-local-branch-names)
- (magit-list-refs "refs/"))
- nil t nil 'magit-revision-history
- (or (magit-local-branch-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-other-branch
- (prompt &optional exclude secondary-default no-require-match)
- (let* ((current (magit-get-current-branch))
- (atpoint (magit-branch-at-point))
- (exclude (or exclude current))
- (default (or (and (not (equal atpoint exclude)) atpoint)
- (and (not (equal current exclude)) current)
- secondary-default
- (magit-get-previous-branch))))
- (magit-completing-read prompt (delete exclude (magit-list-branch-names))
- nil (not no-require-match)
- nil 'magit-revision-history default)))
-
-(defun magit-read-other-branch-or-commit
- (prompt &optional exclude secondary-default)
- (let* ((current (magit-get-current-branch))
- (atpoint (magit-branch-or-commit-at-point))
- (exclude (or exclude current))
- (default (or (and (not (equal atpoint exclude)) atpoint)
- (and (not (equal current exclude)) current)
- secondary-default
- (magit-get-previous-branch))))
- (or (magit-completing-read prompt (delete exclude (magit-list-refnames))
- nil nil nil 'magit-revision-history default)
- (user-error "Nothing selected"))))
-
-(cl-defun magit-read-upstream-branch
- (&optional (branch (magit-get-current-branch)) prompt)
- (magit-completing-read
- (or prompt (format "Change upstream of %s to" branch))
- (-union (--map (concat it "/" branch)
- (magit-list-remotes))
- (delete branch (magit-list-branch-names)))
- nil nil nil 'magit-revision-history
- (or (let ((r (magit-remote-branch-at-point))
- (l (magit-branch-at-point)))
- (when (and l (equal l branch))
- (setq l nil))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (let ((r (magit-branch-p "origin/master"))
- (l (and (not (equal branch "master"))
- (magit-branch-p "master"))))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (let ((previous (magit-get-previous-branch)))
- (and (not (equal previous branch)) previous)))))
-
-(defun magit-read-starting-point (prompt)
- (or (magit-completing-read
- (concat prompt " starting at")
- (cons "HEAD" (magit-list-refnames))
- nil nil nil 'magit-revision-history
- (or (let ((r (magit-remote-branch-at-point))
- (l (magit-local-branch-at-point)))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (magit-commit-at-point)
- (magit-stash-at-point)
- (magit-get-current-branch)))
- (user-error "Nothing selected")))
-
-(defun magit-read-tag (prompt &optional require-match)
- (magit-completing-read prompt (magit-list-tags) nil
- require-match nil 'magit-revision-history
- (magit-tag-at-point)))
-
-(defun magit-read-stash (prompt &optional use-at-point)
- (let ((atpoint (magit-stash-at-point)))
- (or (and use-at-point atpoint)
- (let ((stashes (magit-git-lines "stash" "list" "--format=%gd")))
- (magit-completing-read prompt stashes nil t nil nil
- (or atpoint (car stashes)))))))
-
-(defun magit-read-remote (prompt &optional default use-only)
- (let ((remotes (magit-list-remotes)))
- (if (and use-only (= (length remotes) 1))
- (car remotes)
- (magit-completing-read prompt remotes
- nil t nil nil
- (or default
- (magit-remote-at-point)
- (magit-get-remote))))))
-
-(defun magit-read-remote-or-url (prompt &optional default)
- (magit-completing-read prompt
- (nconc (magit-list-remotes)
- (list "https://" "git://" "git@"))
- nil nil nil nil
- (or default
- (magit-remote-at-point)
- (magit-get-remote))))
-
-;;; Variables
-
-(defun magit-get (&rest keys)
- "Return the value of Git config entry specified by KEYS."
- (magit-git-str "config" (mapconcat 'identity keys ".")))
-
-(defun magit-get-all (&rest keys)
- "Return all values of the Git config entry specified by KEYS."
- (let ((magit-git-debug nil))
- (magit-git-lines "config" "--get-all" (mapconcat 'identity keys "."))))
-
-(defun magit-get-boolean (&rest keys)
- "Return the boolean value of Git config entry specified by KEYS."
- (magit-git-true "config" "--bool" (mapconcat 'identity keys ".")))
-
-(defun magit-set (val &rest keys)
- "Set Git config settings specified by KEYS to VAL."
- (if val
- (magit-git-string "config" (mapconcat 'identity keys ".") val)
- (magit-git-string "config" "--unset" (mapconcat 'identity keys "."))))
-
-;;; magit-git.el ends soon
-
-(define-obsolete-function-alias 'magit-get-tracked-ref
- 'magit-get-upstream-ref "Magit 2.4.0")
-(define-obsolete-function-alias 'magit-get-tracked-branch
- 'magit-get-upstream-branch "Magit 2.4.0")
-(define-obsolete-function-alias 'magit-get-tracked-remote
- 'magit-get-upstream-remote "Magit 2.4.0")
-
-(provide 'magit-git)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-git.el ends here
+++ /dev/null
-;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for looking at Git logs, including
-;; special logs like reflogs and cherry-logs, as well as for selecting
-;; a commit from a log.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-diff)
-
-(declare-function magit-blame-chunk-get 'magit-blame)
-(declare-function magit-blob-visit 'magit)
-(declare-function magit-find-file-noselect 'magit)
-(declare-function magit-insert-head-branch-header 'magit)
-(declare-function magit-insert-upstream-branch-header 'magit)
-(declare-function magit-read-file-from-rev 'magit)
-(declare-function magit-show-commit 'magit)
-(defvar magit-refs-indent-cherry-lines)
-(defvar magit-refs-show-commit-count)
-(defvar magit-status-sections-hook)
-
-(require 'ansi-color)
-(require 'crm)
-
-;;; Options
-;;;; Log Mode
-
-(defgroup magit-log nil
- "Inspect and manipulate Git history."
- :group 'magit-modes)
-
-(defcustom magit-log-mode-hook nil
- "Hook run after entering Magit-Log mode."
- :group 'magit-log
- :type 'hook)
-
-(defcustom magit-log-arguments '("-n256" "--graph" "--decorate")
- "The log arguments used in `magit-log-mode' buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L")
- "The log arguments that cause the `--graph' argument to be dropped."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type '(repeat (string :tag "Argument"))
- :options '("--follow" "--grep" "-G" "-S" "-L"))
-
-(defcustom magit-log-revision-headers-format "\
-%+b
-Author: %aN <%aE>
-Committer: %cN <%cE>"
- "Additional format string used with the `++header' argument."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type 'string)
-
-(defcustom magit-log-auto-more nil
- "Insert more log entries automatically when moving past the last entry.
-Only considered when moving past the last entry with
-`magit-goto-*-section' commands."
- :group 'magit-log
- :type 'boolean)
-
-(defcustom magit-log-show-margin t
- "Whether to initially show the margin in log buffers.
-
-When non-nil the author name and date are initially displayed in
-the margin of log buffers. The margin can be shown or hidden in
-the current buffer using the command `magit-toggle-margin'. In
-status buffers this option is ignored but it is possible to show
-the margin using the mentioned command."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type 'boolean)
-
-(defcustom magit-duration-spec
- `((?Y "year" "years" ,(round (* 60 60 24 365.2425)))
- (?M "month" "months" ,(round (* 60 60 24 30.436875)))
- (?w "week" "weeks" ,(* 60 60 24 7))
- (?d "day" "days" ,(* 60 60 24))
- (?h "hour" "hours" ,(* 60 60))
- (?m "minute" "minutes" 60)
- (?s "second" "seconds" 1))
- "Units used to display durations in a human format.
-The value is a list of time units, beginning with the longest.
-Each element has the form (CHAR UNIT UNITS SECONDS). UNIT is the
-time unit, UNITS is the plural of that unit. CHAR is a character
-abbreviation. And SECONDS is the number of seconds in one UNIT.
-Also see option `magit-log-margin-spec'."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type '(repeat (list (character :tag "Unit character")
- (string :tag "Unit singular string")
- (string :tag "Unit plural string")
- (integer :tag "Seconds in unit"))))
-
-(defcustom magit-log-margin-spec '(28 7 magit-duration-spec)
- "How to format the log margin.
-
-The log margin is used to display each commit's author followed
-by the commit's age. This option controls the total width of the
-margin and how time units are formatted, the value has the form:
-
- (WIDTH UNIT-WIDTH DURATION-SPEC)
-
-WIDTH specifies the total width of the log margin. UNIT-WIDTH is
-either the integer 1, in which case time units are displayed as a
-single characters, leaving more room for author names; or it has
-to be the width of the longest time unit string in DURATION-SPEC.
-DURATION-SPEC has to be a variable, its value controls which time
-units, in what language, are being used."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :set-after '(magit-duration-spec)
- :type '(list (integer :tag "Margin width")
- (choice :tag "Time unit style"
- (const :format "%t\n"
- :tag "abbreviate to single character" 1)
- (integer :format "%t\n"
- :tag "show full name" 7))
- (variable :tag "Duration spec variable")))
-
-(defcustom magit-log-show-refname-after-summary nil
- "Whether to show refnames after commit summaries.
-This is useful if you use really long branch names."
- :package-version '(magit . "2.2.0")
- :group 'magit-log
- :type 'boolean)
-
-(defface magit-log-graph
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for the graph part of the log output."
- :group 'magit-faces)
-
-(defface magit-log-author
- '((((class color) (background light)) :foreground "firebrick")
- (((class color) (background dark)) :foreground "tomato"))
- "Face for the author part of the log output."
- :group 'magit-faces)
-
-(defface magit-log-date
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for the date part of the log output."
- :group 'magit-faces)
-
-;;;; File Log
-
-(defcustom magit-log-buffer-file-locked t
- "Whether `magit-log-buffer-file' uses a decicated buffer."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :group 'magit-log
- :type 'boolean)
-
-;;;; Select Mode
-
-(defcustom magit-log-select-arguments '("-n256" "--decorate")
- "The log arguments used in `magit-log-select-mode' buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-log-select-show-usage 'both
- "Whether to show usage information when selecting a commit from a log.
-The message can be shown in the `echo-area' or the `header-line', or in
-`both' places. If the value isn't one of these symbols, then it should
-be nil, in which case no usage information is shown."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type '(choice (const :tag "in echo-area" echo-area)
- (const :tag "in header-line" header-line)
- (const :tag "in both places" both)
- (const :tag "nowhere")))
-
-;;;; Cherry Mode
-
-(defcustom magit-cherry-sections-hook
- '(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
- :type 'hook)
-
-;;;; Reflog Mode
-
-(defcustom magit-reflog-arguments '("-n256")
- "The log arguments used in `magit-reflog-mode' buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :group 'magit-commands
- :type '(repeat (string :tag "Argument")))
-
-(defcustom magit-reflog-show-margin t
- "Whether to initially show the margin in reflog buffers.
-
-When non-nil the author name and date are initially displayed in
-the margin of reflog buffers. The margin can be shown or hidden
-in the current buffer using the command `magit-toggle-margin'."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type 'boolean)
-
-(defface magit-reflog-commit '((t :foreground "green"))
- "Face for commit commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-amend '((t :foreground "magenta"))
- "Face for amend commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-merge '((t :foreground "green"))
- "Face for merge, checkout and branch commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-checkout '((t :foreground "blue"))
- "Face for checkout commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-reset '((t :foreground "red"))
- "Face for reset commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-rebase '((t :foreground "magenta"))
- "Face for rebase commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-cherry-pick '((t :foreground "green"))
- "Face for cherry-pick commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-remote '((t :foreground "cyan"))
- "Face for pull and clone commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-other '((t :foreground "cyan"))
- "Face for other commands in reflogs."
- :group 'magit-faces)
-
-;;;; Log Sections
-
-(defcustom magit-log-section-commit-count 10
- "How many recent commits to show in certain log sections.
-How many recent commits `magit-insert-recent-commits' and
-`magit-insert-unpulled-from-upstream-or-recent' (provided
-the upstream isn't ahead of the current branch) show."
- :package-version '(magit . "2.1.0")
- :group 'magit-status
- :type 'number)
-
-(defcustom magit-log-section-arguments '("-n256" "--decorate")
- "The log arguments used in buffers that show other things besides logs."
- :package-version '(magit . "2.4.0")
- :group 'magit-log
- :group 'magit-status
- :type '(repeat (string :tag "Argument")))
-
-(define-obsolete-variable-alias 'magit-log-section-args
- 'magit-log-section-arguments "2.2.0")
-
-;;; Commands
-
-(defvar magit-log-popup
- '(:variable magit-log-arguments
- :man-page "git-log"
- :switches ((?g "Show graph" "--graph")
- (?c "Show graph in color" "--color")
- (?d "Show refnames" "--decorate")
- (?S "Show signatures" "--show-signature")
- (?u "Show diffs" "--patch")
- (?s "Show diffstats" "--stat")
- (?h "Show header" "++header")
- (?D "Simplify by decoration" "--simplify-by-decoration")
- (?f "Follow renames when showing single-file log" "--follow"))
- :options ((?n "Limit number of commits" "-n")
- (?f "Limit to files" "-- " magit-read-files)
- (?a "Limit to author" "--author=")
- (?o "Order commits by" "++order=" magit-log-select-order)
- (?g "Search messages" "--grep=")
- (?G "Search changes" "-G")
- (?S "Search occurences" "-S")
- (?L "Trace line evolution" "-L" magit-read-file-trace))
- :actions ((?l "Log current" magit-log-current)
- (?L "Log local branches" magit-log-branches)
- (?r "Reflog current" magit-reflog-current)
- (?o "Log other" magit-log)
- (?b "Log all branches" magit-log-all-branches)
- (?O "Reflog other" magit-reflog)
- (?h "Log HEAD" magit-log-head)
- (?a "Log all references" magit-log-all)
- (?H "Reflog HEAD" magit-reflog-head))
- :default-action magit-log-current
- :max-action-columns 3))
-
-(defvar magit-log-mode-refresh-popup
- '(:variable magit-log-arguments
- :man-page "git-log"
- :switches ((?g "Show graph" "--graph")
- (?c "Show graph in color" "--color")
- (?d "Show refnames" "--decorate")
- (?S "Show signatures" "--show-signature")
- (?u "Show diffs" "--patch")
- (?s "Show diffstats" "--stat")
- (?D "Simplify by decoration" "--simplify-by-decoration")
- (?f "Follow renames when showing single-file log" "--follow"))
- :options ((?n "Limit number of commits" "-n")
- (?f "Limit to files" "-- " magit-read-files)
- (?a "Limit to author" "--author=")
- (?o "Order commits by" "++order=" magit-log-select-order)
- (?g "Search messages" "--grep=")
- (?G "Search changes" "-G")
- (?S "Search occurences" "-S")
- (?L "Trace line evolution" "-L" magit-read-file-trace))
- :actions ((?g "Refresh" magit-log-refresh)
- (?t "Toggle margin" magit-toggle-margin)
- (?s "Set defaults" magit-log-set-default-arguments) nil
- (?w "Save defaults" magit-log-save-default-arguments))
- :max-action-columns 2))
-
-(defvar magit-reflog-mode-refresh-popup
- '(:variable magit-reflog-arguments
- :man-page "git-reflog"
- :options ((?n "Limit number of commits" "-n"))))
-
-(defvar magit-log-refresh-popup
- '(:variable magit-log-arguments
- :man-page "git-log"
- :switches ((?g "Show graph" "--graph")
- (?c "Show graph in color" "--color")
- (?d "Show refnames" "--decorate"))
- :options ((?n "Limit number of commits" "-n")
- (?o "Order commits by" "++order=" magit-log-select-order))
- :actions ((?g "Refresh" magit-log-refresh)
- (?t "Toggle margin" magit-toggle-margin)
- (?s "Set defaults" magit-log-set-default-arguments) nil
- (?w "Save defaults" magit-log-save-default-arguments))
- :max-action-columns 2))
-
-(magit-define-popup-keys-deferred 'magit-log-popup)
-(magit-define-popup-keys-deferred 'magit-log-mode-refresh-popup)
-(magit-define-popup-keys-deferred 'magit-log-refresh-popup)
-
-(defun magit-read-file-trace (&rest _ignored)
- (let ((file (magit-read-file-from-rev "HEAD" "File"))
- (trace (magit-read-string "Trace")))
- (if (string-match
- "^\\(/.+/\\|:[^:]+\\|[0-9]+,[-+]?[0-9]+\\)\\(:\\)?$" trace)
- (concat trace (or (match-string 2 trace) ":") file)
- (user-error "Trace is invalid, see man git-log"))))
-
-(defun magit-log-select-order (&rest _ignored)
- (magit-read-char-case "Order commits by " t
- (?t "[t]opography" "topo")
- (?a "[a]uthor date" "author-date")
- (?c "[c]ommitter date" "date")))
-
-(defun magit-log-arguments (&optional refresh)
- (cond ((memq magit-current-popup
- '(magit-log-popup magit-log-refresh-popup))
- (magit-popup-export-file-args magit-current-popup-args))
- ((derived-mode-p 'magit-log-mode)
- (list (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (refresh
- (list magit-log-section-arguments nil))
- (t
- (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
- (with-current-buffer buffer
- (list (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (list (default-value 'magit-log-arguments) nil)))))
-
-(defun magit-log-popup (arg)
- "Popup console for log commands."
- (interactive "P")
- (let ((magit-log-refresh-popup
- (pcase major-mode
- (`magit-log-mode magit-log-mode-refresh-popup)
- (_ magit-log-refresh-popup)))
- (magit-log-arguments
- (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
- (with-current-buffer buffer
- (magit-popup-import-file-args (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (default-value 'magit-log-arguments))))
- (magit-invoke-popup 'magit-log-popup nil arg)))
-
-;;;###autoload
-(defun magit-log-buffer-file-popup ()
- "Popup console for log commands.
-
-This is a variant of `magit-log-popup' which shows the same popup
-but which limits the log to the file being visited in the current
-buffer."
- (interactive)
- (-if-let (file (magit-file-relative-name))
- (let ((magit-log-arguments
- (magit-popup-import-file-args
- (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
- (with-current-buffer buffer
- (nth 2 magit-refresh-args))
- (default-value 'magit-log-arguments))
- (list file))))
- (magit-invoke-popup 'magit-log-popup nil nil))
- (user-error "Buffer isn't visiting a file")))
-
-(defun magit-log-refresh-popup (arg)
- "Popup console for changing log arguments in the current buffer."
- (interactive "P")
- (magit-log-refresh-assert)
- (let ((magit-log-refresh-popup
- (cond ((derived-mode-p 'magit-log-select-mode)
- magit-log-refresh-popup)
- ((derived-mode-p 'magit-log-mode)
- (let ((def (copy-sequence magit-log-refresh-popup)))
- (plist-put def :switches (plist-get magit-log-popup :switches))
- (plist-put def :options (plist-get magit-log-popup :options))
- def))
- (t
- magit-log-refresh-popup)))
- (magit-log-arguments
- (cond ((derived-mode-p 'magit-log-select-mode)
- (cadr magit-refresh-args))
- ((derived-mode-p 'magit-log-mode)
- (magit-popup-import-file-args (nth 1 magit-refresh-args)
- (nth 2 magit-refresh-args)))
- (t
- magit-log-section-arguments))))
- (magit-invoke-popup 'magit-log-refresh-popup nil arg)))
-
-(defun magit-log-refresh (args files)
- "Set the local log arguments for the current buffer."
- (interactive (magit-log-arguments t))
- (magit-log-refresh-assert)
- (cond ((derived-mode-p 'magit-log-select-mode)
- (setcar (cdr magit-refresh-args) args))
- ((derived-mode-p 'magit-log-mode)
- (setcdr magit-refresh-args (list args files)))
- (t
- (setq-local magit-log-section-arguments args)))
- (magit-refresh))
-
-(defun magit-log-set-default-arguments (args files)
- "Set the global log arguments for the current buffer."
- (interactive (magit-log-arguments t))
- (magit-log-refresh-assert)
- (cond ((derived-mode-p 'magit-log-select-mode)
- (customize-set-variable 'magit-log-select-arguments args)
- (setcar (cdr magit-refresh-args) args))
- ((derived-mode-p 'magit-log-mode)
- (customize-set-variable 'magit-log-arguments args)
- (setcdr magit-refresh-args (list args files)))
- (t
- (customize-set-variable 'magit-log-section-arguments args)
- (kill-local-variable 'magit-log-section-arguments)))
- (magit-refresh))
-
-(defun magit-log-save-default-arguments (args files)
- "Set and save the global log arguments for the current buffer."
- (interactive (magit-log-arguments t))
- (magit-log-refresh-assert)
- (cond ((derived-mode-p 'magit-log-select-mode)
- (customize-save-variable 'magit-log-select-arguments args)
- (setcar (cdr magit-refresh-args) args))
- ((derived-mode-p 'magit-log-mode)
- (customize-save-variable 'magit-log-arguments args)
- (setcdr magit-refresh-args (list args files)))
- (t
- (customize-save-variable 'magit-log-section-arguments args)
- (kill-local-variable 'magit-log-section-arguments)))
- (magit-refresh))
-
-(defun magit-log-refresh-assert ()
- (cond ((derived-mode-p 'magit-reflog-mode)
- (user-error "Cannot change log arguments in reflog buffers"))
- ((derived-mode-p 'magit-cherry-mode)
- (user-error "Cannot change log arguments in cherry buffers"))))
-
-(defvar magit-log-read-revs-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map crm-local-completion-map)
- (define-key map "\s" 'self-insert-command)
- map))
-
-(defun magit-log-read-revs (&optional use-current)
- (or (and use-current (--when-let (magit-get-current-branch) (list it)))
- (let* ((choose-completion-string-functions
- '(crm--choose-completion-string))
- (minibuffer-completion-table #'crm--collection-fn)
- (minibuffer-completion-confirm t)
- (crm-completion-table
- `(,@(and (file-exists-p (magit-git-dir "FETCH_HEAD"))
- (list "FETCH_HEAD"))
- ,@(magit-list-branch-names)))
- (crm-separator "\\(\\.\\.\\.?\\|[, ]\\)")
- (default (or (magit-branch-or-commit-at-point)
- (unless use-current
- (magit-get-previous-branch))))
- (input (read-from-minibuffer
- (format "Log rev,s%s: "
- (if default (format " (%s)" default) ""))
- nil magit-log-read-revs-map
- nil 'magit-revision-history default)))
- (when (string-equal input "")
- (or (setq input default)
- (user-error "Nothing selected")))
- (split-string input "[, ]" t))))
-
-;;;###autoload
-(defun magit-log-current (revs &optional args files)
- "Show log for the current branch.
-When `HEAD' is detached or with a prefix argument show log for
-one or more revs read from the minibuffer."
- (interactive (cons (magit-log-read-revs t)
- (magit-log-arguments)))
- (magit-log revs args files))
-
-;;;###autoload
-(defun magit-log (revs &optional args files)
- "Show log for one or more revs read from the minibuffer.
-The user can input any revision or revisions separated by a
-space, or even ranges, but only branches and tags, and a
-representation of the commit at point, are available as
-completion candidates."
- (interactive (cons (magit-log-read-revs)
- (magit-log-arguments)))
- (require 'magit)
- (magit-mode-setup #'magit-log-mode revs args files)
- (magit-log-goto-same-commit))
-
-;;;###autoload
-(defun magit-log-head (&optional args files)
- "Show log for `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (list "HEAD") args files))
-
-;;;###autoload
-(defun magit-log-branches (&optional args files)
- "Show log for all local branches and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (if (magit-get-current-branch)
- (list "--branches")
- (list "HEAD" "--branches"))
- args files))
-
-;;;###autoload
-(defun magit-log-all-branches (&optional args files)
- "Show log for all local and remote branches and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (if (magit-get-current-branch)
- (list "--branches" "--remotes")
- (list "HEAD" "--branches" "--remotes"))
- args files))
-
-;;;###autoload
-(defun magit-log-all (&optional args files)
- "Show log for all references and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log (if (magit-get-current-branch)
- (list "--all")
- (list "HEAD" "--all"))
- args files))
-
-;;;###autoload
-(defun magit-log-buffer-file (&optional follow beg end)
- "Show log for the blob or file visited in the current buffer.
-With a prefix argument or when `--follow' is part of
-`magit-log-arguments', then follow renames."
- (interactive (if (region-active-p)
- (list current-prefix-arg
- (1- (line-number-at-pos (region-beginning)))
- (1- (line-number-at-pos (region-end))))
- (list current-prefix-arg)))
- (-if-let (file (magit-file-relative-name))
- (magit-mode-setup-internal
- #'magit-log-mode
- (list (list (or magit-buffer-refname
- (magit-get-current-branch)
- "HEAD"))
- (let ((args (car (magit-log-arguments))))
- (when (and follow (not (member "--follow" args)))
- (push "--follow" args))
- (when (and beg end)
- (setq args (cons (format "-L%s,%s:%s" beg end file)
- (cl-delete "-L" args :test
- 'string-prefix-p)))
- (setq file nil))
- args)
- (and file (list file)))
- magit-log-buffer-file-locked)
- (user-error "Buffer isn't visiting a file"))
- (magit-log-goto-same-commit))
-
-;;;###autoload
-(defun magit-reflog-current ()
- "Display the reflog of the current branch."
- (interactive)
- (magit-reflog (magit-get-current-branch)))
-
-;;;###autoload
-(defun magit-reflog (ref)
- "Display the reflog of a branch."
- (interactive (list (magit-read-local-branch-or-ref "Show reflog for")))
- (magit-mode-setup #'magit-reflog-mode ref magit-reflog-arguments))
-
-;;;###autoload
-(defun magit-reflog-head ()
- "Display the `HEAD' reflog."
- (interactive)
- (magit-reflog "HEAD"))
-
-(defun magit-log-toggle-commit-limit ()
- "Toggle the number of commits the current log buffer is limited to.
-If the number of commits is currently limited, then remove that
-limit. Otherwise set it to 256."
- (interactive)
- (magit-log-set-commit-limit (lambda (&rest _) nil)))
-
-(defun magit-log-double-commit-limit ()
- "Double the number of commits the current log buffer is limited to."
- (interactive)
- (magit-log-set-commit-limit '*))
-
-(defun magit-log-half-commit-limit ()
- "Half the number of commits the current log buffer is limited to."
- (interactive)
- (magit-log-set-commit-limit '/))
-
-(defun magit-log-set-commit-limit (fn)
- (let* ((val (car (magit-log-arguments t)))
- (arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val))
- (num (and arg (string-to-number (match-string 1 arg))))
- (num (if num (funcall fn num 2) 256)))
- (setq val (delete arg val))
- (setcar (cdr magit-refresh-args)
- (if (and num (> num 0))
- (cons (format "-n%i" num) val)
- val)))
- (magit-refresh))
-
-(defun magit-log-get-commit-limit ()
- (--when-let (--first (string-match "^-n\\([0-9]+\\)?$" it)
- (car (magit-log-arguments t)))
- (string-to-number (match-string 1 it))))
-
-(defun magit-log-bury-buffer (&optional arg)
- "Bury the current buffer or the revision buffer in the same frame.
-Like `magit-mode-bury-buffer' (which see) but with a negative
-prefix argument instead bury the revision buffer, provided it
-is displayed in the current frame."
- (interactive "p")
- (if (< arg 0)
- (let* ((buf (magit-mode-get-buffer 'magit-revision-mode))
- (win (and buf (get-buffer-window buf (selected-frame)))))
- (if win
- (with-selected-window win
- (with-current-buffer buf
- (magit-mode-bury-buffer (> (abs arg) 1))))
- (user-error "No revision buffer in this frame")))
- (magit-mode-bury-buffer (> arg 1))))
-
-;;; Log Mode
-
-(defvar magit-log-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-c\C-b" 'magit-go-backward)
- (define-key map "\C-c\C-f" 'magit-go-forward)
- (define-key map "=" 'magit-log-toggle-commit-limit)
- (define-key map "+" 'magit-log-double-commit-limit)
- (define-key map "-" 'magit-log-half-commit-limit)
- (define-key map "q" 'magit-log-bury-buffer)
- map)
- "Keymap for `magit-log-mode'.")
-
-(define-derived-mode magit-log-mode magit-mode "Magit Log"
- "Mode for looking at Git log.
-
-This mode is documented in info node `(magit)Log Buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-branch-popup] to see available branch commands.
-Type \\[magit-merge-popup] to merge the branch or commit at point.
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-Type \\[magit-reset] to reset HEAD to the commit at point.
-
-\\{magit-log-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(defvar magit-log-disable-graph-hack-args
- '("-G" "--grep" "--author")
- "Arguments which disable the graph speedup hack.")
-
-(defun magit-log-refresh-buffer (revs args files)
- (setq header-line-format
- (propertize
- (concat " Commits in " (mapconcat 'identity revs " ")
- (and files (concat " touching "
- (mapconcat 'identity files " "))))
- 'face 'magit-header-line))
- (unless (= (length files) 1)
- (setq args (remove "--follow" args)))
- (when (--any-p (string-match-p
- (concat "^" (regexp-opt magit-log-remove-graph-args)) it)
- args)
- (setq args (remove "--graph" args)))
- (unless (member "--graph" args)
- (setq args (remove "--color" args)))
- (-when-let* ((limit (magit-log-get-commit-limit))
- (limit (* 2 limit)) ; increase odds for complete graph
- (count (and (= (length revs) 1)
- (> limit 1024) ; otherwise it's fast enough
- (setq revs (car revs))
- (not (string-match-p "\\.\\." revs))
- (not (member revs '("--all" "--branches")))
- (-none-p (lambda (arg)
- (--any-p (string-prefix-p it arg)
- magit-log-disable-graph-hack-args))
- args)
- (magit-git-string "rev-list" "--count"
- "--first-parent" args revs))))
- (setq revs (if (< (string-to-number count) limit)
- revs
- (format "%s~%s..%s" revs limit revs))))
- (magit-insert-section (logbuf)
- (magit-insert-log revs args files)))
-
-(defun magit-insert-log (revs &optional args files)
- "Insert a log section.
-Do not add this to a hook variable."
- (magit-git-wash (apply-partially #'magit-log-wash-log 'log)
- "log"
- (format "--format=%%h%s %s[%%aN][%%at]%%s%s"
- (if (member "--decorate" args) "%d" "")
- (if (member "--show-signature" args)
- (progn (setq args (remove "--show-signature" args)) "%G?")
- "")
- (if (member "++header" args)
- (if (member "--graph" (setq args (remove "++header" args)))
- (concat "\n" magit-log-revision-headers-format "\n")
- (concat "\n\1e" magit-log-revision-headers-format "\1e\n"))
- ""))
- (progn
- (--when-let (--first (string-match "^\\+\\+order=\\(.+\\)$" it) args)
- (setq args (cons (format "--%s-order" (match-string 1 it))
- (remove it args))))
- (if (member "--decorate" args)
- (cons "--decorate=full" (remove "--decorate" args))
- args))
- "--use-mailmap" "--no-prefix" revs "--" files))
-
-(defvar magit-commit-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-show-commit)
- (define-key map "a" 'magit-cherry-apply)
- map)
- "Keymap for `commit' sections.")
-
-(defvar magit-module-commit-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-show-commit)
- map)
- "Keymap for `module-commit' sections.")
-
-(defconst magit-log-heading-re
- (concat "^"
- "\\(?4:[-_/|\\*o. ]*\\)" ; graph
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs
- "\\(?7:[BGUN]\\)?" ; gpg
- "\\[\\(?5:[^]]*\\)\\]" ; author
- "\\[\\(?6:[^]]*\\)\\]" ; date
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-cherry-re
- (concat "^"
- "\\(?8:[-+]\\) " ; cherry
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-module-re
- (concat "^"
- "\\(?:\\(?11:[<>]\\) \\)?" ; side
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-bisect-vis-re
- (concat "^"
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-bisect-log-re
- (concat "^# "
- "\\(?3:bad:\\|skip:\\|good:\\) " ; "refs"
- "\\[\\(?1:[^]]+\\)\\] " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-reflog-re
- (concat "^"
- "\\(?1:[^ ]+\\) " ; sha1
- "\\(?:\\(?:[^@]+@{\\(?6:[^}]+\\)} " ; date
- "\\(?10:merge \\|autosave \\|restart \\|[^:]+: \\)?" ; refsub
- "\\(?2:.*\\)?\\)\\| \\)$")) ; msg
-
-(defconst magit-reflog-subject-re
- (concat "\\(?1:[^ ]+\\) ?" ; command
- "\\(?2:\\(?: ?-[^ ]+\\)+\\)?" ; option
- "\\(?: ?(\\(?3:[^)]+\\))\\)?")) ; type
-
-(defconst magit-log-stash-re
- (concat "^"
- "\\(?1:[^ ]+\\)" ; "sha1"
- "\\(?5: \\)" ; "author"
- "\\(?6:[^ ]+\\) " ; date
- "\\(?2:.*\\)$")) ; msg
-
-(defvar magit-log-count nil)
-
-(defun magit-log-wash-log (style args)
- (setq args (-flatten args))
- (when (and (member "--graph" args)
- (member "--color" args))
- (let ((ansi-color-apply-face-function
- (lambda (beg end face)
- (put-text-property beg end 'font-lock-face
- (or face 'magit-log-graph)))))
- (ansi-color-apply-on-region (point-min) (point-max))))
- (when (eq style 'cherry)
- (reverse-region (point-min) (point-max)))
- (let ((magit-log-count 0)
- (abbrev (magit-abbrev-length)))
- (magit-wash-sequence (apply-partially 'magit-log-wash-rev style abbrev))
- (if (derived-mode-p 'magit-log-mode)
- (when (eq magit-log-count (magit-log-get-commit-limit))
- (magit-insert-section (longer)
- (insert-text-button
- (substitute-command-keys
- (format "Type \\<%s>\\[%s] to show more history"
- 'magit-log-mode-map
- 'magit-log-double-commit-limit))
- 'action (lambda (_button)
- (magit-log-double-commit-limit))
- 'follow-link t
- 'mouse-face 'magit-section-highlight)))
- (unless (equal (car args) "cherry")
- (insert ?\n)))))
-
-(defun magit-log-wash-rev (style abbrev)
- (when (derived-mode-p 'magit-log-mode)
- (cl-incf magit-log-count))
- (looking-at (pcase style
- (`log magit-log-heading-re)
- (`cherry magit-log-cherry-re)
- (`module magit-log-module-re)
- (`reflog magit-log-reflog-re)
- (`stash magit-log-stash-re)
- (`bisect-vis magit-log-bisect-vis-re)
- (`bisect-log magit-log-bisect-log-re)))
- (magit-bind-match-strings
- (hash msg refs graph author date gpg cherry _ refsub side) nil
- (let ((align (not (member "--stat" (cadr magit-refresh-args)))))
- (magit-delete-line)
- (magit-insert-section section (commit hash)
- (pcase style
- (`stash (setf (magit-section-type section) 'stash))
- (`module (setf (magit-section-type section) 'module-commit))
- (`bisect-log (setq hash (magit-rev-parse "--short" hash))))
- (when cherry
- (when (and (derived-mode-p 'magit-refs-mode)
- magit-refs-show-commit-count)
- (insert (make-string magit-refs-indent-cherry-lines ?\s)))
- (insert (propertize cherry 'face (if (string= cherry "-")
- 'magit-cherry-equivalent
- 'magit-cherry-unmatched)))
- (insert ?\s))
- (when side
- (insert (propertize side 'face (if (string= side "<")
- 'magit-cherry-equivalent
- 'magit-cherry-unmatched)))
- (insert ?\s))
- (when align
- (insert (propertize hash 'face 'magit-hash) ?\s))
- (when graph
- (insert graph))
- (unless align
- (insert (propertize hash 'face 'magit-hash) ?\s))
- (when (and refs (not magit-log-show-refname-after-summary))
- (insert (magit-format-ref-labels refs) ?\s))
- (when refsub
- (insert (format "%-2s " (1- magit-log-count)))
- (insert (magit-reflog-format-subject
- (substring refsub 0 (if (string-match-p ":" refsub) -2 -1)))))
- (when msg
- (insert (propertize msg 'face
- (pcase (and gpg (aref gpg 0))
- (?G 'magit-signature-good)
- (?B 'magit-signature-bad)
- (?U 'magit-signature-untrusted)))))
- (when (and refs magit-log-show-refname-after-summary)
- (insert ?\s)
- (insert (magit-format-ref-labels refs)))
- (insert ?\n)
- (when (memq style '(log reflog stash))
- (goto-char (line-beginning-position))
- (when (and refsub
- (string-match "\\`\\([^ ]\\) \\+\\(..\\)\\(..\\)" date))
- (setq date (+ (string-to-number (match-string 1 date))
- (* (string-to-number (match-string 2 date)) 60 60)
- (* (string-to-number (match-string 3 date)) 60))))
- (save-excursion
- (backward-char)
- (magit-format-log-margin author date)))
- (when (and (eq style 'log)
- (not (or (eobp) (looking-at magit-log-heading-re))))
- (when (looking-at "\1e")
- (magit-insert-heading)
- (delete-char 1)
- (magit-insert-section (commit-header)
- (forward-line)
- (magit-insert-heading)
- (re-search-forward "\1e")
- (backward-delete-char 1)
- (forward-char)
- (insert ?\n))
- (delete-char 1))
- (if (looking-at "^\\(---\\|\n\s\\|\ndiff\\)")
- (let ((limit (save-excursion
- (and (re-search-forward magit-log-heading-re nil t)
- (match-beginning 0)))))
- (unless (magit-section-content magit-insert-section--current)
- (magit-insert-heading))
- (delete-char (if (looking-at "\n") 1 4))
- (magit-diff-wash-diffs (list "--stat") limit))
- (when align
- (setq align (make-string (1+ abbrev) ? )))
- (when (and (not (eobp)) (not (looking-at magit-log-heading-re)))
- (when align
- (setq align (make-string (1+ abbrev) ? )))
- (while (and (not (eobp)) (not (looking-at magit-log-heading-re)))
- (when align
- (save-excursion (insert align)))
- (magit-format-log-margin)
- (forward-line))
- ;; When `--format' is used and its value isn't one of the
- ;; predefined formats, then `git-log' does not insert a
- ;; separator line.
- (save-excursion
- (forward-line -1)
- (looking-at "[-_/|\\*o. ]*"))
- (setq graph (match-string 0))
- (unless (string-match-p "[/\\]" graph)
- (insert graph ?\n))))))))
- t)
-
-(defun magit-format-log-margin (&optional author date)
- (-let [(width unit-width duration-spec) magit-log-margin-spec]
- (when (and date (not author))
- (setq width (+ (if (= unit-width 1) 1 (1+ unit-width))
- (if (derived-mode-p 'magit-log-mode) 1 0))))
- (if date
- (magit-make-margin-overlay
- (and author
- (concat (propertize (truncate-string-to-width
- (or author "")
- (- width 1 3 ; gap, digits
- (if (= unit-width 1) 1 (1+ unit-width))
- (if (derived-mode-p 'magit-log-mode) 1 0))
- nil ?\s (make-string 1 magit-ellipsis))
- 'face 'magit-log-author)
- " "))
- (propertize (magit-format-duration
- (abs (truncate (- (float-time)
- (string-to-number date))))
- (symbol-value duration-spec)
- unit-width)
- 'face 'magit-log-date)
- (and (derived-mode-p 'magit-log-mode)
- (propertize " " 'face 'fringe)))
- (magit-make-margin-overlay
- (propertize (make-string (1- width) ?\s) 'face 'default)
- (propertize " " 'face 'fringe)))))
-
-(defun magit-format-duration (duration spec &optional width)
- (-let [(char unit units weight) (car spec)]
- (let ((cnt (round (/ duration weight 1.0))))
- (if (or (not (cdr spec))
- (>= (/ duration weight) 1))
- (if (eq width 1)
- (format "%3i%c" cnt char)
- (format (if width (format "%%3i %%-%is" width) "%i %s")
- cnt (if (= cnt 1) unit units)))
- (magit-format-duration duration (cdr spec) width)))))
-
-(defun magit-log-maybe-show-more-commits (section)
- "Automatically insert more commit sections in a log.
-Only do so if `point' is on the \"show more\" section,
-and `magit-log-auto-more' is non-nil."
- (when (and (eq (magit-section-type section) 'longer)
- magit-log-auto-more)
- (magit-log-double-commit-limit)
- (forward-line -1)
- (magit-section-forward)))
-
-(defvar magit--update-revision-buffer nil)
-
-(defun magit-log-maybe-update-revision-buffer (&optional _)
- "When moving in the log buffer, update the revision buffer.
-If there is no revision buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-log-mode)
- (magit-log-maybe-update-revision-buffer-1)))
-
-(defun magit-log-maybe-update-revision-buffer-1 ()
- (unless magit--update-revision-buffer
- (-when-let* ((commit (magit-section-when 'commit))
- (buffer (magit-mode-get-buffer 'magit-revision-mode nil t)))
- (setq magit--update-revision-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (-let [(rev buf) magit--update-revision-buffer]
- (setq magit--update-revision-buffer nil)
- (when (buffer-live-p buf)
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-show-commit rev (magit-diff-arguments)))))
- (setq magit--update-revision-buffer nil))))))
-
-(defvar magit--update-blob-buffer nil)
-
-(defun magit-log-maybe-update-blob-buffer (&optional _)
- "When moving in the log buffer, update the blob buffer.
-If there is no blob buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-log-mode)
- (magit-log-maybe-update-blob-buffer-1)))
-
-(defun magit-log-maybe-update-blob-buffer-1 ()
- (unless magit--update-revision-buffer
- (-when-let* ((commit (magit-section-when 'commit))
- (buffer (--first (with-current-buffer it magit-buffer-revision)
- (-map #'window-buffer (window-list)))))
- (setq magit--update-blob-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (-let [(rev buf) magit--update-blob-buffer]
- (setq magit--update-blob-buffer nil)
- (when (buffer-live-p buf)
- (save-excursion
- (with-selected-window (get-buffer-window buf)
- (with-current-buffer buf
- (magit-blob-visit (list (magit-rev-parse rev)
- (magit-file-relative-name
- magit-buffer-file-name))
- (line-number-at-pos))))))))))))
-
-(defun magit-log-goto-same-commit ()
- (-when-let* ((prev magit-previous-section)
- (rev (cond ((magit-section-match 'commit prev)
- (magit-section-value prev))
- ((magit-section-match 'branch prev)
- (magit-rev-format
- "%h" (magit-section-value prev)))))
- (same (--first (equal (magit-section-value it) rev)
- (magit-section-children magit-root-section))))
- (goto-char (magit-section-start same))))
-
-;;; Select Mode
-
-(defvar magit-log-select-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-log-mode-map)
- (define-key map "\C-c\C-b" 'undefined)
- (define-key map "\C-c\C-f" 'undefined)
- (define-key map "." 'magit-log-select-pick)
- (define-key map "e" 'magit-log-select-pick)
- (define-key map "\C-c\C-c" 'magit-log-select-pick)
- (define-key map "q" 'magit-log-select-quit)
- (define-key map "\C-c\C-k" 'magit-log-select-quit)
- map)
- "Keymap for `magit-log-select-mode'.")
-
-(put 'magit-log-select-pick :advertised-binding [?\C-c ?\C-c])
-(put 'magit-log-select-quit :advertised-binding [?\C-c ?\C-k])
-
-(define-derived-mode magit-log-select-mode magit-log-mode "Magit Select"
- "Mode for selecting a commit from history.
-
-This mode is documented in info node `(magit)Select from log'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-\\<magit-log-select-mode-map>\
-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))
-
-(defun magit-log-select-refresh-buffer (rev args)
- (magit-insert-section (logbuf)
- (magit-insert-log rev args)))
-
-(defvar-local magit-log-select-pick-function nil)
-(defvar-local magit-log-select-quit-function nil)
-
-(defun magit-log-select (pick &optional msg quit branch)
- (declare (indent defun))
- (magit-mode-setup #'magit-log-select-mode
- (or branch (magit-get-current-branch) "HEAD")
- magit-log-select-arguments)
- (magit-log-goto-same-commit)
- (setq magit-log-select-pick-function pick)
- (setq magit-log-select-quit-function quit)
- (when magit-log-select-show-usage
- (setq msg (substitute-command-keys
- (format-spec
- (if msg
- (if (string-suffix-p "," msg)
- (concat msg " or %q to abort")
- msg)
- "Type %p to select commit at point, or %q to abort")
- '((?p . "\\[magit-log-select-pick]")
- (?q . "\\[magit-log-select-quit]")))))
- (when (memq magit-log-select-show-usage '(both header-line))
- (setq header-line-format (propertize (concat " " msg) 'face 'bold)))
- (when (memq magit-log-select-show-usage '(both echo-area))
- (message "%s" msg))))
-
-(defun magit-log-select-pick ()
- "Select the commit at point and act on it.
-Call `magit-log-select-pick-function' with the selected
-commit as argument."
- (interactive)
- (let ((fun magit-log-select-pick-function)
- (rev (magit-commit-at-point)))
- (kill-buffer (current-buffer))
- (funcall fun rev)))
-
-(defun magit-log-select-quit ()
- "Abort selecting a commit, don't act on any commit."
- (interactive)
- (kill-buffer (current-buffer))
- (when magit-log-select-quit-function
- (funcall magit-log-select-quit-function)))
-
-;;; Cherry Mode
-
-(defvar magit-cherry-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "q" 'magit-log-bury-buffer)
- (define-key map "L" 'magit-toggle-margin)
- map)
- "Keymap for `magit-cherry-mode'.")
-
-(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry"
- "Mode for looking at commits not merged upstream.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-
-\\{magit-cherry-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-;;;###autoload
-(defun magit-cherry (head upstream)
- "Show commits in a branch that are not merged in the upstream branch."
- (interactive
- (let ((head (magit-read-branch "Cherry head")))
- (list head (magit-read-other-branch "Cherry upstream" head
- (magit-get-upstream-branch head)))))
- (magit-mode-setup #'magit-cherry-mode upstream head))
-
-(defun magit-cherry-refresh-buffer (_upstream _head)
- (magit-insert-section (cherry)
- (run-hooks 'magit-cherry-sections-hook)))
-
-(defun magit-insert-cherry-headers ()
- "Insert headers appropriate for `magit-cherry-mode' buffers."
- (magit-insert-head-branch-header (nth 1 magit-refresh-args))
- (magit-insert-upstream-branch-header (nth 1 magit-refresh-args)
- (nth 0 magit-refresh-args)
- "Upstream: ")
- (insert ?\n))
-
-(defun magit-insert-cherry-commits ()
- "Insert commit sections into a `magit-cherry-mode' buffer."
- (magit-insert-section (cherries)
- (magit-insert-heading "Cherry commits:")
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" "--abbrev" magit-refresh-args)))
-
-;;; Reflog Mode
-
-(defvar magit-reflog-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-log-mode-map)
- (define-key map "L" 'magit-toggle-margin)
- map)
- "Keymap for `magit-reflog-mode'.")
-
-(define-derived-mode magit-reflog-mode magit-log-mode "Magit Reflog"
- "Mode for looking at Git reflog.
-
-This mode is documented in info node `(magit)Reflog'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-Type \\[magit-reset] to reset HEAD to the commit at point.
-
-\\{magit-reflog-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-reflog-refresh-buffer (ref args)
- (setq header-line-format
- (propertize (concat " Reflog for " ref) 'face 'magit-header-line))
- (magit-insert-section (reflogbuf)
- (magit-git-wash (apply-partially 'magit-log-wash-log 'reflog)
- "reflog" "show" "--format=%h %gd %gs" "--date=raw" args ref)))
-
-(defvar magit-reflog-labels
- '(("commit" . magit-reflog-commit)
- ("amend" . magit-reflog-amend)
- ("merge" . magit-reflog-merge)
- ("checkout" . magit-reflog-checkout)
- ("branch" . magit-reflog-checkout)
- ("reset" . magit-reflog-reset)
- ("rebase" . magit-reflog-rebase)
- ("cherry-pick" . magit-reflog-cherry-pick)
- ("initial" . magit-reflog-commit)
- ("pull" . magit-reflog-remote)
- ("clone" . magit-reflog-remote)
- ("autosave" . magit-reflog-commit)
- ("restart" . magit-reflog-reset)))
-
-(defun magit-reflog-format-subject (subject)
- (let* ((match (string-match magit-reflog-subject-re subject))
- (command (and match (match-string 1 subject)))
- (option (and match (match-string 2 subject)))
- (type (and match (match-string 3 subject)))
- (label (if (string= command "commit")
- (or type command)
- command))
- (text (if (string= command "commit")
- label
- (mapconcat #'identity
- (delq nil (list command option type))
- " "))))
- (format "%-16s "
- (propertize text 'face
- (or (cdr (assoc label magit-reflog-labels))
- 'magit-reflog-other)))))
-
-;;; Log Sections
-;;;; Standard Log Sections
-
-(defvar magit-unpulled-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
- map)
- "Keymap for `unpulled' sections.")
-
-(magit-define-section-jumper magit-jump-to-unpulled-from-upstream
- "Unpulled from @{upstream}" unpulled "..@{upstream}")
-
-(defun magit-insert-unpulled-from-upstream ()
- "Insert commits that haven't been pulled from the upstream yet."
- (when (magit-git-success "rev-parse" "@{upstream}")
- (magit-insert-section (unpulled "..@{upstream}")
- (magit-insert-heading
- (format (propertize "Unpulled from %s:" 'face 'magit-section-heading)
- (magit-get-upstream-branch)))
- (magit-insert-log "..@{upstream}" magit-log-section-arguments)
- (magit-section-cache-visibility))))
-
-(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote
- "Unpulled from <push-remote>" unpulled
- (concat ".." (magit-get-push-branch)))
-
-(defun magit-insert-unpulled-from-pushremote ()
- "Insert commits that haven't been pulled from the push-remote yet."
- (--when-let (magit-get-push-branch)
- (unless (and (equal (magit-rev-name it)
- (magit-rev-name "@{upstream}"))
- (or (memq 'magit-insert-unpulled-from-upstream
- magit-status-sections-hook)
- (memq 'magit-insert-unpulled-from-upstream-or-recent
- magit-status-sections-hook)))
- (magit-insert-section (unpulled (concat ".." it))
- (magit-insert-heading
- (format (propertize "Unpulled from %s:" 'face 'magit-section-heading)
- (propertize it 'face 'magit-branch-remote)))
- (magit-insert-log (concat ".." it) magit-log-section-arguments)
- (magit-section-cache-visibility)))))
-
-(defvar magit-unpushed-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
- map)
- "Keymap for `unpushed' sections.")
-
-(magit-define-section-jumper magit-jump-to-unpushed-to-upstream
- "Unpushed to @{upstream}" unpushed "@{upstream}..")
-
-(defun magit-insert-unpushed-to-upstream ()
- "Insert commits that haven't been pushed to the upstream yet."
- (when (magit-git-success "rev-parse" "@{upstream}")
- (magit-insert-section (unpushed "@{upstream}..")
- (magit-insert-heading
- (format (propertize "Unmerged into %s:" 'face 'magit-section-heading)
- (magit-get-upstream-branch)))
- (magit-insert-log "@{upstream}.." magit-log-section-arguments)
- (magit-section-cache-visibility))))
-
-(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote
- "Unpushed to <push-remote>" unpushed
- (concat (magit-get-push-branch) ".."))
-
-(defun magit-insert-unpushed-to-pushremote ()
- "Insert commits that haven't been pushed to the push-remote yet."
- (--when-let (magit-get-push-branch)
- (unless (and (equal (magit-rev-name it)
- (magit-rev-name "@{upstream}"))
- (memq 'magit-insert-unpushed-to-upstream
- magit-status-sections-hook))
- (magit-insert-section (unpushed (concat it ".."))
- (magit-insert-heading
- (format (propertize "Unpushed to %s:" 'face 'magit-section-heading)
- (propertize it 'face 'magit-branch-remote)))
- (magit-insert-log (concat it "..") magit-log-section-arguments)
- (magit-section-cache-visibility)))))
-
-(defun magit-insert-recent-commits (&optional collapse)
- "Insert section showing recent commits.
-Show the last `magit-log-section-commit-count' commits."
- (let* ((start (format "HEAD~%s" magit-log-section-commit-count))
- (range (and (magit-rev-verify start)
- (concat start "..HEAD"))))
- (magit-insert-section (recent range collapse)
- (magit-insert-heading "Recent commits:")
- (magit-insert-log range
- (cons (format "-%d" magit-log-section-commit-count)
- magit-log-section-arguments)))))
-
-(defun magit-insert-unpulled-from-upstream-or-recent ()
- "Insert section showing unpulled or recent commits.
-If an upstream is configured for the current branch and it is
-ahead of the current branch, then show the commits that have
-not yet been pulled into the current branch. If no upstream is
-configured or if the upstream is not ahead of the current branch,
-then show the last `magit-log-section-commit-count' commits."
- (let ((upstream (magit-rev-parse "@{upstream}")))
- (if (or (not upstream)
- (equal upstream (magit-rev-parse "HEAD")))
- (magit-insert-recent-commits t)
- (magit-insert-unpulled-from-upstream))))
-
-;;;; Auxiliary Log Sections
-
-(defun magit-insert-unpulled-cherries ()
- "Insert section showing unpulled commits.
-Like `magit-insert-unpulled-to-upstream' but prefix each commit
-which has not been applied yet (i.e. a commit with a patch-id
-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-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" (magit-abbrev-arg)
- (magit-get-current-branch) "@{upstream}"))))
-
-(defun magit-insert-unpushed-cherries ()
- "Insert section showing unpushed commits.
-Like `magit-insert-unpushed-to-upstream' but prefix each commit
-which has not been applied to upstream yet (i.e. a commit with
-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-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" (magit-abbrev-arg) "@{upstream}"))))
-
-;;; Buffer Margins
-
-(defvar-local magit-set-buffer-margin-refresh nil)
-
-(defvar-local magit-show-margin nil)
-(put 'magit-show-margin 'permanent-local t)
-
-(defun magit-toggle-margin ()
- "Show or hide the Magit margin."
- (interactive)
- (unless (derived-mode-p 'magit-log-mode 'magit-status-mode 'magit-refs-mode)
- (user-error "Buffer doesn't contain any logs"))
- (magit-set-buffer-margin (not (cdr (window-margins)))))
-
-(defun magit-maybe-show-margin ()
- "Maybe show the margin, depending on the major-mode and an option.
-Supported modes are `magit-log-mode' and `magit-reflog-mode',
-and the respective options are `magit-log-show-margin' and
-`magit-reflog-show-margin'."
- (if (local-variable-p 'magit-show-margin)
- (magit-set-buffer-margin magit-show-margin)
- (pcase major-mode
- (`magit-log-mode (magit-set-buffer-margin magit-log-show-margin))
- (`magit-reflog-mode (magit-set-buffer-margin magit-reflog-show-margin)))))
-
-(defun magit-set-buffer-margin (enable)
- (let ((width (cond ((not enable) nil)
- ((derived-mode-p 'magit-reflog-mode)
- (+ (cadr magit-log-margin-spec) 5))
- (t (car magit-log-margin-spec)))))
- (setq magit-show-margin width)
- (when (and enable magit-set-buffer-margin-refresh)
- (magit-refresh))
- (-when-let (window (get-buffer-window))
- (with-selected-window window
- (set-window-margins nil (car (window-margins)) width)
- (if enable
- (add-hook 'window-configuration-change-hook
- 'magit-set-buffer-margin-1 nil t)
- (remove-hook 'window-configuration-change-hook
- 'magit-set-buffer-margin-1 t))))))
-
-(defun magit-set-buffer-margin-1 ()
- (-when-let (window (get-buffer-window))
- (with-selected-window window
- (set-window-margins nil (car (window-margins)) magit-show-margin))))
-
-(defun magit-make-margin-overlay (&rest strings)
- ;; Don't put the overlay on the complete line to work around #1880.
- (let ((o (make-overlay (1+ (line-beginning-position))
- (line-end-position)
- nil t)))
- (overlay-put o 'evaporate t)
- (overlay-put o 'before-string
- (propertize "o" 'display
- (list '(margin right-margin)
- (apply #'concat strings))))))
-
-;;; magit-log.el ends soon
-
-(define-obsolete-function-alias 'magit-insert-unpulled-or-recent-commits
- 'magit-insert-unpulled-from-upstream-or-recent "Magit 2.4.0")
-
-(provide 'magit-log)
-;; Local Variables:
-;; coding: utf-8
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-log.el ends here
+++ /dev/null
-;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements the abstract major-mode `magit-mode' from
-;; which almost all other Magit major-modes derive. The code in here
-;; is mostly concerned with creating and refreshing Magit buffers.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-section)
-(require 'magit-git)
-
-;; For `magit-xref-insert-buttons' from `magit'
-(defvar magit-diff-show-xref-buttons)
-(defvar magit-revision-show-xref-buttons)
-;; For `magit-refresh' and `magit-refresh-all'
-(declare-function magit-auto-revert-buffers 'magit-autorevert)
-
-(require 'format-spec)
-(require 'help-mode)
-
-;;; Options
-
-(defcustom magit-mode-hook
- '(magit-load-config-extensions
- magit-xref-setup)
- "Hook run when entering a mode derived from Magit mode."
- :group 'magit-modes
- :type 'hook
- :options '(magit-load-config-extensions
- magit-xref-setup
- bug-reference-mode))
-
-(defcustom magit-mode-setup-hook
- '(magit-maybe-save-repository-buffers
- magit-maybe-show-margin)
- "Hook run by `magit-mode-setup'."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-maybe-save-repository-buffers
- magit-maybe-show-margin))
-
-(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers)
- "Hook run before refreshing in `magit-refresh'.
-
-This hook, or `magit-post-refresh-hook', should be used
-for functions that are not tied to a particular buffer.
-
-To run a function with a particular buffer current, use
-`magit-refresh-buffer-hook' and use `derived-mode-p'
-inside your function."
- :package-version '(magit . "2.4.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-maybe-save-repository-buffers))
-
-(defcustom magit-post-refresh-hook nil
- "Hook run after refreshing in `magit-refresh'.
-
-This hook, or `magit-pre-refresh-hook', should be used
-for functions that are not tied to a particular buffer.
-
-To run a function with a particular buffer current, use
-`magit-refresh-buffer-hook' and use `derived-mode-p'
-inside your function."
- :package-version '(magit . "2.4.0")
- :group 'magit-modes
- :type 'hook)
-
-(defcustom magit-display-buffer-function 'magit-display-buffer-traditional
- "The function used display a Magit buffer.
-
-All Magit buffers (buffers whose major-modes derive from
-`magit-mode') are displayed using `magit-display-buffer',
-which in turn uses the function specified here."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :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")))
-
-(unless (find-lisp-object-file-name 'magit-pre-display-buffer-hook 'defvar)
- (add-hook 'magit-pre-display-buffer-hook 'magit-save-window-configuration))
-(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration)
- "Hook run by `magit-display-buffer' before displaying the buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-save-window-configuration))
-
-(unless (find-lisp-object-file-name 'magit-post-display-buffer-hook 'defvar)
- (add-hook 'magit-post-display-buffer-hook 'magit-maybe-set-dedicated))
-(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated)
- "Hook run by `magit-display-buffer' after displaying the buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'hook
- :options '(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-modes
- :type '(radio (function-item magit-generate-buffer-name-default-function)
- (function :tag "Function")))
-
-(defcustom magit-buffer-name-format "*%M%v: %t"
- "The format string used to name Magit buffers.
-
-The following %-sequences are supported:
-
-`%m' The name of the major-mode, but with the `-mode' suffix
- removed.
-
-`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'.
-
-`%v' The value the buffer is locked to, in parentheses, or an empty
- string if the buffer is not locked to a value.
-
-`%V' Like \"%v\", but the string is prefixed with a space, unless it
- is an empty string.
-
-`%t' The top-level directory of the working tree of the
- repository, or if `magit-uniquify-buffer-names' is non-nil
- an abbreviation of that.
-
-The value should always contain either \"%m\" or \"%M\" as well as
-\"%t\". If `magit-uniquify-buffer-names' is non-nil, then the
-value must end with \"%t\".
-
-This is used by `magit-generate-buffer-name-default-function'.
-If another `magit-generate-buffer-name-function' is used, then
-it may not respect this option, or on the contrary it may
-support additional %-sequences."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'string)
-
-(defcustom magit-uniquify-buffer-names t
- "Whether to uniquify the names of Magit buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'boolean)
-
-(defcustom magit-bury-buffer-function 'magit-restore-window-configuration
- "The function used to bury or kill the current Magit buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type '(radio (function-item quit-window)
- (function-item magit-mode-quit-window)
- (function-item magit-restore-window-configuration)
- (function :tag "Function")))
-
-(defcustom magit-region-highlight-hook
- '(magit-section-update-region magit-diff-update-hunk-region)
- "Functions used to highlight the region.
-Each function is run with the current section as only argument
-until one of them returns non-nil. When multiple sections are
-selected, then this hook does not run and the region is not
-displayed. Otherwise fall back to regular region highlighting."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-section-update-region magit-diff-update-hunk-region))
-
-(defcustom magit-refresh-verbose nil
- "Whether to revert Magit buffers verbosely."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'boolean)
-
-(defcustom magit-refresh-buffer-hook nil
- "Normal hook for `magit-refresh-buffer' to run after refreshing."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'hook)
-
-(defcustom magit-refresh-status-buffer t
- "Whether the status buffer is refreshed after running git.
-
-When this is non-nil, then the status buffer is automatically
-refreshed after running git for side-effects, in addition to the
-current Magit buffer, which is always refreshed automatically.
-
-Only set this to nil after exhausting all other options to
-improve performance."
- :package-version '(magit . "2.4.0")
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-save-repository-buffers t
- "Whether to save file-visiting buffers when appropriate.
-
-If this is non-nil then all modified file-visiting buffers
-belonging to the current repository may be saved before running
-commands, before creating new Magit buffers, and before
-explicitly refreshing such buffers. If this is `dontask' then
-this is done without user intervention, if it is t then the user
-has to confirm each save. `dontask' is the recommended setting."
- :group 'magit
- :type '(choice (const :tag "Never" nil)
- (const :tag "Ask" t)
- (const :tag "Save without asking" dontask)))
-
-(defcustom magit-keep-region-overlay nil
- "Whether to keep the region overlay when there is a valid selection.
-
-By default Magit removes the regular region overlay if, and only
-if, that region constitutes a valid selection as understood by
-Magit commands. Otherwise it does not remove that overlay, and
-the region looks like it would in other buffers.
-
-There are two types of such valid selections: hunk-internal
-regions and regions that select two or more sibling sections.
-In such cases Magit removes the region overlay and instead
-highlights a slightly larger range. All text (for hunk-internal
-regions) or the headings of all sections (for sibling selections)
-that are inside that range (not just inside the region) are acted
-on by commands such as the staging command. This buffer range
-begins at the beginning of the line on which the region begins
-and ends at the end of the line on which the region ends.
-
-Because Magit acts on this larger range and not the region, it is
-actually quite important to visualize that larger range. If we
-don't do that, then one might think that these commands act on
-the region instead. If you want to *also* visualize the region,
-then set this option to t. But please note that when the region
-does *not* constitute a valid selection, then the region is
-*always* visualized as usual, and that it is usually under such
-circumstances that you want to use a non-magit command to act on
-the region.
-
-Besides keeping the region overlay, setting this option to t also
-causes all face properties, except for `:foreground', to be
-ignored for the faces used to highlight headings of selected
-sections. This avoids the worst conflicts that result from
-displaying the region and the selection overlays at the same
-time. We are not interested in dealing with other conflicts.
-In fact we *already* provide a way to avoid all of these
-conflicts: *not* changing the value of this option.
-
-It should be clear by now that we consider it a mistake to set
-this to display the region when the Magit selection is also
-visualized, but since it has been requested a few times and
-because it doesn't cost much to offer this option we do so.
-However that might change. If the existence of this option
-starts complicating other things, then it will be removed."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'boolean)
-
-;;; Magit Mode
-
-(defvar magit-mode-map
- (let ((map (make-keymap)))
- (suppress-keymap map t)
- (define-key map "\t" 'magit-section-toggle)
- (define-key map [C-tab] 'magit-section-cycle)
- (define-key map [M-tab] 'magit-section-cycle-diffs)
- (define-key map [s-tab] 'magit-section-cycle-global)
- (define-key map [backtab] 'magit-section-cycle-global)
- (define-key map "^" 'magit-section-up)
- (define-key map "n" 'magit-section-forward)
- (define-key map "p" 'magit-section-backward)
- (define-key map "\M-n" 'magit-section-forward-sibling)
- (define-key map "\M-p" 'magit-section-backward-sibling)
- (define-key map "+" 'magit-diff-more-context)
- (define-key map "-" 'magit-diff-less-context)
- (define-key map "0" 'magit-diff-default-context)
- (define-key map "1" 'magit-section-show-level-1)
- (define-key map "2" 'magit-section-show-level-2)
- (define-key map "3" 'magit-section-show-level-3)
- (define-key map "4" 'magit-section-show-level-4)
- (define-key map "\M-1" 'magit-section-show-level-1-all)
- (define-key map "\M-2" 'magit-section-show-level-2-all)
- (define-key map "\M-3" 'magit-section-show-level-3-all)
- (define-key map "\M-4" 'magit-section-show-level-4-all)
- (define-key map "g" 'magit-refresh)
- (define-key map "G" 'magit-refresh-all)
- (define-key map "q" 'magit-mode-bury-buffer)
- (define-key map "$" 'magit-process-buffer)
- (define-key map "a" 'magit-cherry-apply)
- (define-key map "A" 'magit-cherry-pick-popup)
- (define-key map "b" 'magit-branch-popup)
- (define-key map "B" 'magit-bisect-popup)
- (define-key map "c" 'magit-commit-popup)
- (define-key map "d" 'magit-diff-popup)
- (define-key map "D" 'magit-diff-refresh-popup)
- (define-key map "h" 'magit-dispatch-popup)
- (define-key map "?" 'magit-dispatch-popup)
- (define-key map "\C-c\C-c" 'magit-dispatch-popup)
- (define-key map "\C-c\C-e" 'magit-dispatch-popup)
- (define-key map "e" 'magit-ediff-dwim)
- (define-key map "E" 'magit-ediff-popup)
- (define-key map "f" 'magit-fetch-popup)
- (define-key map "F" 'magit-pull-popup)
- (define-key map "i" 'magit-gitignore)
- (define-key map "I" 'magit-gitignore-locally)
- (define-key map "k" 'magit-delete-thing)
- (define-key map "K" 'magit-file-untrack)
- (define-key map "l" 'magit-log-popup)
- (define-key map "L" 'magit-log-refresh-popup)
- (define-key map "m" 'magit-merge-popup)
- (define-key map "M" 'magit-remote-popup)
- (define-key map "o" 'magit-submodule-popup)
- (define-key map "O" 'magit-subtree-popup)
- (define-key map "P" 'magit-push-popup)
- (define-key map "r" 'magit-rebase-popup)
- (define-key map "R" 'magit-file-rename)
- (define-key map "t" 'magit-tag-popup)
- (define-key map "T" 'magit-notes-popup)
- (define-key map "\r" 'magit-visit-thing)
- (define-key map [C-return] 'magit-visit-thing)
- (define-key map [M-return] 'magit-dired-jump)
- (define-key map "\s" 'magit-diff-show-or-scroll-up)
- (define-key map "\d" 'magit-diff-show-or-scroll-down)
- (define-key map "s" 'magit-stage-file)
- (define-key map "S" 'magit-stage-modified)
- (define-key map "u" 'magit-unstage-file)
- (define-key map "U" 'magit-unstage-all)
- (define-key map "v" 'magit-revert-no-commit)
- (define-key map "V" 'magit-revert-popup)
- (define-key map "w" 'magit-am-popup)
- (define-key map "W" 'magit-patch-popup)
- (define-key map "x" 'magit-reset)
- (define-key map "X" 'magit-reset-popup)
- (define-key map "y" 'magit-show-refs-popup)
- (define-key map "Y" 'magit-cherry)
- (define-key map "z" 'magit-stash-popup)
- (define-key map "Z" 'magit-stash-popup)
- (define-key map ":" 'magit-git-command)
- (define-key map "!" 'magit-run-popup)
- (define-key map "\C-xa" 'magit-add-change-log-entry)
- (define-key map "\C-x4a" 'magit-add-change-log-entry-other-window)
- (define-key map "\C-w" 'magit-copy-section-value)
- (define-key map "\M-w" 'magit-copy-buffer-revision)
- (define-key map [remap evil-previous-line] 'evil-previous-visual-line)
- (define-key map [remap evil-next-line] 'evil-next-visual-line)
- map)
- "Parent keymap for all keymaps of modes derived from `magit-mode'.")
-
-(defun magit-delete-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which deletes the thing at point."
- (interactive)
- (user-error "There is no thing at point that could be deleted"))
-
-(defun magit-visit-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which visits the thing at point."
- (interactive)
- (user-error "There is no thing at point that could be visited"))
-
-(easy-menu-define magit-mode-menu magit-mode-map
- "Magit menu"
- '("Magit"
- ["Refresh" magit-refresh t]
- ["Refresh all" magit-refresh-all t]
- "---"
- ["Stage" magit-stage t]
- ["Stage modified" magit-stage-modified t]
- ["Unstage" magit-unstage t]
- ["Reset index" magit-reset-index t]
- ["Commit" magit-commit-popup t]
- ["Add log entry" magit-commit-add-log t]
- ["Tag" magit-tag t]
- "---"
- ["Diff working tree" magit-diff-working-tree t]
- ["Diff" magit-diff t]
- ("Log"
- ["Log" magit-log t]
- ["Reflog" magit-reflog t]
- ["Extended..." magit-log-popup t])
- "---"
- ["Cherry pick" magit-cherry-pick t]
- ["Revert commit" magit-revert-popup t]
- "---"
- ["Ignore" magit-gitignore t]
- ["Ignore locally" magit-gitignore-locally t]
- ["Discard" magit-discard t]
- ["Reset head" magit-reset-head t]
- ["Stash" magit-stash t]
- ["Snapshot" magit-snapshot t]
- "---"
- ["Branch..." magit-checkout t]
- ["Merge" magit-merge t]
- ["Ediff resolve" magit-ediff-resolve t]
- ["Rebase..." magit-rebase-popup t]
- "---"
- ["Push" magit-push t]
- ["Pull" magit-pull t]
- ["Remote update" magit-fetch-all t]
- ("Submodule"
- ["Submodule update" magit-submodule-update t]
- ["Submodule update and init" magit-submodule-setup t]
- ["Submodule init" magit-submodule-init t]
- ["Submodule sync" magit-submodule-sync t])
- "---"
- ("Extensions")
- "---"
- ["Display Git output" magit-process-buffer t]
- ["Quit Magit" magit-mode-bury-buffer t]))
-
-(defun magit-load-config-extensions ()
- "Load Magit extensions that are defined at the Git config layer."
- (dolist (ext (magit-get-all "magit.extension"))
- (let ((sym (intern (format "magit-%s-mode" ext))))
- (when (fboundp sym)
- (funcall sym 1)))))
-
-(define-derived-mode magit-mode special-mode "Magit"
- "Parent major mode from which Magit major modes inherit.
-
-Magit is documented in info node `(magit)'."
- :group 'magit-modes
- (buffer-disable-undo)
- (setq truncate-lines t)
- (setq buffer-read-only t)
- (setq-local line-move-visual t) ; see #1771
- (setq show-trailing-whitespace nil)
- (setq list-buffers-directory default-directory)
- (hack-dir-local-variables-non-file-buffer)
- (make-local-variable 'text-property-default-nonsticky)
- (push (cons 'keymap t) text-property-default-nonsticky)
- (add-hook 'post-command-hook #'magit-section-update-highlight t t)
- (setq-local redisplay-highlight-region-function 'magit-highlight-region)
- (setq-local redisplay-unhighlight-region-function 'magit-unhighlight-region)
- (when (fboundp 'linum-mode)
- (linum-mode -1)))
-
-(defvar-local magit-region-overlays nil)
-
-(defun magit-highlight-region (start end window rol)
- (mapc #'delete-overlay magit-region-overlays)
- (if (and (run-hook-with-args-until-success 'magit-region-highlight-hook
- (magit-current-section))
- (not magit-keep-region-overlay))
- (funcall (default-value 'redisplay-unhighlight-region-function) rol)
- (funcall (default-value 'redisplay-highlight-region-function)
- start end window rol)))
-
-(defun magit-unhighlight-region (rol)
- (setq magit-section-highlighted-section nil)
- (mapc #'delete-overlay magit-region-overlays)
- (funcall (default-value 'redisplay-unhighlight-region-function) rol))
-
-(defvar-local magit-refresh-args nil
- "The arguments used to refresh the current buffer.")
-(put 'magit-refresh-args 'permanent-local t)
-
-(defvar-local magit-previous-section nil)
-(put 'magit-previous-section 'permanent-local t)
-
-(defun magit-mode-setup (mode &rest args)
- "Setup up a MODE buffer using ARGS to generate its content."
- (magit-mode-setup-internal mode args))
-
-(defun magit-mode-setup-internal (mode args &optional locked)
- "Setup up a MODE buffer using ARGS to generate its content.
-When optional LOCKED is non-nil, then create a buffer that is
-locked to its value, which is derived from MODE and ARGS."
- (let ((buffer (magit-mode-get-buffer
- mode t nil
- (and locked (magit-buffer-lock-value mode args))))
- (section (magit-current-section)))
- (with-current-buffer buffer
- (setq magit-previous-section section)
- (setq magit-refresh-args args)
- (funcall mode))
- (magit-display-buffer buffer)
- (with-current-buffer buffer
- (run-hooks 'magit-mode-setup-hook)
- (magit-refresh-buffer))))
-
-(defvar magit-display-buffer-noselect nil
- "If non-nil, then `magit-display-buffer' doesn't call `select-window'.")
-
-(defun magit-display-buffer (buffer)
- "Display BUFFER in some window and maybe select it.
-
-Display the buffer using `magit-display-buffer-function' and
-then, unless `magit-display-buffer-noselect' is non-nil, select
-the window which was used to display the buffer.
-
-Also run the hooks `magit-pre-display-buffer-hook'
-and `magit-post-display-buffer-hook'."
- (with-current-buffer buffer
- (run-hooks 'magit-pre-display-buffer-hook))
- (let ((window (funcall magit-display-buffer-function buffer)))
- (unless magit-display-buffer-noselect
- (select-window window)))
- (with-current-buffer buffer
- (run-hooks 'magit-post-display-buffer-hook)))
-
-(defun magit-display-buffer-traditional (buffer)
- "Display BUFFER the way this has traditionally been done."
- (display-buffer
- buffer (if (and (derived-mode-p 'magit-mode)
- (not (memq (with-current-buffer buffer major-mode)
- '(magit-process-mode
- magit-revision-mode
- magit-diff-mode
- magit-stash-mode
- magit-status-mode))))
- '(display-buffer-same-window)
- nil))) ; display in another window
-
-(defun magit-display-buffer-same-window-except-diff-v1 (buffer)
- "Display BUFFER in the selected window except for some modes.
-If a buffer's `major-mode' derives from `magit-diff-mode' or
-`magit-process-mode', display it in another window. Display all
-other buffers in the selected window."
- (display-buffer
- buffer (if (with-current-buffer buffer
- (derived-mode-p 'magit-diff-mode 'magit-process-mode))
- nil ; display in another window
- '(display-buffer-same-window))))
-
-(defun magit--display-buffer-fullframe (buffer alist)
- (-when-let (window (or (display-buffer-reuse-window buffer alist)
- (display-buffer-same-window buffer alist)
- (display-buffer-pop-up-window buffer alist)
- (display-buffer-use-some-window buffer alist)))
- (delete-other-windows window)
- window))
-
-(defun magit-display-buffer-fullframe-status-v1 (buffer)
- "Display BUFFER, filling entire frame if BUFFER is a status buffer.
-Otherwise, behave like `magit-display-buffer-traditional'."
- (if (eq (with-current-buffer buffer major-mode)
- 'magit-status-mode)
- (display-buffer buffer '(magit--display-buffer-fullframe))
- (magit-display-buffer-traditional buffer)))
-
-(defun magit--display-buffer-topleft (buffer alist)
- (or (display-buffer-reuse-window buffer alist)
- (-when-let (window2 (display-buffer-pop-up-window buffer alist))
- (let ((window1 (get-buffer-window))
- (buffer1 (current-buffer))
- (buffer2 (window-buffer window2))
- (w2-quit-restore (window-parameter window2 'quit-restore)))
- (set-window-buffer window1 buffer2)
- (set-window-buffer window2 buffer1)
- (select-window window2)
- ;; Swap some window state that `magit-mode-quit-window' and
- ;; `quit-restore-window' inspect.
- (set-window-prev-buffers window2 (cdr (window-prev-buffers window1)))
- (set-window-prev-buffers window1 nil)
- (set-window-parameter window2 'magit-dedicated
- (window-parameter window1 'magit-dedicated))
- (set-window-parameter window1 'magit-dedicated t)
- (set-window-parameter window1 'quit-restore
- (list 'window 'window
- (nth 2 w2-quit-restore)
- (nth 3 w2-quit-restore)))
- (set-window-parameter window2 'quit-restore nil)
- window1))))
-
-(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer)
- "Display BUFFER, filling entire frame if BUFFER is a status buffer.
-When BUFFER derives from `magit-diff-mode' or
-`magit-process-mode', try to display BUFFER to the top or left of
-the current buffer rather than to the bottom or right, as
-`magit-display-buffer-fullframe-status-v1' would. Whether the
-split is made vertically or horizontally is determined by
-`split-window-preferred-function'."
- (display-buffer
- buffer
- (cond ((eq (with-current-buffer buffer major-mode)
- 'magit-status-mode)
- '(magit--display-buffer-fullframe))
- ((with-current-buffer buffer
- (derived-mode-p 'magit-diff-mode 'magit-process-mode))
- '(magit--display-buffer-topleft))
- (t
- '(display-buffer-same-window)))))
-
-(defun magit--display-buffer-fullcolumn (buffer alist)
- (-when-let (window (or (display-buffer-reuse-window buffer alist)
- (display-buffer-same-window buffer alist)
- (display-buffer-below-selected buffer alist)))
- (delete-other-windows-vertically window)
- window))
-
-(defun magit-display-buffer-fullcolumn-most-v1 (buffer)
- "Display BUFFER using the full column except in some cases.
-For most cases where BUFFER's `major-mode' derives from
-`magit-mode', display it in the selected window and grow that
-window to the full height of the frame, deleting other windows in
-that column as necessary. However, display BUFFER in another
-window if 1) BUFFER's mode derives from `magit-process-mode', or
-2) BUFFER's mode derives from `magit-diff-mode', provided that
-the mode of the current buffer derives from `magit-log-mode' or
-`magit-cherry-mode'."
- (display-buffer
- buffer
- (cond ((and (derived-mode-p 'magit-log-mode 'magit-cherry-mode)
- (with-current-buffer buffer
- (derived-mode-p 'magit-diff-mode)))
- nil)
- ((with-current-buffer buffer
- (derived-mode-p 'magit-process-mode))
- nil)
- (t
- '(magit--display-buffer-fullcolumn)))))
-
-(defun magit-maybe-set-dedicated ()
- "Mark the selected window as dedicated if appropriate.
-
-If a new window was created to display the buffer, then remember
-that fact. That information is used by `magit-mode-quit-window',
-to determine whether the window should be deleted when its last
-Magit buffer is buried."
- (let ((window (get-buffer-window (current-buffer))))
- (when (and (window-live-p window)
- (not (window-prev-buffers window)))
- (set-window-parameter window 'magit-dedicated t))))
-
-(defvar-local magit--default-directory nil
- "Value of `default-directory' when buffer is generated.
-This exists to prevent a let-bound `default-directory' from
-tricking `magit-mode-get-buffer' or `magit-mode-get-buffers' into
-thinking a buffer belongs to a repo that it doesn't.")
-(put 'magit--default-directory 'permanent-local 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))))
-
-(defvar-local magit-buffer-locked-p nil)
-(put 'magit-buffer-locked-p 'permanent-local t)
-
-(defun magit-mode-get-buffer (mode &optional create frame value)
- (-if-let (topdir (magit-toplevel))
- (or (--first (with-current-buffer it
- (and (eq major-mode mode)
- (equal magit--default-directory topdir)
- (if value
- (and magit-buffer-locked-p
- (equal (magit-buffer-lock-value) value))
- (not magit-buffer-locked-p))))
- (if frame
- (-map #'window-buffer
- (window-list (unless (eq frame t) frame)))
- (buffer-list)))
- (and create
- (let ((default-directory topdir))
- (magit-generate-new-buffer mode value))))
- (user-error "Not inside a Git repository")))
-
-(defun magit-generate-new-buffer (mode &optional value)
- (let* ((name (funcall magit-generate-buffer-name-function mode value))
- (buffer (generate-new-buffer name)))
- (with-current-buffer buffer
- (setq magit--default-directory default-directory)
- (setq magit-buffer-locked-p (and value t)))
- (when magit-uniquify-buffer-names
- (add-to-list 'uniquify-list-buffers-directory-modes mode)
- (with-current-buffer buffer
- (setq list-buffers-directory default-directory))
- (let ((uniquify-buffer-name-style
- (if (memq uniquify-buffer-name-style '(nil forward))
- 'post-forward-angle-brackets
- uniquify-buffer-name-style)))
- (uniquify-rationalize-file-buffer-names
- name (file-name-directory (directory-file-name default-directory))
- buffer)))
- buffer))
-
-(defun magit-generate-buffer-name-default-function (mode &optional value)
- (let ((m (substring (symbol-name mode) 0 -5))
- (v (and value (format "%s" (if (listp value) value (list value))))))
- (format-spec
- magit-buffer-name-format
- `((?m . ,m)
- (?M . ,(if (eq mode 'magit-status-mode) "magit" m))
- (?v . ,(or v ""))
- (?V . ,(if v (concat " " v) ""))
- (?t . ,(if magit-uniquify-buffer-names
- (file-name-nondirectory
- (directory-file-name default-directory))
- default-directory))))))
-
-(defun magit-toggle-buffer-lock ()
- "Lock the current buffer to its value or unlock it.
-
-Locking a buffer to its value, prevents it from being reused to
-display another value. The name of a locked buffer contains its
-value, which allows telling it apart from other locked buffers
-and the unlocked buffer.
-
-Not all Magit buffers can be locked to their values, for example
-it wouldn't make sense to lock a status buffer.
-
-There can only be a single unlocked buffer using a certain
-major-mode per repository. So when a buffer is being unlocked
-and another unlocked buffer already exists for that mode and
-repository, then the former buffer is instead deleted and the
-latter is displayed in its place."
- (interactive)
- (if magit-buffer-locked-p
- (-if-let (unlocked (magit-mode-get-buffer major-mode))
- (let ((locked (current-buffer)))
- (switch-to-buffer unlocked nil t)
- (kill-buffer locked))
- (setq magit-buffer-locked-p nil)
- (rename-buffer (funcall magit-generate-buffer-name-function
- major-mode)))
- (-if-let (value (magit-buffer-lock-value))
- (-if-let (locked (magit-mode-get-buffer major-mode nil nil value))
- (let ((unlocked (current-buffer)))
- (switch-to-buffer locked nil t)
- (kill-buffer unlocked))
- (setq magit-buffer-locked-p t)
- (rename-buffer (funcall magit-generate-buffer-name-function
- major-mode value)))
- (user-error "Buffer has no value it could be locked to"))))
-
-(cl-defun magit-buffer-lock-value
- (&optional (mode major-mode)
- (args magit-refresh-args))
- (cl-case mode
- (magit-cherry-mode
- (-let [(upstream head) args]
- (concat head ".." upstream)))
- (magit-diff-mode
- (-let [(rev-or-range const _args files) args]
- (nconc (cons (or rev-or-range
- (if (member "--cached" const)
- (progn (setq const (delete "--cached" const))
- 'staged)
- 'unstaged))
- const)
- (and files (cons "--" files)))))
- (magit-log-mode
- (-let [(revs _args files) args]
- (if (and revs files)
- (append revs (cons "--" files))
- (append revs files))))
- (magit-refs-mode
- (-let [(ref args) args]
- (cons (or ref "HEAD") args)))
- (magit-revision-mode
- (-let [(rev __const _args files) args]
- (if files (cons rev files) (list rev))))
- ((magit-reflog-mode ; (ref ~args)
- magit-stash-mode ; (stash _const _args _files)
- magit-stashes-mode) ; (ref)
- (car args))))
-
-(defun magit-mode-bury-buffer (&optional kill-buffer)
- "Bury the current buffer.
-With a prefix argument, kill the buffer instead.
-This is done using `magit-bury-buffer-function'."
- (interactive "P")
- (funcall magit-bury-buffer-function kill-buffer))
-
-(defun magit-mode-quit-window (kill-buffer)
- "Quit the selected window and bury its buffer.
-
-This behaves similar to `quit-window', but when the window
-was originally created to display a Magit buffer and the
-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)))
- (quit-window kill-buffer)
- (let ((window (selected-window)))
- (quit-window kill-buffer)
- (when (window-live-p window)
- (delete-window window)))))
-
-;;; Refresh Magit Buffers
-
-(defvar inhibit-magit-refresh nil)
-
-(defun magit-refresh ()
- "Refresh some buffers belonging to the current repository.
-
-Refresh the current buffer if its major mode derives from
-`magit-mode', and refresh the corresponding status buffer.
-
-Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
- (interactive)
- (unless inhibit-magit-refresh
- (let ((start (current-time))
- (magit--refresh-cache (list (cons 0 0))))
- (when magit-refresh-verbose
- (message "Refreshing magit..."))
- (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
- (when (derived-mode-p 'magit-mode)
- (magit-refresh-buffer))
- (--when-let (and magit-refresh-status-buffer
- (not (derived-mode-p 'magit-status-mode))
- (magit-mode-get-buffer 'magit-status-mode))
- (with-current-buffer it
- (magit-refresh-buffer)))
- (magit-auto-revert-buffers)
- (magit-run-hook-with-benchmark 'magit-post-refresh-hook)
- (when magit-refresh-verbose
- (message "Refreshing magit...done (%.3fs, cached %s/%s)"
- (float-time (time-subtract (current-time) start))
- (caar magit--refresh-cache)
- (+ (caar magit--refresh-cache)
- (cdar magit--refresh-cache)))))))
-
-(defun magit-refresh-all ()
- "Refresh all buffers belonging to the current repository.
-
-Refresh all Magit buffers belonging to the current repository,
-and revert buffers that visit files located inside the current
-repository.
-
-Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
- (interactive)
- (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
- (dolist (buffer (magit-mode-get-buffers))
- (with-current-buffer buffer (magit-refresh-buffer)))
- (magit-auto-revert-buffers)
- (magit-run-hook-with-benchmark 'magit-post-refresh-hook))
-
-(defvar-local magit-refresh-start-time nil)
-
-(defun magit-refresh-buffer ()
- "Refresh the current Magit buffer."
- (setq magit-refresh-start-time (current-time))
- (let ((refresh (intern (format "%s-refresh-buffer"
- (substring (symbol-name major-mode) 0 -5))))
- (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0)))))
- (when (functionp refresh)
- (when magit-refresh-verbose
- (message "Refreshing buffer `%s'..." (buffer-name)))
- (let* ((buffer (current-buffer))
- (windows
- (--mapcat (with-selected-window it
- (with-current-buffer buffer
- (-when-let (section (magit-current-section))
- (list
- (nconc (list it section)
- (magit-refresh-get-relative-position))))))
- (or (get-buffer-window-list buffer nil t)
- (list (selected-window))))))
- (deactivate-mark)
- (setq magit-section-highlight-overlays nil
- magit-section-highlighted-section nil
- magit-section-highlighted-sections nil
- magit-section-unhighlight-sections nil)
- (let ((inhibit-read-only t))
- (erase-buffer)
- (save-excursion
- (apply refresh magit-refresh-args)))
- (dolist (window windows)
- (with-selected-window (car window)
- (with-current-buffer buffer
- (apply #'magit-section-goto-successor (cdr window)))))
- (run-hooks 'magit-refresh-buffer-hook)
- (magit-section-update-highlight)
- (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)))))))
-
-(defun magit-refresh-get-relative-position ()
- (-when-let (section (magit-current-section))
- (let ((start (magit-section-start section)))
- (list (count-lines start (point))
- (- (point) (line-beginning-position))
- (and (eq (magit-section-type section) 'hunk)
- (region-active-p)
- (progn (goto-char (line-beginning-position))
- (when (looking-at "^[-+]") (forward-line))
- (while (looking-at "^[ @]") (forward-line))
- (let ((beg (point)))
- (cond ((looking-at "^[-+]")
- (forward-line)
- (while (looking-at "^[-+]") (forward-line))
- (while (looking-at "^ ") (forward-line))
- (forward-line -1)
- (regexp-quote (buffer-substring-no-properties
- beg (line-end-position))))
- (t t)))))))))
-
-;;; Save File-Visiting Buffers
-
-(defvar disable-magit-save-buffers nil)
-
-(defun magit-pre-command-hook ()
- (setq disable-magit-save-buffers nil))
-(add-hook 'pre-command-hook #'magit-pre-command-hook)
-
-(defvar magit-after-save-refresh-buffers nil)
-
-(defun magit-after-save-refresh-buffers ()
- (dolist (buffer magit-after-save-refresh-buffers)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (magit-refresh-buffer))))
- (setq magit-after-save-refresh-buffers nil)
- (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers))
-
-(defun magit-after-save-refresh-status ()
- "Refresh the status buffer of the current repository.
-
-This function is intended to be added to `after-save-hook'.
-
-If the status buffer does not exist or the file being visited in
-the current buffer isn't inside the working tree of a repository,
-then do nothing.
-
-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 disable-magit-save-buffers)
- (magit-inside-worktree-p))
- (--when-let (ignore-errors (magit-mode-get-buffer 'magit-status-mode))
- (add-to-list 'magit-after-save-refresh-buffers it)
- (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.
-Do so if `magit-save-repository-buffers' is non-nil. You should
-not remove this from any hooks, instead set that variable to nil
-if you so desire."
- (when (and magit-save-repository-buffers
- (not disable-magit-save-buffers))
- (setq disable-magit-save-buffers t)
- (let ((msg (current-message)))
- (magit-save-repository-buffers
- (eq magit-save-repository-buffers 'dontask))
- (when (and msg (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)
-
-(defun magit-save-repository-buffers (&optional arg)
- "Save file-visiting buffers belonging to the current repository.
-After any buffer where `buffer-save-without-query' is non-nil
-is saved without asking, the user is asked about each modified
-buffer which visits a file in the current repository. Optional
-argument (the prefix) non-nil means save all with no questions."
- (interactive "P")
- (-when-let (topdir (magit-rev-parse-safe "--show-toplevel"))
- (save-some-buffers
- arg (-partial (lambda (topdir)
- (and buffer-file-name
- ;; Avoid needlessly connecting to unrelated remotes.
- (string-prefix-p topdir buffer-file-name)
- (equal (magit-rev-parse-safe "--show-toplevel")
- topdir)))
- topdir))))
-
-;;; Restore Window Configuration
-
-(defvar magit-inhibit-save-previous-winconf nil)
-
-(defvar-local magit-previous-window-configuration nil)
-(put 'magit-previous-window-configuration 'permanent-local t)
-
-(defun magit-save-window-configuration ()
- "Save the current window configuration.
-
-Later, when the buffer is buried, it may be restored by
-`magit-restore-window-configuration'."
- (if magit-inhibit-save-previous-winconf
- (when (eq magit-inhibit-save-previous-winconf 'unset)
- (setq magit-previous-window-configuration nil))
- (unless (get-buffer-window (current-buffer) (selected-frame))
- (setq magit-previous-window-configuration
- (current-window-configuration)))))
-
-(defun magit-restore-window-configuration (&optional kill-buffer)
- "Bury or kill the current buffer and restore previous window configuration."
- (let ((winconf magit-previous-window-configuration)
- (buffer (current-buffer))
- (frame (selected-frame)))
- (quit-window kill-buffer (selected-window))
- (when (and winconf (equal frame (window-configuration-frame winconf)))
- (set-window-configuration winconf)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (setq magit-previous-window-configuration nil))))))
-
-;;; Buffer History
-
-(defun magit-go-backward ()
- "Move backward in current buffer's history."
- (interactive)
- (if help-xref-stack
- (help-xref-go-back (current-buffer))
- (user-error "No previous entry in buffer's history")))
-
-(defun magit-go-forward ()
- "Move forward in current buffer's history."
- (interactive)
- (if help-xref-forward-stack
- (help-xref-go-forward (current-buffer))
- (user-error "No next entry in buffer's history")))
-
-(defun magit-insert-xref-buttons (&optional _)
- "Insert xref buttons."
- (when (or help-xref-stack help-xref-forward-stack)
- (when help-xref-stack
- (magit-xref-insert-button help-back-label 'magit-xref-backward))
- (when help-xref-forward-stack
- (when help-xref-stack
- (insert " "))
- (magit-xref-insert-button help-forward-label 'magit-xref-forward))))
-
-(defun magit-xref-insert-button (label type)
- (magit-insert-section (button label)
- (insert-text-button label 'type type
- 'help-args (list (current-buffer)))))
-
-(define-button-type 'magit-xref-backward
- :supertype 'help-back
- 'mouse-face 'magit-section-highlight
- 'help-echo (purecopy "mouse-2, RET: go back to previous history entry"))
-
-(define-button-type 'magit-xref-forward
- :supertype 'help-forward
- 'mouse-face 'magit-section-highlight
- 'help-echo (purecopy "mouse-2, RET: go back to next history entry"))
-
-(defun magit-xref-setup ()
- "Insert backward/forward buttons if the major-mode supports it.
-Currently `magit-log-mode', `magit-reflog-mode',
-`magit-diff-mode', and `magit-revision-mode' support it"
- (when (memq major-mode '(magit-log-mode
- magit-reflog-mode
- magit-diff-mode
- magit-revision-mode))
- (when help-xref-stack-item
- (push (cons (point) help-xref-stack-item) help-xref-stack)
- (setq help-xref-forward-stack nil))
- (when (called-interactively-p 'interactive)
- (--when-let (nthcdr 10 help-xref-stack)
- (setcdr it nil)))
- (setq help-xref-stack-item
- `(magit-xref-restore ,default-directory ,@magit-refresh-args))))
-
-(defun magit-xref-restore (&rest args)
- (magit-xref-setup)
- (setq default-directory (car args))
- (setq magit-refresh-args (cdr args))
- (magit-refresh-buffer))
-
-;;; Utilities
-
-(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))))
-
-;;; magit-mode.el ends soon
-(provide 'magit-mode)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-mode.el ends here
+++ /dev/null
-(define-package "magit" "20160529.1211" "A Git porcelain inside Emacs"
- '((emacs "24.4")
- (async "20150909.2257")
- (dash "20151021.113")
- (with-editor "20160408.201")
- (git-commit "20160425.430")
- (magit-popup "20160512.328"))
- :url "https://github.com/magit/magit" :keywords
- '("git" "tools" "vc"))
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; magit-process.el --- process functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements the tools used to run Git for side-effects.
-
-;; Note that the functions used to run Git and then consume its
-;; output, are defined in `magit-git.el'. There's a bit of overlap
-;; though.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'with-editor)
-(require 'magit-utils)
-(require 'magit-section)
-(require 'magit-git)
-(require 'magit-mode)
-
-(eval-when-compile (require 'dired))
-(declare-function dired-uncache 'dired)
-
-;;; Options
-
-(defcustom magit-process-connection-type (not (eq system-type 'cygwin))
- "Connection type used for the Git process.
-
-If nil, use pipes: this is usually more efficient, and works on Cygwin.
-If t, use ptys: this enables Magit to prompt for passphrases when needed."
- :group 'magit-process
- :type '(choice (const :tag "pipe" nil)
- (const :tag "pty" t)))
-
-(defcustom magit-need-cygwin-noglob
- (equal "x0\n" (with-temp-buffer
- (let ((process-environment
- (append magit-git-environment process-environment)))
- (process-file magit-git-executable
- nil (current-buffer) nil
- "-c" "alias.echo=!echo" "echo" "x{0}"))
- (buffer-string)))
- "Whether to use a workaround for Cygwin's globbing behavior.
-
-If non-nil, add environment variables to `process-environment' to
-prevent the git.exe distributed by Cygwin and MSYS2 from
-attempting to perform glob expansion when called from a native
-Windows build of Emacs. See #2246."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(choice (const :tag "Yes" t)
- (const :tag "No" nil)))
-
-(defcustom magit-process-popup-time -1
- "Popup the process buffer if a command takes longer than this many seconds."
- :group 'magit-process
- :type '(choice (const :tag "Never" -1)
- (const :tag "Immediately" 0)
- (integer :tag "After this many seconds")))
-
-(defcustom magit-process-log-max 32
- "Maximum number of sections to keep in a process log buffer.
-When adding a new section would go beyond the limit set here,
-then the older half of the sections are remove. Sections that
-belong to processes that are still running are never removed.
-When this is nil, no sections are ever removed."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(choice (const :tag "Never remove old sections" nil) integer))
-
-(defcustom magit-credential-cache-daemon-socket
- (--some (-let [(prog . args) (split-string it)]
- (if (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"))))
- "If non-nil, start a credential cache daemon using this socket.
-
-When using Git's cache credential helper in the normal way, Emacs
-sends a SIGHUP to the credential daemon after the git subprocess
-has exited, causing the daemon to also quit. This can be avoided
-by starting the `git-credential-cache--daemon' process directly
-from Emacs.
-
-The function `magit-maybe-start-credential-cache-daemon' takes
-care of starting the daemon if necessary, using the value of this
-option as the socket. If this option is nil, then it does not
-start any daemon. Likewise if another daemon is already running,
-then it starts no new daemon. This function has to be a member
-of the hook variable `magit-credential-hook' for this to work.
-If an error occurs while starting the daemon, most likely because
-the necessary executable is missing, then the function removes
-itself from the hook, to avoid further futile attempts."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(choice (file :tag "Socket")
- (const :tag "Don't start a cache daemon" nil)))
-
-(defcustom magit-process-yes-or-no-prompt-regexp
- " [\[(]\\([Yy]\\(?:es\\)?\\)[/|]\\([Nn]o?\\)[\])] ?[?:] ?$"
- "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 a host
- "^\\(Enter \\)?[Pp]assword\\( for '\\(?99:.*\\)'\\)?: ?$"
- "^.*'s password: ?$"
- "^Yubikey for .*: ?$")
- "List of regexps matching password prompts of Git and its subprocesses.
-Also see `magit-process-find-password-functions'."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(repeat (regexp)))
-
-(defcustom magit-process-find-password-functions nil
- "List of functions to try in sequence to get a password.
-
-These functions may be called when git asks for a password, which
-is detected using `magit-process-password-prompt-regexps'. They
-are called if and only if matching the prompt resulted in the
-value of the 99th submatch to be non-nil. Therefore users can
-control for which prompts these functions should be called by
-putting the host name in the 99th submatch, or not.
-
-If the functions are called, then they are called in the order
-given, with the host name as only argument, until one of them
-returns non-nil. If they are not called or none of them returns
-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))
-
-(defcustom magit-process-username-prompt-regexps
- '("^Username for '.*': ?$")
- "List of regexps matching username prompts of Git and its subprocesses."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(repeat (regexp)))
-
-(defcustom magit-process-ensure-unix-line-ending t
- "Whether Magit should ensure a unix coding system when talking to Git."
- :package-version '(magit . "2.6.0")
- :group 'magit-process
- :type 'boolean)
-
-(defface magit-process-ok
- '((t :inherit magit-section-heading :foreground "green"))
- "Face for zero exit-status."
- :group 'magit-faces)
-
-(defface magit-process-ng
- '((t :inherit magit-section-heading :foreground "red"))
- "Face for non-zero exit-status."
- :group 'magit-faces)
-
-;;; Process Mode
-
-(defvar magit-process-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- map)
- "Keymap for `magit-process-mode'.")
-
-(define-derived-mode magit-process-mode magit-mode "Magit Process"
- "Mode for looking at Git process output."
- :group 'magit-process
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-process-buffer (&optional nodisplay)
- "Display the current repository's process buffer.
-
-If that buffer doesn't exist yet, then create it.
-Non-interactively return the buffer and unless
-optional NODISPLAY is non-nil also display it."
- (interactive)
- (let ((topdir (magit-toplevel)))
- (unless topdir
- (magit--with-safe-default-directory nil
- (setq topdir default-directory)
- (let (prev)
- (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 ((default-directory topdir))
- (magit-generate-new-buffer 'magit-process-mode)))))
- (with-current-buffer buffer
- (if magit-root-section
- (when magit-process-log-max
- (magit-process-truncate-log))
- (magit-process-mode)
- (let ((inhibit-read-only t))
- (make-local-variable 'text-property-default-nonsticky)
- (magit-insert-section (processbuf)
- (insert "\n")))))
- (unless nodisplay
- (magit-display-buffer buffer))
- buffer)))
-
-(defun magit-process-kill ()
- "Kill the process at point."
- (interactive)
- (magit-section-when process
- (let ((process (magit-section-value it)))
- (if (eq (process-status process) 'run)
- (when (magit-confirm 'kill-process)
- (kill-process process))
- (user-error "Process isn't running")))))
-
-;;; Synchronous Processes
-
-(defvar magit-process-raise-error nil)
-
-(defun magit-git (&rest args)
- "Call Git synchronously in a separate process, for side-effects.
-
-Option `magit-git-executable' specifies the Git executable.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'. If Git exits with a non-zero status,
-then raise an error."
- (let ((magit-process-raise-error t))
- (magit-call-git args)))
-
-(defun magit-run-git (&rest args)
- "Call Git synchronously in a separate process, and refresh.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-After Git returns, the current buffer (if it is a Magit buffer)
-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'."
- (magit-call-git args)
- (magit-refresh))
-
-(defvar magit-pre-call-git-hook nil)
-
-(defun magit-call-git (&rest args)
- "Call Git synchronously in a separate process.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'."
- (run-hooks 'magit-pre-call-git-hook)
- (apply #'magit-call-process magit-git-executable
- (magit-process-git-arguments args)))
-
-(defun magit-call-process (program &rest args)
- "Call PROGRAM synchronously in a separate process.
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'."
- (-let [(process-buf . section) (magit-process-setup program args)]
- (magit-process-finish
- (let ((inhibit-read-only t))
- (apply #'magit-process-file program nil process-buf nil args))
- process-buf (current-buffer) default-directory section)))
-
-(defun magit-process-file (&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."
- (let ((process-environment (append (magit-cygwin-env-vars)
- process-environment))
- (default-process-coding-system (magit--process-coding-system)))
- (apply #'process-file args)))
-
-(defun magit-cygwin-env-vars ()
- (append magit-git-environment
- (when magit-need-cygwin-noglob
- (mapcar (lambda (var)
- (concat var "=" (--if-let (getenv var)
- (concat it " noglob")
- "noglob")))
- '("CYGWIN" "MSYS")))))
-
-(defvar magit-this-process nil)
-
-(defun magit-run-git-with-input (&rest args)
- "Call Git in a separate process.
-ARGS is flattened and then used as arguments to Git.
-
-The current buffer's content is used as the process' standard
-input.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The remaining arguments ARGS specify arguments to Git, they are
-flattened before use."
- (declare (indent 1))
- (if (file-remote-p default-directory)
- ;; We lack `process-file-region', so fall back to asynch +
- ;; waiting in remote case.
- (progn
- (magit-start-git (current-buffer) args)
- (while (and magit-this-process
- (eq (process-status magit-this-process) 'run))
- (sleep-for 0.005)))
- (run-hooks 'magit-pre-call-git-hook)
- (-let* ((process-environment (append (magit-cygwin-env-vars)
- process-environment))
- (default-process-coding-system (magit--process-coding-system))
- (flat-args (magit-process-git-arguments args))
- ((process-buf . section)
- (magit-process-setup magit-git-executable flat-args))
- (inhibit-read-only t))
- (magit-process-finish
- (apply #'call-process-region (point-min) (point-max)
- magit-git-executable nil process-buf nil flat-args)
- process-buf nil default-directory section))))
-
-(defun magit-run-git-with-logfile (file &rest args)
- "Call Git in a separate process and log its output to FILE.
-This function might have a short halflive."
- (apply #'magit-process-file magit-git-executable nil `(:file ,file) nil
- (magit-process-git-arguments args))
- (magit-refresh))
-
-;;; Asynchronous Processes
-
-(defun magit-run-git-async (&rest args)
- "Start Git, prepare for refresh, and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-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 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)
- "Export GIT_EDITOR and start Git.
-Also prepare for refresh and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-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' and `with-editor' for more information."
- (with-editor "GIT_EDITOR"
- (let ((magit-process-popup-time -1))
- (magit-run-git-async args))))
-
-(defun magit-run-git-sequencer (&rest args)
- "Export GIT_EDITOR and start Git.
-Also prepare for refresh and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-current when this function was called (if it is a Magit buffer
-and still alive), as well as the respective Magit status buffer.
-If the sequence stops at a commit, make the section representing
-that commit the current section by moving `point' there.
-
-See `magit-start-process' and `with-editor' for more information."
- (with-editor "GIT_EDITOR"
- (let ((magit-process-popup-time -1))
- (magit-run-git-async args)))
- (set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel)
- magit-this-process)
-
-(defvar magit-pre-start-git-hook nil)
-
-(defun magit-start-git (input &rest args)
- "Start Git, prepare for refresh, and return the process object.
-
-If INPUT is non-nil, it has to be a buffer or the name of an
-existing buffer. The buffer content becomes the processes
-standard input.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The remaining arguments ARGS specify arguments to Git, they are
-flattened before use.
-
-After Git returns some buffers are refreshed: the buffer that was
-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."
- (run-hooks 'magit-pre-start-git-hook)
- (apply #'magit-start-process magit-git-executable input
- (magit-process-git-arguments args)))
-
-(defun magit-start-process (program &optional input &rest args)
- "Start PROGRAM, prepare for refresh, and return the process object.
-
-If optional argument INPUT is non-nil, it has to be a buffer or
-the name of an existing buffer. The buffer content becomes the
-processes standard input.
-
-The process is started using `start-file-process' and then setup
-to use the sentinel `magit-process-sentinel' and the filter
-`magit-process-filter'. Information required by these functions
-is stored in the process object. When this function returns the
-process has not started to run yet so it is possible to override
-the sentinel and filter.
-
-After the process returns, `magit-process-sentinel' refreshes the
-buffer that was current when `magit-start-process' was called (if
-it is a Magit buffer and still alive), as well as the respective
-Magit status buffer."
- (-let* (((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))
- (process-environment (append (magit-cygwin-env-vars)
- process-environment))
- (default-process-coding-system (magit--process-coding-system)))
- (apply #'start-file-process
- (file-name-nondirectory program)
- process-buf program args))))
- (with-editor-set-process-filter process #'magit-process-filter)
- (set-process-sentinel process #'magit-process-sentinel)
- (set-process-buffer process process-buf)
- (process-put process 'section section)
- (process-put process 'command-buf (current-buffer))
- (process-put process 'default-dir default-directory)
- (when inhibit-magit-refresh
- (process-put process 'inhibit-refresh t))
- (setf (magit-section-process section) process)
- (with-current-buffer process-buf
- (set-marker (process-mark process) (point)))
- (when input
- (with-current-buffer input
- (process-send-region process (point-min) (point-max))
- (process-send-eof process)))
- (setq magit-this-process process)
- (setf (magit-section-value section) process)
- (magit-process-display-buffer process)
- process))
-
-;;; Process Internals
-
-(defun magit-process-setup (program args)
- (magit-process-set-mode-line program args)
- (let ((pwd default-directory)
- (buf (magit-process-buffer t)))
- (cons buf (with-current-buffer buf
- (prog1 (magit-process-insert-section pwd program args nil nil)
- (backward-char 1))))))
-
-(defun magit-process-insert-section (pwd program args &optional errcode errlog)
- (let ((inhibit-read-only t)
- (magit-insert-section--parent magit-root-section))
- (goto-char (1- (point-max)))
- (magit-insert-section (process)
- (insert (if errcode
- (format "%3s " (propertize (number-to-string errcode)
- 'face 'magit-process-ng))
- "run "))
- (unless (equal (expand-file-name pwd)
- (expand-file-name default-directory))
- (insert (file-relative-name pwd default-directory) ?\s))
- (insert (propertize program 'face 'magit-section-heading))
- (insert " ")
- (when (and args (equal program magit-git-executable))
- (setq args (-split-at (length magit-git-global-arguments) args))
- (insert (propertize (char-to-string magit-ellipsis)
- 'face 'magit-section-heading
- 'help-echo (mapconcat #'identity (car args) " ")))
- (insert " ")
- (setq args (cadr args)))
- (insert (propertize (mapconcat #'identity args " ")
- 'face 'magit-section-heading))
- (magit-insert-heading)
- (when errlog
- (insert-file-contents errlog)
- (goto-char (1- (point-max))))
- (insert "\n"))))
-
-(defun magit-process-truncate-log ()
- (let* ((head nil)
- (tail (magit-section-children magit-root-section))
- (count (length tail)))
- (when (> (1+ count) magit-process-log-max)
- (while (and (cdr tail)
- (> count (/ magit-process-log-max 2)))
- (let* ((inhibit-read-only t)
- (section (car tail))
- (process (magit-section-process section)))
- (cond ((not process))
- ((memq (process-status process) '(exit signal))
- (delete-region (magit-section-start section)
- (1+ (magit-section-end section)))
- (cl-decf count))
- (t
- (push section head))))
- (pop tail))
- (setf (magit-section-children magit-root-section)
- (nconc (reverse head) tail)))))
-
-(defun magit-process-sentinel (process event)
- "Default sentinel used by `magit-start-process'."
- (when (memq (process-status process) '(exit signal))
- (setq event (substring event 0 -1))
- (when (string-match "^finished" event)
- (message (concat (capitalize (process-name process)) " finished")))
- (magit-process-finish process)
- (when (eq process magit-this-process)
- (setq magit-this-process nil))
- (unless (process-get process 'inhibit-refresh)
- (let ((command-buf (process-get process 'command-buf)))
- (if (buffer-live-p command-buf)
- (with-current-buffer command-buf
- (magit-refresh))
- (with-temp-buffer
- (setq default-directory (process-get process 'default-dir))
- (magit-refresh)))))))
-
-(defun magit-sequencer-process-sentinel (process event)
- "Special sentinel used by `magit-run-git-sequencer'."
- (when (memq (process-status process) '(exit signal))
- (magit-process-sentinel process event)
- (--when-let (magit-mode-get-buffer 'magit-status-mode)
- (with-current-buffer it
- (--when-let
- (magit-get-section
- `((commit . ,(magit-rev-parse "HEAD"))
- (,(pcase (car (cadr (-split-at
- (1+ (length magit-git-global-arguments))
- (process-command process))))
- ((or "rebase" "am") 'rebase-sequence)
- ((or "cherry-pick" "revert") 'sequence)))
- (status)))
- (goto-char (magit-section-start it))
- (magit-section-update-highlight))))))
-
-(defun magit-process-filter (proc string)
- "Default filter used by `magit-start-process'."
- (with-current-buffer (process-buffer proc)
- (let ((inhibit-read-only t))
- (magit-process-yes-or-no-prompt proc string)
- (magit-process-username-prompt proc string)
- (magit-process-password-prompt proc string)
- (goto-char (process-mark proc))
- (setq string (propertize string 'magit-section
- (process-get proc 'section)))
- ;; Find last ^M in string. If one was found, ignore
- ;; everything before it and delete the current line.
- (let ((ret-pos (length string)))
- (while (and (>= (cl-decf ret-pos) 0)
- (/= ?\r (aref string ret-pos))))
- (if (< ret-pos 0)
- (insert string)
- (delete-region (line-beginning-position) (point))
- (insert (substring string (1+ ret-pos)))))
- (set-marker (process-mark proc) (point)))))
-
-(defmacro magit-process-kill-on-abort (proc &rest body)
- (declare (indent 1) (debug (form body)))
- (let ((map (cl-gensym)))
- `(let ((,map (make-sparse-keymap)))
- (set-keymap-parent ,map minibuffer-local-map)
- (define-key ,map "\C-g"
- (lambda ()
- (interactive)
- (ignore-errors (kill-process ,proc))
- (abort-recursive-edit)))
- (let ((minibuffer-local-map ,map))
- ,@body))))
-
-(defun magit-process-yes-or-no-prompt (process string)
- "Forward Yes-or-No prompts to the user."
- (-when-let (beg (string-match magit-process-yes-or-no-prompt-regexp string))
- (let ((max-mini-window-height 30))
- (process-send-string
- process
- (downcase
- (concat
- (match-string
- (if (save-match-data
- (magit-process-kill-on-abort process
- (yes-or-no-p (substring string 0 beg)))) 1 2)
- string)
- "\n"))))))
-
-(defun magit-process-password-auth-source (key)
- "Use `auth-source-search' to get a password.
-If found, return the password. Otherwise, return nil."
- (require 'auth-source)
- (let ((secret (plist-get (car (auth-source-search :max 1 :host key
- :require '(:host)))
- :secret)))
- (if (functionp secret)
- (funcall secret)
- secret)))
-
-(defun magit-process-password-prompt (process string)
- "Find a password based on prompt STRING and send it to git.
-First try the functions in `magit-process-find-password-functions'.
-If none of them returns a password, then read it from the user
-instead."
- (--when-let (magit-process-match-prompt
- magit-process-password-prompt-regexps string)
- (process-send-string
- process (magit-process-kill-on-abort process
- (concat (or (--when-let (match-string 99 string)
- (run-hook-with-args-until-success
- 'magit-process-find-password-functions it))
- (read-passwd it))
- "\n")))))
-
-(defun magit-process-username-prompt (process string)
- "Forward username prompts to the user."
- (--when-let (magit-process-match-prompt
- magit-process-username-prompt-regexps string)
- (process-send-string
- process (magit-process-kill-on-abort process
- (concat (read-string it nil nil (user-login-name)) "\n")))))
-
-(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? (string-match it string) prompts)
- (let ((prompt (match-string 0 string)))
- (cond ((string-suffix-p ": " prompt) prompt)
- ((string-suffix-p ":" prompt) (concat prompt " "))
- (t (concat prompt ": "))))))
-
-(defun magit--process-coding-system ()
- (if magit-process-ensure-unix-line-ending
- (cons (coding-system-change-eol-conversion
- (car default-process-coding-system) 'unix)
- (coding-system-change-eol-conversion
- (cdr default-process-coding-system) 'unix))
- default-process-coding-system))
-
-(defvar magit-credential-hook nil
- "Hook run before Git needs credentials.")
-
-(defvar magit-credential-cache-daemon-process nil)
-
-(defun magit-maybe-start-credential-cache-daemon ()
- "Maybe start a `git-credential-cache--daemon' process.
-
-If such a process is already running or if the value of option
-`magit-credential-cache-daemon-socket' is nil, then do nothing.
-Otherwise start the process passing the value of that options
-as argument."
- (unless (or (not magit-credential-cache-daemon-socket)
- (process-live-p magit-credential-cache-daemon-process)
- (memq magit-credential-cache-daemon-process
- (list-system-processes)))
- (setq magit-credential-cache-daemon-process
- (or (--first (-let (((&alist 'comm comm 'user user)
- (process-attributes it)))
- (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*"
- magit-git-executable
- "credential-cache--daemon"
- magit-credential-cache-daemon-socket)
- ;; Some Git implementations (e.g. Windows) won't have
- ;; this program; if we fail the first time, stop trying.
- ((debug error)
- (remove-hook 'magit-credential-hook
- #'magit-maybe-start-credential-cache-daemon)))))))
-
-(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)
-
-(defun magit-process-set-mode-line (program args)
- (when (equal program magit-git-executable)
- (setq args (nthcdr (length magit-git-global-arguments) args)))
- (let ((str (concat " " program (and args (concat " " (car args))))))
- (dolist (buf (magit-mode-get-buffers))
- (with-current-buffer buf (setq mode-line-process str)))))
-
-(defun magit-process-unset-mode-line ()
- (dolist (buf (magit-mode-get-buffers))
- (with-current-buffer buf (setq mode-line-process nil))))
-
-(defvar magit-process-error-message-re
- (concat "^\\(?:error\\|fatal\\|git\\): \\(.*\\)" paragraph-separate))
-
-(define-error 'magit-git-error "Git error")
-
-(defvar-local magit-this-error nil)
-
-(defun magit-process-finish (arg &optional process-buf command-buf
- default-dir section)
- (unless (integerp arg)
- (setq process-buf (process-buffer arg)
- command-buf (process-get arg 'command-buf)
- default-dir (process-get arg 'default-dir)
- section (process-get arg 'section)
- arg (process-exit-status arg)))
- (magit-process-unset-mode-line)
- (when (featurep 'dired)
- (dired-uncache default-dir))
- (when (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (let ((inhibit-read-only t)
- (marker (magit-section-start section)))
- (goto-char marker)
- (save-excursion
- (delete-char 3)
- (set-marker-insertion-type marker nil)
- (insert (propertize (format "%3s" arg)
- 'magit-section section
- 'face (if (= arg 0)
- 'magit-process-ok
- 'magit-process-ng)))
- (set-marker-insertion-type marker t))
- (if (= (magit-section-end section)
- (+ (line-end-position) 2))
- (save-excursion
- (goto-char (1+ (line-end-position)))
- (delete-char -1)
- (setf (magit-section-content section) nil))
- (let ((buf (magit-process-buffer t)))
- (when (and (= arg 0)
- (not (--any-p (eq (window-buffer it) buf)
- (window-list))))
- (magit-section-hide section)))))))
- (unless (= arg 0)
- (let ((msg (or (and (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (save-excursion
- (goto-char (magit-section-end section))
- (--when-let (magit-section-content section)
- (when (re-search-backward
- magit-process-error-message-re it t)
- (match-string-no-properties 1))))))
- "Git failed")))
- (if magit-process-raise-error
- (signal 'magit-git-error (list (format "%s (in %s)" msg default-dir)))
- (--when-let (magit-mode-get-buffer 'magit-status-mode)
- (setq magit-this-error msg))
- (message "%s ... [%s buffer %s for details]" msg
- (-if-let (key (and (buffer-live-p command-buf)
- (with-current-buffer command-buf
- (car (where-is-internal
- 'magit-process-buffer)))))
- (format "Hit %s to see" (key-description key))
- "See")
- (buffer-name process-buf)))))
- arg)
-
-(defun magit-process-display-buffer (process)
- (when (process-live-p process)
- (let ((buf (process-buffer process)))
- (cond ((not (buffer-live-p buf)))
- ((= magit-process-popup-time 0)
- (if (minibufferp)
- (switch-to-buffer-other-window buf)
- (pop-to-buffer buf)))
- ((> magit-process-popup-time 0)
- (run-with-timer magit-process-popup-time nil
- (lambda (p)
- (when (eq (process-status p) 'run)
- (let ((buf (process-buffer p)))
- (when (buffer-live-p buf)
- (if (minibufferp)
- (switch-to-buffer-other-window buf)
- (pop-to-buffer buf))))))
- process))))))
-
-;;; magit-process.el ends soon
-(provide 'magit-process)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-process.el ends here
+++ /dev/null
-;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for interacting with remote
-;; repositories. Commands for cloning, fetching, pulling, and
-;; pushing are defined here.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Clone
-
-(defcustom magit-clone-set-remote-head nil
- "Whether cloning creates the symbolic-ref `<remote>/HEAD'."
- :package-version '(magit . "2.4.2")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-clone-set-remote.pushDefault 'ask
- "Whether to set the value of `remote.pushDefault' after cloning.
-
-If t, then set without asking. If nil, then don't set. If
-`ask', then ask."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(choice (const :tag "set" t)
- (const :tag "ask" ask)
- (const :tag "don't set" nil)))
-
-;;;###autoload
-(defun magit-clone (repository directory)
- "Clone the REPOSITORY to DIRECTORY.
-Then show the status buffer for the new repository."
- (interactive
- (let ((url (magit-read-string-ns "Clone repository")))
- (list url (read-directory-name
- "Clone to: " nil nil nil
- (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
- (match-string 1 url))))))
- (setq directory (file-name-as-directory (expand-file-name directory)))
- (magit-run-git-async "clone" repository
- ;; Stop cygwin git making a "c:" directory.
- (magit-convert-git-filename directory))
- ;; Don't refresh the buffer we're calling from.
- (process-put magit-this-process 'inhibit-refresh t)
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (let ((magit-process-raise-error t))
- (magit-process-sentinel process event)))
- (when (and (eq (process-status process) 'exit)
- (= (process-exit-status process) 0))
- (let ((default-directory directory))
- (when (or (eq magit-clone-set-remote.pushDefault t)
- (and magit-clone-set-remote.pushDefault
- (y-or-n-p "Set `remote.pushDefault' to \"origin\"? ")))
- (magit-call-git "config" "remote.pushDefault" "origin"))
- (unless magit-clone-set-remote-head
- (magit-remote-unset-head "origin")))
- (with-current-buffer (process-get process 'command-buf)
- (magit-status-internal directory))))))
-
-;;; Setup
-
-(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset
- "Whether to set the value of `remote.pushDefault' after adding a remote.
-
-If `ask', then always ask. If `ask-if-unset', then ask, but only
-if the variable isn't set already. If nil, then don't ever set.
-If the value is a string, then set without asking, provided the
-name of the name of the added remote is equal to that string and
-the variable isn't already set."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(choice (const :tag "ask if unset" ask-if-unset)
- (const :tag "always ask" ask)
- (string :tag "set if named")
- (const :tag "don't set")))
-
-;;;###autoload (autoload 'magit-remote-popup "magit-remote" nil t)
-(magit-define-popup magit-remote-popup
- "Popup console for remote commands."
- 'magit-commands nil nil
- :man-page "git-remote"
- :actions '((?a "Add" magit-remote-add)
- (?r "Rename" magit-remote-rename)
- (?k "Remove" magit-remote-remove)
- (?u "Set url" magit-remote-set-url)))
-
-(defun magit-read-url (prompt &optional initial-input)
- (let ((url (magit-read-string-ns prompt initial-input)))
- (if (string-prefix-p "~" url)
- (expand-file-name url)
- url)))
-
-;;;###autoload
-(defun magit-remote-add (remote url)
- "Add a remote named REMOTE and fetch it."
- (interactive (list (magit-read-string-ns "Remote name")
- (magit-read-url "Remote url")))
- (if (pcase (list magit-remote-add-set-remote.pushDefault
- (magit-get "remote.defaultPush"))
- (`(,(pred stringp) ,_) t)
- ((or `(ask ,_) `(ask-if-unset nil))
- (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote))))
- (progn (magit-call-git "remote" "add" "-f" remote url)
- (magit-call-git "config" "remote.pushDefault" remote)
- (magit-refresh))
- (magit-run-git-async "remote" "add" "-f" remote url)))
-
-;;;###autoload
-(defun magit-remote-rename (old new)
- "Rename the remote named OLD to NEW."
- (interactive
- (let ((remote (magit-read-remote "Rename remote")))
- (list remote (magit-read-string-ns (format "Rename %s to" remote)))))
- (unless (string= old new)
- (magit-run-git "remote" "rename" old new)))
-
-;;;###autoload
-(defun magit-remote-set-url (remote url)
- "Change the url of the remote named REMOTE to URL."
- (interactive
- (let ((remote (magit-read-remote "Set url of remote")))
- (list remote (magit-read-url
- "Url" (magit-get "remote" remote "url")))))
- (magit-run-git "remote" "set-url" remote url))
-
-;;;###autoload
-(defun magit-remote-remove (remote)
- "Delete the remote named REMOTE."
- (interactive (list (magit-read-remote "Delete remote")))
- (magit-run-git "remote" "rm" remote))
-
-;;;###autoload
-(defun magit-remote-set-head (remote &optional branch)
- "Set the local representation of REMOTE's default branch.
-Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
-accordingly. With a prefix argument query for the branch to be
-used, which allows you to select an incorrect value if you fancy
-doing that."
- (interactive
- (let ((remote (magit-read-remote "Set HEAD for remote")))
- (list remote
- (and current-prefix-arg
- (magit-read-remote-branch (format "Set %s/HEAD to" remote)
- remote nil nil t)))))
- (magit-run-git "remote" "set-head" remote (or branch "--auto")))
-
-;;;###autoload
-(defun magit-remote-unset-head (remote)
- "Unset the local representation of REMOTE's default branch.
-Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\"."
- (interactive (list (magit-read-remote "Unset HEAD for remote")))
- (magit-run-git "remote" "set-head" remote "--delete"))
-
-;;; Fetch
-
-;;;###autoload (autoload 'magit-fetch-popup "magit-remote" nil t)
-(magit-define-popup magit-fetch-popup
- "Popup console for fetch commands."
- 'magit-commands
- :man-page "git-fetch"
- :switches '((?p "Prune deleted branches" "--prune"))
- :actions '("Configure"
- (?C "variables..." magit-branch-config-popup)
- "Fetch from"
- (?p magit-get-push-remote magit-fetch-from-pushremote)
- (?u magit-get-remote magit-fetch-from-upstream)
- (?e "elsewhere" magit-fetch)
- (?a "all remotes" magit-fetch-all)
- "Fetch"
- (?o "another branch" magit-fetch-branch)
- (?r "explicit refspec" magit-fetch-refspec)
- (?m "submodules" magit-submodule-fetch))
- :default-action 'magit-fetch
- :max-action-columns 1)
-
-(defun magit-git-fetch (remote args)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "fetch" remote args))
-
-;;;###autoload
-(defun magit-fetch-from-pushremote (args)
- "Fetch from the push-remote of the current branch."
- (interactive (list (magit-fetch-arguments)))
- (--if-let (magit-get-push-remote)
- (magit-git-fetch it args)
- (--if-let (magit-get-current-branch)
- (user-error "No push-remote is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-fetch-from-upstream (args)
- "Fetch from the upstream repository of the current branch."
- (interactive (list (magit-fetch-arguments)))
- (--if-let (magit-get-remote)
- (magit-git-fetch it args)
- (--if-let (magit-get-current-branch)
- (user-error "No upstream is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-fetch (remote args)
- "Fetch from another repository."
- (interactive (list (magit-read-remote "Fetch remote")
- (magit-fetch-arguments)))
- (magit-git-fetch remote args))
-
-;;;###autoload
-(defun magit-fetch-branch (remote branch args)
- "Fetch a BRANCH from a REMOTE."
- (interactive
- (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
- (list remote
- (magit-read-remote-branch "Fetch branch" remote)
- (magit-fetch-arguments))))
- (magit-git-fetch remote (cons branch args)))
-
-;;;###autoload
-(defun magit-fetch-refspec (remote refspec args)
- "Fetch a REFSPEC from a REMOTE."
- (interactive
- (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
- (list remote
- (magit-read-refspec "Fetch using refspec" remote)
- (magit-fetch-arguments))))
- (magit-git-fetch remote (cons refspec args)))
-
-;;;###autoload
-(defun magit-fetch-all (args)
- "Fetch from all remotes."
- (interactive (list (magit-fetch-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update" args))
-
-;;;###autoload
-(defun magit-fetch-all-prune ()
- "Fetch from all remotes, and prune.
-Prune remote tracking branches for branches that have been
-removed on the respective remote."
- (interactive)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update" "--prune"))
-
-;;;###autoload
-(defun magit-fetch-all-no-prune ()
- "Fetch from all remotes."
- (interactive)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update"))
-
-;;; Pull
-
-;;;###autoload (autoload 'magit-pull-popup "magit-remote" nil t)
-(magit-define-popup magit-pull-popup
- "Popup console for pull commands."
- 'magit-commands
- :man-page "git-pull"
- :variables '("Configure"
- (?r "branch.%s.rebase"
- magit-cycle-branch*rebase
- magit-pull-format-branch*rebase)
- (?C "variables..." magit-branch-config-popup))
- :actions '((lambda ()
- (--if-let (magit-get-current-branch)
- (concat
- (propertize "Pull into " 'face 'magit-popup-heading)
- (propertize it 'face 'magit-branch-local)
- (propertize " from" 'face 'magit-popup-heading))
- (propertize "Pull from" 'face 'magit-popup-heading)))
- (?p magit-get-push-branch magit-pull-from-pushremote)
- (?u magit-get-upstream-branch magit-pull-from-upstream)
- (?e "elsewhere" magit-pull))
- :default-action 'magit-pull
- :max-action-columns 1)
-
-;;;###autoload (autoload 'magit-pull-and-fetch-popup "magit-remote" nil t)
-(magit-define-popup magit-pull-and-fetch-popup
- "Popup console for pull and fetch commands.
-
-This popup is intended as a replacement for the separate popups
-`magit-pull-popup' and `magit-fetch-popup'. To use it, add this
-to your init file:
-
- (with-eval-after-load \\='magit-remote
- (define-key magit-mode-map \"f\" \\='magit-pull-and-fetch-popup)
- (define-key magit-mode-map \"F\" nil))
-
-The combined popup does not offer all commands and arguments
-available from the individual popups. Instead of the argument
-`--prune' and the command `magit-fetch-all' it uses two commands
-`magit-fetch-prune' and `magit-fetch-no-prune'. And the commands
-`magit-fetch-from-pushremote' and `magit-fetch-from-upstream' are
-missing. To add them use something like:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-pull-and-fetch-popup ?U
- \\='magit-get-upstream-branch
- \\='magit-fetch-from-upstream-remote ?F)
- (magit-define-popup-action \\='magit-pull-and-fetch-popup ?P
- \\='magit-get-push-branch
- \\='magit-fetch-from-push-remote ?F))"
- 'magit-commands
- :man-page "git-pull"
- :variables '("Configure"
- (?r "branch.%s.rebase"
- magit-cycle-branch*rebase
- magit-pull-format-branch*rebase)
- (?C "variables..." magit-branch-config-popup))
- :actions '((lambda ()
- (--if-let (magit-get-current-branch)
- (concat
- (propertize "Pull into " 'face 'magit-popup-heading)
- (propertize it 'face 'magit-branch-local)
- (propertize " from" 'face 'magit-popup-heading))
- (propertize "Pull from" 'face 'magit-popup-heading)))
- (?p magit-get-push-branch magit-pull-from-pushremote)
- (?u magit-get-upstream-branch magit-pull-from-upstream)
- (?e "elsewhere" magit-pull)
- "Fetch from"
- (?f "remotes" magit-fetch-all-no-prune)
- (?F "remotes and prune" magit-fetch-all-prune)
- "Fetch"
- (?o "another branch" magit-fetch-branch)
- (?s "explicit refspec" magit-fetch-refspec)
- (?m "submodules" magit-submodule-fetch))
- :default-action 'magit-fetch
- :max-action-columns 1)
-
-(defun magit-pull-format-branch*rebase ()
- (magit-popup-format-variable (format "branch.%s.rebase"
- (or (magit-get-current-branch) "<name>"))
- '("true" "false")
- "false" "pull.rebase"))
-
-(defun magit-git-pull (source args)
- (run-hooks 'magit-credential-hook)
- (-let [(remote . branch)
- (magit-split-branch-name source)]
- (magit-run-git-with-editor "pull" args remote branch)))
-
-;;;###autoload
-(defun magit-pull-from-pushremote (args)
- "Pull from the push-remote of the current branch."
- (interactive (list (magit-pull-arguments)))
- (--if-let (magit-get-push-branch)
- (magit-git-pull it args)
- (--if-let (magit-get-current-branch)
- (user-error "No push-remote is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-pull-from-upstream (args)
- "Pull from the upstream of the current branch."
- (interactive (list (magit-pull-arguments)))
- (--if-let (magit-get-upstream-branch)
- (progn (run-hooks 'magit-credential-hook)
- (magit-run-git-with-editor
- "pull" args (car (magit-split-branch-name it))))
- (--if-let (magit-get-current-branch)
- (user-error "No upstream is configured for %s" it)
- (user-error "No branch is checked out"))))
-
-;;;###autoload
-(defun magit-pull (source args)
- "Pull from a branch read in the minibuffer."
- (interactive (list (magit-read-remote-branch "Pull" nil nil nil t)
- (magit-pull-arguments)))
- (magit-git-pull source args))
-
-;;; Push
-
-(defcustom magit-push-current-set-remote-if-missing t
- "Whether to configure missing remotes before pushing.
-
-When nil, then the command `magit-push-current-to-pushremote' and
-`magit-push-current-to-upstream' do not appear in the push popup
-if the push-remote resp. upstream is not configured. If the user
-invokes one of these commands anyway, then it raises an error.
-
-When non-nil, then these commands always appear in the push
-popup. But if the required configuration is missing, then they
-do appear in a way that indicates that this is the case. If the
-user invokes one of them, then it asks for the necessary
-configuration, stores the configuration, and then uses it to push
-a first time.
-
-This option also affects whether the argument `--set-upstream' is
-available in the popup. If the value is t, then that argument is
-redundant. But note that changing the value of this option does
-not take affect immediately, the argument will only be added or
-removed after restarting Emacs."
- :package-version '(magit . "2.6.0")
- :group 'magit-commands
- :type '(choice (const :tag "don't set" nil)
- (const :tag "set branch.<name>.pushRemote" t)
- (const :tag "set remote.pushDefault" default)))
-
-;;;###autoload (autoload 'magit-push-popup "magit-remote" nil t)
-(magit-define-popup magit-push-popup
- "Popup console for push commands."
- 'magit-commands
- :man-page "git-push"
- :switches `((?f "Force" "--force-with-lease")
- (?h "Disable hooks" "--no-verify")
- (?d "Dry run" "--dry-run")
- ,@(and (not magit-push-current-set-remote-if-missing)
- '((?u "Set upstream" "--set-upstream"))))
- :actions '("Configure"
- (?C "variables..." magit-branch-config-popup)
- (lambda ()
- (--when-let (magit-get-current-branch)
- (concat (propertize "Push " 'face 'magit-popup-heading)
- (propertize it 'face 'magit-branch-local)
- (propertize " to" 'face 'magit-popup-heading))))
- (?p magit--push-current-to-pushremote-desc
- magit-push-current-to-pushremote)
- (?u magit--push-current-to-upstream-desc
- magit-push-current-to-upstream)
- (?e "elsewhere\n" magit-push-current)
- "Push"
- (?o "another branch" magit-push)
- (?T "a tag" magit-push-tag)
- (?r "explicit refspecs" magit-push-refspecs)
- (?t "all tags" magit-push-tags)
- (?m "matching branches" magit-push-matching))
- :max-action-columns 2)
-
-(defun magit-git-push (branch target args)
- (run-hooks 'magit-credential-hook)
- (-let [(remote . target)
- (magit-split-branch-name target)]
- (magit-run-git-async "push" "-v" args remote
- (format "%s:refs/heads/%s" branch target))))
-
-;;;###autoload
-(defun magit-push-current-to-pushremote (args &optional push-remote)
- "Push the current branch to `branch.<name>.pushRemote'.
-If that variable is unset, then push to `remote.pushDefault'.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the push-remote is not configured, then read the push-remote from
-the user, set it, and then push to it. With a prefix argument
-the push-remote can be changed before pushed to it."
- (interactive
- (list (magit-push-arguments)
- (and (magit--push-current-set-pushremote-p current-prefix-arg)
- (magit-read-remote
- (if (eq magit-push-current-set-remote-if-missing 'default)
- "Set `remote.pushDefault' and push there"
- (format "Set `branch.%s.pushRemote' and push there"
- (magit-get-current-branch)))))))
- (--if-let (magit-get-current-branch)
- (progn (when push-remote
- (magit-call-git
- "config"
- (if (eq magit-push-current-set-remote-if-missing 'default)
- "remote.pushDefault"
- (format "branch.%s.pushRemote"
- (magit-get-current-branch)))
- push-remote))
- (-if-let (remote (magit-get-push-remote it))
- (if (member remote (magit-list-remotes))
- (magit-git-push it (concat remote "/" it) args)
- (user-error "Remote `%s' doesn't exist" remote))
- (user-error "No push-remote is configured for %s" it)))
- (user-error "No branch is checked out")))
-
-(defun magit--push-current-set-pushremote-p (&optional change)
- (and (or change
- (and magit-push-current-set-remote-if-missing
- (not (magit-get-push-remote))))
- (magit-get-current-branch)))
-
-(defun magit--push-current-to-pushremote-desc ()
- (--if-let (magit-get-push-branch)
- (concat (magit-branch-set-face it) "\n")
- (and (magit--push-current-set-pushremote-p)
- (concat
- (propertize (if (eq magit-push-current-set-remote-if-missing 'default)
- "pushDefault"
- "pushRemote")
- 'face 'bold)
- ", after setting that\n"))))
-
-;;;###autoload
-(defun magit-push-current-to-upstream (args &optional upstream)
- "Push the current branch to its upstream branch.
-
-When `magit-push-current-set-remote-if-missing' is non-nil and
-the upstream is not configured, then read the upstream from the
-user, set it, and then push to it. With a prefix argument the
-upstream can be changed before pushed to it."
- (interactive
- (list (magit-push-arguments)
- (and (magit--push-current-set-upstream-p current-prefix-arg)
- (magit-read-upstream-branch))))
- (--if-let (magit-get-current-branch)
- (progn
- (when upstream
- (magit-set-branch*merge/remote it upstream))
- (-if-let (target (magit-get-upstream-branch it))
- (magit-git-push it target args)
- (user-error "No upstream is configured for %s" it)))
- (user-error "No branch is checked out")))
-
-(defun magit--push-current-set-upstream-p (&optional change)
- (and (or change
- (and magit-push-current-set-remote-if-missing
- (not (magit-get-upstream-branch))))
- (magit-get-current-branch)))
-
-(defun magit--push-current-to-upstream-desc ()
- (--if-let (magit-get-upstream-branch)
- (concat (magit-branch-set-face it) "\n")
- (and (magit--push-current-set-upstream-p)
- (concat (propertize "@{upstream}" 'face 'bold)
- ", after setting that\n"))))
-
-;;;###autoload
-(defun magit-push-current (target args)
- "Push the current branch to a branch read in the minibuffer."
- (interactive
- (--if-let (magit-get-current-branch)
- (list (magit-read-remote-branch (format "Push %s to" it)
- nil nil it 'confirm)
- (magit-push-arguments))
- (user-error "No branch is checked out")))
- (magit-git-push (magit-get-current-branch) target args))
-
-;;;###autoload
-(defun magit-push (source target args)
- "Push an arbitrary branch or commit somewhere.
-Both the source and the target are read in the minibuffer."
- (interactive
- (let ((source (magit-read-local-branch-or-commit "Push")))
- (list source
- (magit-read-remote-branch (format "Push %s to" source) nil
- (magit-get-upstream-branch source)
- source 'confirm)
- (magit-push-arguments))))
- (magit-git-push source target args))
-
-;;;###autoload
-(defun magit-push-refspecs (remote refspecs args)
- "Push one or multiple REFSPECS to a REMOTE.
-Both the REMOTE and the REFSPECS are read in the minibuffer. To
-use multiple REFSPECS, separate them with commas. Completion is
-only available for the part before the colon, or when no colon
-is used."
- (interactive
- (list (magit-read-remote "Push to remote")
- (completing-read-multiple
- "Push refspec,s: "
- (cons "HEAD" (magit-list-local-branch-names)))
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote refspecs))
-
-;;;###autoload
-(defun magit-push-matching (remote &optional args)
- "Push all matching branches to another repository.
-If multiple remotes exist, then read one from the user.
-If just one exists, use that without requiring confirmation."
- (interactive (list (magit-read-remote "Push matching branches to" nil t)
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote ":"))
-
-;;;###autoload
-(defun magit-push-tags (remote &optional args)
- "Push all tags to another repository.
-If only one remote exists, then push to that. Otherwise prompt
-for a remote, offering the remote configured for the current
-branch as default."
- (interactive (list (magit-read-remote "Push tags to remote" nil t)
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" remote "--tags" args))
-
-;;;###autoload
-(defun magit-push-tag (tag remote &optional args)
- "Push a tag to another repository."
- (interactive
- (let ((tag (magit-read-tag "Push tag")))
- (list tag (magit-read-remote (format "Push %s to remote" tag) nil t)
- (magit-push-arguments))))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" remote tag args))
-
-;;;###autoload
-(defun magit-push-implicitly (args)
- "Push somewhere without using an explicit refspec.
-
-This command simply runs \"git push -v [ARGS]\". ARGS are the
-arguments specified in the popup buffer. No explicit refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?P
- 'magit-push-implicitly--desc
- 'magit-push-implicitly ?p t))
-
-The function `magit-push-implicitly--desc' attempts to predict
-what this command will do, the value it returns is displayed in
-the popup buffer."
- (interactive (list (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args))
-
-(defun magit-push-implicitly--desc ()
- (let ((default (magit-get "push.default")))
- (unless (equal default "nothing")
- (or (-when-let* ((remote (or (magit-get-remote)
- (magit-remote-p "origin")))
- (refspec (magit-get "remote" remote "push")))
- (format "%s using %s"
- (propertize remote 'face 'magit-branch-remote)
- (propertize refspec 'face 'bold)))
- (--when-let (and (not (magit-get-push-branch))
- (magit-get-upstream-branch))
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (propertize "@{upstream}" 'face 'bold)))
- (--when-let (magit-get-push-branch)
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (propertize "pushRemote" 'face 'bold)))
- (--when-let (magit-get-@{push}-branch)
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (propertize "@{push}" 'face 'bold)))
- (format "using %s (%s is %s)\n"
- (propertize "git push" 'face 'bold)
- (propertize "push.default" 'face 'bold)
- (propertize default 'face 'bold))))))
-
-;;;###autoload
-(defun magit-push-to-remote (remote args)
- "Push to REMOTE without using an explicit refspec.
-The REMOTE is read in the minibuffer.
-
-This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
-are the arguments specified in the popup buffer. No refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-To add this command to the push popup add this to your init file:
-
- (with-eval-after-load \\='magit-remote
- (magit-define-popup-action \\='magit-push-popup ?r
- 'magit-push-to-remote--desc
- 'magit-push-to-remote ?p t))"
- (interactive (list (magit-read-remote "Push to remote")
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote))
-
-(defun magit-push-to-remote--desc ()
- (format "using %s\n" (propertize "git push <remote>" 'face 'bold)))
-
-;;; Email
-
-;;;###autoload (autoload 'magit-patch-popup "magit-remote" nil t)
-(magit-define-popup magit-patch-popup
- "Popup console for patch commands."
- 'magit-commands
- :man-page "git-format-patch"
- :switches '("Switches for formatting patches"
- (?l "Add cover letter" "--cover-letter"))
- :options '("Options for formatting patches"
- (?f "From" "--from=")
- (?t "To" "--to=")
- (?c "CC" "--cc=")
- (?r "In reply to" "--in-reply-to=")
- (?v "Reroll count" "--reroll-count=")
- (?s "Thread style" "--thread=")
- (?U "Context lines" "-U")
- (?M "Detect renames" "-M")
- (?C "Detect copies" "-C")
- (?A "Diff algorithm" "--diff-algorithm="
- magit-diff-select-algorithm)
- (?o "Output directory" "--output-directory="))
- :actions '((?p "Format patches" magit-format-patch)
- (?r "Request pull" magit-request-pull))
- :default-action 'magit-format-patch)
-
-;;;###autoload
-(defun magit-format-patch (range args)
- "Create patches for the commits in RANGE.
-When a single commit is given for RANGE, create a patch for the
-changes introduced by that commit (unlike 'git format-patch'
-which creates patches for all commits that are reachable from
-HEAD but not from the specified commit)."
- (interactive
- (list (-if-let (revs (magit-region-values 'commit))
- (concat (car (last revs)) "^.." (car revs))
- (let ((range (magit-read-range-or-commit "Format range or commit")))
- (if (string-match-p "\\.\\." range)
- range
- (format "%s~..%s" range range))))
- (magit-patch-arguments)))
- (magit-call-git "format-patch" range args)
- (when (member "--cover-letter" args)
- (find-file
- (expand-file-name
- "0000-cover-letter.patch"
- (let ((topdir (magit-toplevel)))
- (or (--some (and (string-match "--output-directory=\\(.+\\)" it)
- (expand-file-name (match-string 1 it) topdir))
- args)
- topdir))))))
-
-;;;###autoload
-(defun magit-request-pull (url start end)
- "Request upstream to pull from you public repository.
-
-URL is the url of your publically accessible repository.
-START is a commit that already is in the upstream repository.
-END is the last commit, usually a branch name, which upstream
-is asked to pull. START has to be reachable from that commit."
- (interactive
- (list (magit-get "remote" (magit-read-remote "Remote") "url")
- (magit-read-branch-or-commit "Start" (magit-get-upstream-branch))
- (magit-read-branch-or-commit "End")))
- (let ((dir default-directory))
- ;; mu4e changes default-directory
- (compose-mail)
- (setq default-directory dir))
- (message-goto-body)
- (magit-git-insert "request-pull" start url end)
- (set-buffer-modified-p nil))
-
-;;; magit-remote.el ends soon
-(provide 'magit-remote)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-remote.el ends here
+++ /dev/null
-;;; magit-section.el --- section functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements "sections" as used in all Magit buffers.
-;; If you have used Magit before then you probably know what that
-;; means, otherwise think "read-only Org-Mode for Git", kinda.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-utils)
-
-(defvar magit-keep-region-overlay)
-
-;;; Options
-
-(defgroup magit-section nil
- "Expandable sections."
- :group 'magit)
-
-(defcustom magit-section-show-child-count t
- "Whether to append the number of children to section headings."
- :package-version '(magit . "2.1.0")
- :group 'magit-section
- :type 'boolean)
-
-(defcustom magit-section-movement-hook
- '(magit-hunk-set-window-start
- magit-log-maybe-update-revision-buffer
- magit-log-maybe-show-more-commits)
- "Hook run by `magit-section-goto'.
-That function in turn is used by all section movement commands."
- :package-version '(magit . "2.3.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-hunk-set-window-start
- magit-status-maybe-update-revision-buffer
- magit-status-maybe-update-blob-buffer
- magit-log-maybe-update-revision-buffer
- magit-log-maybe-update-blob-buffer
- magit-log-maybe-show-more-commits))
-
-(defcustom magit-section-highlight-hook
- '(magit-diff-highlight
- magit-section-highlight
- magit-section-highlight-selection)
- "Functions used to highlight the current section.
-Each function is run with the current section as only argument
-until one of them returns non-nil."
- :package-version '(magit . "2.1.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-diff-highlight
- magit-section-highlight
- magit-section-highlight-selection))
-
-(defcustom magit-section-unhighlight-hook
- '(magit-diff-unhighlight)
- "Functions used to unhighlight the previously current section.
-Each function is run with the current section as only argument
-until one of them returns non-nil. Most sections are properly
-unhighlighted without requiring a specialized unhighlighter,
-diff-related sections being the only exception."
- :package-version '(magit . "2.1.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-diff-unhighlight))
-
-(defcustom magit-section-set-visibility-hook
- '(magit-diff-expansion-threshold
- magit-section-set-visibility-from-cache)
- "Hook used to set the initial visibility of a section.
-Stop at the first function that returns non-nil. The value
-should be `show' or `hide'. If no function returns non-nil
-determine the visibility as usual, i.e. use the hardcoded
-section specific default (see `magit-insert-section')."
- :package-version '(magit . "2.4.0")
- :group 'magit-section
- :type 'hook
- :options '(magit-diff-expansion-threshold
- magit-section-set-visibility-from-cache))
-
-(defface magit-section-highlight
- '((((class color) (background light)) :background "grey95")
- (((class color) (background dark)) :background "grey20"))
- "Face for highlighting the current section."
- :group 'magit-faces)
-
-(defface magit-section-heading
- '((((class color) (background light)) :foreground "DarkGoldenrod4" :weight bold)
- (((class color) (background dark)) :foreground "LightGoldenrod2" :weight bold))
- "Face for section headings."
- :group 'magit-faces)
-
-(defface magit-section-secondary-heading '((t :weight bold))
- "Face for section headings of some secondary headings."
- :group 'magit-faces)
-
-(defface magit-section-heading-selection
- '((((class color) (background light)) :foreground "salmon4")
- (((class color) (background dark)) :foreground "LightSalmon3"))
- "Face for selected section headings."
- :group 'magit-faces)
-
-;;; Core
-
-(cl-defstruct magit-section
- type value start content end hidden washer refined
- source diff-header process parent children)
-
-(defvar-local magit-root-section nil
- "The root section in the current buffer.
-All other sections are descendants of this section. The value
-of this variable is set by `magit-insert-section' and you should
-never modify it.")
-(put 'magit-root-section 'permanent-local t)
-
-(defun magit-current-section ()
- "Return the section at point."
- (or (get-text-property (point) 'magit-section) magit-root-section))
-
-(defun magit-section-ident (section)
- "Return an unique identifier for SECTION.
-The return value has the form ((TYPE . VALUE)...)."
- (cons (cons (magit-section-type section)
- (magit-section-value section))
- (--when-let (magit-section-parent section)
- (magit-section-ident it))))
-
-(defun magit-get-section (ident &optional root)
- "Return the section identified by IDENT.
-IDENT has to be a list as returned by `magit-section-ident'."
- (setq ident (reverse ident))
- (let ((section (or root magit-root-section)))
- (when (eq (car (pop ident)) (magit-section-type section))
- (while (and ident
- (setq section
- (--first
- (and (eq (caar ident) (magit-section-type it))
- (equal (cdar ident) (magit-section-value it)))
- (magit-section-children section))))
- (pop ident))
- section)))
-
-(defvar magit-insert-section--current nil "For internal use only.")
-(defvar magit-insert-section--parent nil "For internal use only.")
-(defvar magit-insert-section--oldroot nil "For internal use only.")
-
-;;; Commands
-;;;; Movement
-
-(defun magit-section-forward ()
- "Move to the beginning of the next visible section."
- (interactive)
- (if (eobp)
- (user-error "No next section")
- (let ((section (magit-current-section)))
- (if (magit-section-parent section)
- (let ((next (and (not (magit-section-hidden section))
- (not (= (magit-section-end section) (1+ (point))))
- (car (magit-section-children section)))))
- (while (and section (not next))
- (unless (setq next (car (magit-section-siblings section 'next)))
- (setq section (magit-section-parent section))))
- (if next
- (magit-section-goto next)
- (user-error "No next section")))
- (magit-section-goto 1)))))
-
-(defun magit-section-backward ()
- "Move to the beginning of the current or the previous visible section.
-When point is at the beginning of a section then move to the
-beginning of the previous visible section. Otherwise move to
-the beginning of the current section."
- (interactive)
- (if (bobp)
- (user-error "No previous section")
- (let ((section (magit-current-section)) children)
- (cond
- ((and (= (point) (1- (magit-section-end section)))
- (setq children (magit-section-children section)))
- (magit-section-goto (car (last children))))
- ((and (magit-section-parent section)
- (not (= (point) (magit-section-start section))))
- (magit-section-goto section))
- (t
- (let ((prev (car (magit-section-siblings section 'prev))))
- (if prev
- (while (and (not (magit-section-hidden prev))
- (setq children (magit-section-children prev)))
- (setq prev (car (last children))))
- (setq prev (magit-section-parent section)))
- (cond (prev
- (magit-section-goto prev))
- ((magit-section-parent section)
- (user-error "No previous section"))
- ;; Eob special cases.
- ((not (get-text-property (1- (point)) 'invisible))
- (magit-section-goto -1))
- (t
- (goto-char (previous-single-property-change
- (1- (point)) 'invisible))
- (forward-line -1)
- (magit-section-goto (magit-current-section))))))))))
-
-(defun magit-section-up ()
- "Move to the beginning of the parent section."
- (interactive)
- (--if-let (magit-section-parent (magit-current-section))
- (magit-section-goto it)
- (user-error "No parent section")))
-
-(defun magit-section-forward-sibling ()
- "Move to the beginning of the next sibling section.
-If there is no next sibling section, then move to the parent."
- (interactive)
- (let ((current (magit-current-section)))
- (if (magit-section-parent current)
- (--if-let (car (magit-section-siblings current 'next))
- (magit-section-goto it)
- (magit-section-forward))
- (magit-section-goto 1))))
-
-(defun magit-section-backward-sibling ()
- "Move to the beginning of the previous sibling section.
-If there is no previous sibling section, then move to the parent."
- (interactive)
- (let ((current (magit-current-section)))
- (if (magit-section-parent current)
- (--if-let (car (magit-section-siblings current 'prev))
- (magit-section-goto it)
- (magit-section-backward))
- (magit-section-goto -1))))
-
-(defun magit-section-goto (arg)
- (if (integerp arg)
- (progn (forward-line arg)
- (setq arg (magit-current-section)))
- (goto-char (magit-section-start arg)))
- (run-hook-with-args 'magit-section-movement-hook arg))
-
-(defun magit-section-set-window-start (section)
- "Ensure the beginning of SECTION is visible."
- (unless (pos-visible-in-window-p (magit-section-end section))
- (set-window-start (selected-window) (magit-section-start section))))
-
-(defun magit-hunk-set-window-start (section)
- "Ensure the beginning of the `hunk' SECTION is visible.
-It the SECTION has a different type, then do nothing."
- (when (eq (magit-section-type section) 'hunk)
- (magit-section-set-window-start section)))
-
-(defmacro magit-define-section-jumper (name heading type &optional value)
- "Define an interactive function to go some section.
-Together TYPE and VALUE identify the section.
-HEADING is the displayed heading of the section."
- (declare (indent defun))
- `(defun ,name (&optional expand) ,(format "\
-Jump to the section \"%s\".
-With a prefix argument also expand it." heading)
- (interactive "P")
- (--if-let (magit-get-section
- (cons (cons ',type ,value)
- (magit-section-ident magit-root-section)))
- (progn (goto-char (magit-section-start it))
- (when expand
- (with-local-quit (magit-section-show it))
- (recenter 0)))
- (message ,(format "Section \"%s\" wasn't found" heading)))))
-
-;;;; Visibility
-
-(defun magit-section-show (section)
- "Show the body of the current section."
- (interactive (list (magit-current-section)))
- (setf (magit-section-hidden section) nil)
- (-when-let (washer (magit-section-washer section))
- (setf (magit-section-washer section) nil)
- (let ((inhibit-read-only t)
- (magit-insert-section--parent section)
- (content (magit-section-content section)))
- (save-excursion
- (if (and content (< content (magit-section-end section)))
- (funcall washer section) ; already partially washed (hunk)
- (goto-char (magit-section-end section))
- (setf (magit-section-content section) (point-marker))
- (funcall washer)
- (setf (magit-section-end section) (point-marker)))))
- (magit-section-update-highlight))
- (-when-let (beg (magit-section-content section))
- (remove-overlays beg (magit-section-end section) 'invisible t))
- (magit-section-update-visibility-cache section)
- (dolist (child (magit-section-children section))
- (if (magit-section-hidden child)
- (magit-section-hide child)
- (magit-section-show child))))
-
-(defun magit-section-hide (section)
- "Hide the body of the current section."
- (interactive (list (magit-current-section)))
- (if (eq section magit-root-section)
- (user-error "Cannot hide root section")
- (setf (magit-section-hidden section) t)
- (-when-let (beg (magit-section-content section))
- (let ((end (magit-section-end section)))
- (remove-overlays beg end 'invisible t)
- (let ((o (make-overlay beg end)))
- (overlay-put o 'evaporate t)
- (overlay-put o 'invisible t))))))
-
-(defun magit-section-toggle (section)
- "Toggle visibility of the body of the current section."
- (interactive (list (magit-current-section)))
- (if (eq section magit-root-section)
- (user-error "Cannot hide root section")
- (goto-char (magit-section-start section))
- (if (magit-section-hidden section)
- (magit-section-show section)
- (magit-section-hide section))))
-
-(defun magit-section-toggle-children (section)
- "Toggle visibility of bodies of children of the current section."
- (interactive (list (magit-current-section)))
- (goto-char (magit-section-start section))
- (let* ((children (magit-section-children section))
- (show (-any? 'magit-section-hidden children)))
- (dolist (c children)
- (setf (magit-section-hidden c) show)))
- (magit-section-show section))
-
-(defun magit-section-show-children (section &optional depth)
- "Recursively show the bodies of children of the current section.
-With a prefix argument show children that deep and hide deeper
-children."
- (interactive (list (magit-current-section)))
- (magit-section-show-children-1 section depth)
- (magit-section-show section))
-
-(defun magit-section-show-children-1 (section &optional depth)
- (dolist (s (magit-section-children section))
- (setf (magit-section-hidden s) nil)
- (if depth
- (if (> depth 0)
- (magit-section-show-children-1 s (1- depth))
- (magit-section-hide s))
- (magit-section-show-children-1 s))))
-
-(defun magit-section-hide-children (section)
- "Recursively hide the bodies of children of the current section."
- (interactive (list (magit-current-section)))
- (mapc 'magit-section-hide (magit-section-children section)))
-
-(defun magit-section-show-headings (section)
- "Recursively show headings of children of the current section.
-Only show the headings, previously shown text-only bodies are
-hidden."
- (interactive (list (magit-current-section)))
- (magit-section-show-headings-1 section)
- (magit-section-show section))
-
-(defun magit-section-show-headings-1 (section)
- (dolist (s (magit-section-children section))
- (setf (magit-section-hidden s) nil)
- (when (or (magit-section-children s)
- (not (magit-section-content s)))
- (magit-section-show-headings-1 s))))
-
-(defun magit-section-cycle (section)
- "Cycle visibility of current section and its children."
- (interactive (list (magit-current-section)))
- (goto-char (magit-section-start section))
- (if (magit-section-hidden section)
- (progn (magit-section-show section)
- (magit-section-hide-children section))
- (let ((children (magit-section-children section)))
- (cond ((and (-any? 'magit-section-hidden children)
- (-any? 'magit-section-children children))
- (magit-section-show-headings section))
- ((-any? 'magit-section-hidden-body children)
- (magit-section-show-children section))
- (t
- (magit-section-hide section))))))
-
-(defun magit-section-cycle-global ()
- "Cycle visibility of all sections in the current buffer."
- (interactive)
- (let ((children (magit-section-children magit-root-section)))
- (cond ((and (-any? 'magit-section-hidden children)
- (-any? 'magit-section-children children))
- (magit-section-show-headings magit-root-section))
- ((-any? 'magit-section-hidden-body children)
- (magit-section-show-children magit-root-section))
- (t
- (mapc 'magit-section-hide children)))))
-
-(defun magit-section-cycle-diffs ()
- "Cycle visibility of diff-related sections in the current buffer."
- (interactive)
- (-when-let (sections
- (cond ((derived-mode-p 'magit-status-mode)
- (--mapcat
- (when it
- (when (magit-section-hidden it)
- (magit-section-show it))
- (magit-section-children it))
- (list (magit-get-section '((staged) (status)))
- (magit-get-section '((unstaged) (status))))))
- ((derived-mode-p 'magit-diff-mode)
- (--filter (eq (magit-section-type it) 'file)
- (magit-section-children magit-root-section)))))
- (if (-any? 'magit-section-hidden sections)
- (dolist (s sections)
- (magit-section-show s)
- (magit-section-hide-children s))
- (let ((children (-mapcat 'magit-section-children sections)))
- (cond ((and (-any? 'magit-section-hidden children)
- (-any? 'magit-section-children children))
- (mapc 'magit-section-show-headings sections))
- ((-any? 'magit-section-hidden-body children)
- (mapc 'magit-section-show-children sections))
- (t
- (mapc 'magit-section-hide sections)))))))
-
-(defun magit-section-hidden-body (section &optional pred)
- (--if-let (magit-section-children section)
- (funcall (or pred '-any?) 'magit-section-hidden-body it)
- (and (magit-section-content section)
- (magit-section-hidden section))))
-
-(defun magit-section-invisible-p (section)
- "Return t if the SECTION's body is invisible.
-When the body of an ancestor of SECTION is collapsed then
-SECTION's body (and heading) obviously cannot be visible."
- (or (magit-section-hidden section)
- (--when-let (magit-section-parent section)
- (magit-section-invisible-p it))))
-
-(defun magit-section-show-level (level)
- "Show surrounding sections up to LEVEL.
-If LEVEL is negative show up to the absolute value.
-Sections at higher levels are hidden."
- (if (< level 0)
- (let ((s (magit-current-section)))
- (setq level (- level))
- (while (> (1- (length (magit-section-ident s))) level)
- (setq s (magit-section-parent s))
- (goto-char (magit-section-start s)))
- (magit-section-show-children magit-root-section (1- level)))
- (cl-do* ((s (magit-current-section) (magit-section-parent s))
- (i (1- (length (magit-section-ident s))) (cl-decf i)))
- ((cond ((< i level) (magit-section-show-children s (- level i 1)) t)
- ((= i level) (magit-section-hide s) t))
- (magit-section-goto s)))))
-
-(defun magit-section-show-level-1 ()
- "Show surrounding sections on first level."
- (interactive)
- (magit-section-show-level 1))
-
-(defun magit-section-show-level-1-all ()
- "Show all sections on first level."
- (interactive)
- (magit-section-show-level -1))
-
-(defun magit-section-show-level-2 ()
- "Show surrounding sections up to second level."
- (interactive)
- (magit-section-show-level 2))
-
-(defun magit-section-show-level-2-all ()
- "Show all sections up to second level."
- (interactive)
- (magit-section-show-level -2))
-
-(defun magit-section-show-level-3 ()
- "Show surrounding sections up to third level."
- (interactive)
- (magit-section-show-level 3))
-
-(defun magit-section-show-level-3-all ()
- "Show all sections up to third level."
- (interactive)
- (magit-section-show-level -3))
-
-(defun magit-section-show-level-4 ()
- "Show surrounding sections up to fourth level."
- (interactive)
- (magit-section-show-level 4))
-
-(defun magit-section-show-level-4-all ()
- "Show all sections up to fourth level."
- (interactive)
- (magit-section-show-level -4))
-
-;;;; Auxiliary
-
-(defun magit-describe-section ()
- "Show information about the section at point.
-This command is intended for debugging purposes."
- (interactive)
- (let ((section (magit-current-section)))
- (message "%S %S %s-%s"
- (magit-section-value section)
- (apply 'vector (mapcar 'car (magit-section-ident section)))
- (marker-position (magit-section-start section))
- (marker-position (magit-section-end section)))))
-
-;;; Match
-
-(defun magit-section-match (condition &optional section)
- "Return t if SECTION matches CONDITION.
-SECTION defaults to the section at point.
-
-Conditions can take the following forms:
- (CONDITION...) matches if any of the CONDITIONs matches.
- [TYPE...] matches if the first TYPE matches the type
- of the section at point, the second matches
- that of its parent, and so on.
- [* TYPE...] matches sections that match [TYPE...] and
- also recursively all their child sections.
- TYPE matches TYPE regardless of its parents.
-
-Each TYPE is a symbol. Note that is not necessary to specify all
-TYPEs up to the root section as printed by `magit-describe-type',
-unless of course your want to be that precise."
- ;; When recursing SECTION actually is a type list. Matching
- ;; macros also pass such a list instead of a section struct.
- (let ((types (if (magit-section-p section)
- (mapcar 'car (magit-section-ident section))
- section)))
- (when (or types section (magit-current-section))
- (if (listp condition)
- (--first (magit-section-match it types) condition)
- (magit-section-match-1 (if (symbolp condition)
- (list condition)
- (append condition nil))
- types)))))
-
-(defun magit-section-match-1 (l1 l2)
- (or (null l1)
- (if (eq (car l1) '*)
- (or (magit-section-match-1 (cdr l1) l2)
- (and l2
- (magit-section-match-1 l1 (cdr l2))))
- (and l2
- (equal (car l1) (car l2))
- (magit-section-match-1 (cdr l1) (cdr l2))))))
-
-(defmacro magit-section-when (condition &rest body)
- "If the section at point matches CONDITION evaluate BODY.
-
-If the section matches evaluate BODY forms sequentially and
-return the value of the last one, or if there are no BODY forms
-return the value of the section. If the section does not match
-return nil.
-
-See `magit-section-match' for the forms CONDITION can take."
- (declare (indent 1)
- (debug (sexp body)))
- `(--when-let (magit-current-section)
- (when (magit-section-match ',condition
- (mapcar 'car (magit-section-ident it)))
- ,@(or body '((magit-section-value it))))))
-
-(defmacro magit-section-case (&rest clauses)
- "Choose among clauses on the type of the section at point.
-
-Each clause looks like (CONDITION BODY...). The type of the
-section is compared against each CONDITION; the BODY forms of the
-first match are evaluated sequentially and the value of the last
-form is returned. Inside BODY the symbol `it' is bound to the
-section at point. If no clause succeeds or if there is no
-section at point return nil.
-
-See `magit-section-match' for the forms CONDITION can take.
-Additionally a CONDITION of t is allowed in the final clause, and
-matches if no other CONDITION match, even if there is no section
-at point."
- (declare (indent 0)
- (debug (&rest (sexp body))))
- (let ((ident (cl-gensym "id")))
- `(let* ((it (magit-current-section))
- (,ident (and it (mapcar 'car (magit-section-ident it)))))
- (cond ,@(mapcar (lambda (clause)
- `(,(or (eq (car clause) t)
- `(and it (magit-section-match
- ',(car clause) ,ident)))
- ,@(cdr clause)))
- clauses)))))
-;;; Create
-
-(defvar magit-insert-section-hook nil
- "Hook run after `magit-insert-section's BODY.
-Avoid using this hook and only ever do so if you know
-what you are doing and are sure there is no other way.")
-
-(defmacro magit-insert-section (&rest args)
- "Insert a section at point.
-
-TYPE is the section type, a symbol. Many commands that act on
-the current section behave differently depending on that type.
-Also if a variable `magit-TYPE-section-map' exists, then use
-that as the text-property `keymap' of all text belonging to the
-section (but this may be overwritten in subsections). TYPE can
-also have the form `(eval FORM)' in which case FORM is evaluated
-at runtime.
-
-Optional VALUE is the value of the section, usually a string
-that is required when acting on the section.
-
-When optional HIDE is non-nil collapse the section body by
-default, i.e. when first creating the section, but not when
-refreshing the buffer. Else expand it by default. This can be
-overwritten using `magit-section-set-visibility-hook'. When a
-section is recreated during a refresh, then the visibility of
-predecessor is inherited and HIDE is ignored (but the hook is
-still honored).
-
-BODY is any number of forms that actually insert the section's
-heading and body. Optional NAME, if specified, has to be a
-symbol, which is then bound to the struct of the section being
-inserted.
-
-Before BODY is evaluated the `start' of the section object is set
-to the value of `point' and after BODY was evaluated its `end' is
-set to the new value of `point'; BODY is responsible for moving
-`point' forward.
-
-If it turns out inside BODY that the section is empty, then
-`magit-cancel-section' can be used to abort and remove all traces
-of the partially inserted section. This can happen when creating
-a section by washing Git's output and Git didn't actually output
-anything this time around.
-
-\(fn [NAME] (TYPE &optional VALUE HIDE) &rest BODY)"
- (declare (indent defun)
- (debug ([&optional symbolp]
- (&or [("eval" symbolp) &optional form form]
- [symbolp &optional form form])
- body)))
- (let ((s (if (symbolp (car args))
- (pop args)
- (cl-gensym "section"))))
- `(let* ((,s (make-magit-section
- :type ,(let ((type (nth 0 (car args))))
- (if (eq (car-safe type) 'eval)
- (cadr type)
- `',type))
- :value ,(nth 1 (car args))
- :start (point-marker)
- :parent magit-insert-section--parent)))
- (setf (magit-section-hidden ,s)
- (-if-let (value (run-hook-with-args-until-success
- 'magit-section-set-visibility-hook ,s))
- (eq value 'hide)
- (--if-let (and magit-insert-section--oldroot
- (magit-get-section
- (magit-section-ident ,s)
- magit-insert-section--oldroot))
- (magit-section-hidden it)
- ,(nth 2 (car args)))))
- (let ((magit-insert-section--current ,s)
- (magit-insert-section--parent ,s)
- (magit-insert-section--oldroot
- (or magit-insert-section--oldroot
- (unless magit-insert-section--parent
- (prog1 magit-root-section
- (setq magit-root-section ,s))))))
- (catch 'cancel-section
- ,@(cdr args)
- (run-hooks 'magit-insert-section-hook)
- (magit-insert-child-count ,s)
- (set-marker-insertion-type (magit-section-start ,s) t)
- (let* ((end (setf (magit-section-end ,s) (point-marker)))
- (map (intern (format "magit-%s-section-map"
- (magit-section-type ,s))))
- (map (and (boundp map) (symbol-value map))))
- (save-excursion
- (goto-char (magit-section-start ,s))
- (while (< (point) end)
- (let ((next (or (next-single-property-change
- (point) 'magit-section)
- end)))
- (unless (get-text-property (point) 'magit-section)
- (put-text-property (point) next 'magit-section ,s)
- (when map
- (put-text-property (point) next 'keymap map)))
- (goto-char next)))))
- (if (eq ,s magit-root-section)
- (magit-section-show ,s)
- (setf (magit-section-children (magit-section-parent ,s))
- (nconc (magit-section-children (magit-section-parent ,s))
- (list ,s)))))
- ,s))))
-
-(defun magit-cancel-section ()
- (when magit-insert-section--current
- (if (not (magit-section-parent magit-insert-section--current))
- (insert "(empty)\n")
- (delete-region (magit-section-start magit-insert-section--current)
- (point))
- (setq magit-insert-section--current nil)
- (throw 'cancel-section nil))))
-
-(defun magit-insert-heading (&rest args)
- "Insert the heading for the section currently being inserted.
-
-This function should only be used inside `magit-insert-section'.
-
-When called without any arguments, then just set the `content'
-slot of the object representing the section being inserted to
-a marker at `point'. The section should only contain a single
-line when this function is used like this.
-
-When called with arguments ARGS, which have to be strings, then
-insert those strings at point. The section should not contain
-any text before this happens and afterwards it should again only
-contain a single line. If the `face' property is set anywhere
-inside any of these strings, then insert all of them unchanged.
-Otherwise use the `magit-section-heading' face for all inserted
-text.
-
-The `content' property of the section struct is the end of the
-heading (which lasts from `start' to `content') and the beginning
-of the the body (which lasts from `content' to `end'). If the
-value of `content' is nil, then the section has no heading and
-its body cannot be collapsed. If a section does have a heading
-then its height must be exactly one line, including a trailing
-newline character. This isn't enforced, you are responsible for
-getting it right. The only exception is that this function does
-insert a newline character if necessary."
- (declare (indent defun))
- (when args
- (let ((heading (apply #'concat args)))
- (insert (if (next-single-property-change 0 'face (concat "0" heading))
- heading
- (propertize heading 'face 'magit-section-heading)))))
- (unless (bolp)
- (insert ?\n))
- (setf (magit-section-content magit-insert-section--current) (point-marker)))
-
-(defvar magit-insert-headers-hook nil "For internal use only.")
-
-(defun magit-insert-headers (hooks)
- (let ((magit-insert-section-hook
- (cons 'magit-insert-remaining-headers
- (if (listp magit-insert-section-hook)
- magit-insert-section-hook
- (list magit-insert-section-hook))))
- (magit-insert-headers-hook hooks)
- wrapper)
- (while (and (setq wrapper (pop magit-insert-headers-hook))
- (= (point) (point-min)))
- (funcall wrapper))))
-
-(defun magit-insert-remaining-headers ()
- (if (= (point) (point-min))
- (magit-cancel-section)
- (magit-insert-heading)
- (remove-hook 'magit-insert-section-hook 'magit-insert-remaining-headers)
- (mapc #'funcall magit-insert-headers-hook)
- (insert "\n")))
-
-(defun magit-insert-child-count (section)
- "Modify SECTION's heading to contain number of child sections.
-
-If `magit-section-show-child-count' is non-nil and the SECTION
-has children and its heading ends with \":\", then replace that
-with \" (N)\", where N is the number of child sections.
-
-This function is called by `magit-insert-section' after that has
-evaluated its BODY. Admittedly that's a bit of a hack."
- ;; This has to be fast, not pretty!
- (let (content count)
- (when (and magit-section-show-child-count
- (setq count (length (magit-section-children section)))
- (> count 0)
- (setq content (magit-section-content section))
- (eq (char-before (1- content)) ?:))
- (save-excursion
- (goto-char (- content 2))
- (insert (format " (%s)" count))
- (delete-char 1)))))
-
-;;; Update
-
-(defvar-local magit-section-highlight-overlays nil)
-(defvar-local magit-section-highlighted-section nil)
-(defvar-local magit-section-highlighted-sections nil)
-(defvar-local magit-section-unhighlight-sections nil)
-
-(defun magit-section-update-region (_)
- ;; Don't show complete region. Highlighting emphasizes headings.
- (magit-region-sections))
-
-(defun magit-section-update-highlight ()
- (let ((section (magit-current-section)))
- (unless (eq section magit-section-highlighted-section)
- (let ((inhibit-read-only t)
- (deactivate-mark nil)
- (selection (magit-region-sections)))
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (setq magit-section-unhighlight-sections
- magit-section-highlighted-sections
- magit-section-highlighted-sections nil)
- (unless (eq section magit-root-section)
- (run-hook-with-args-until-success
- 'magit-section-highlight-hook section selection))
- (--each magit-section-unhighlight-sections
- (run-hook-with-args-until-success
- 'magit-section-unhighlight-hook it selection))
- (restore-buffer-modified-p nil)
- (unless (eq magit-section-highlighted-section section)
- (setq magit-section-highlighted-section
- (unless (magit-section-hidden section) section))))
- (setq deactivate-mark nil))))
-
-(defun magit-section-highlight (section selection)
- "Highlight SECTION and if non-nil all SELECTION.
-This function works for any section but produces undesirable
-effects for diff related sections, which by default are
-highlighted using `magit-diff-highlight'. Return t."
- (cond (selection
- (magit-section-make-overlay (magit-section-start (car selection))
- (magit-section-end (car (last selection)))
- 'magit-section-highlight)
- (magit-section-highlight-selection nil selection))
- (t
- (magit-section-make-overlay (magit-section-start section)
- (magit-section-end section)
- 'magit-section-highlight)))
- t)
-
-(defun magit-section-highlight-selection (_ selection)
- "Highlight the section selection region.
-If SELECTION is non-nil then it is a list of sections selected by
-the region. The headings of these sections are then highlighted.
-
-This is a fallback for people who don't want to highlight the
-current section and therefore removed `magit-section-highlight'
-from `magit-section-highlight-hook'.
-
-This function is necessary to ensure that a representation of
-such a region is visible. If neither of these functions were
-part of the hook variable, then such a region would be
-invisible."
- (when selection
- (--each selection
- (magit-section-make-overlay (magit-section-start it)
- (or (magit-section-content it)
- (magit-section-end it))
- 'magit-section-heading-selection))
- t))
-
-(defun magit-section-make-overlay (start end face)
- ;; Yes, this doesn't belong here. But the alternative of
- ;; spreading this hack across the code base is even worse.
- (when (and magit-keep-region-overlay
- (memq face '(magit-section-heading-selection
- magit-diff-file-heading-selection
- magit-diff-hunk-heading-selection)))
- (setq face (list :foreground (face-foreground face))))
- (let ((ov (make-overlay start end nil t)))
- (overlay-put ov 'face face)
- (overlay-put ov 'evaporate t)
- (push ov magit-section-highlight-overlays)
- ov))
-
-(defun magit-section-goto-successor (section line char arg)
- (let ((ident (magit-section-ident section)))
- (--if-let (magit-get-section ident)
- (let ((start (magit-section-start it)))
- (goto-char start)
- (unless (eq it magit-root-section)
- (ignore-errors
- (forward-line line)
- (forward-char char))
- (unless (eq (magit-current-section) it)
- (goto-char start))))
- (or (and (eq (magit-section-type section) 'hunk)
- (-when-let (parent (magit-get-section
- (magit-section-ident
- (magit-section-parent section))))
- (let* ((children (magit-section-children parent))
- (siblings (magit-section-siblings section 'prev))
- (previous (nth (length siblings) children)))
- (if (not arg)
- (--when-let (or previous (car (last children)))
- (goto-char (magit-section-start it)))
- (when previous
- (goto-char (magit-section-start previous)))
- (if (and (stringp arg)
- (re-search-forward
- arg (magit-section-end parent) t))
- (goto-char (match-beginning 0))
- (goto-char (magit-section-end (car (last children))))
- (forward-line -1)
- (while (looking-at "^ ") (forward-line -1))
- (while (looking-at "^[-+]") (forward-line -1))
- (forward-line))))))
- (goto-char (--if-let (magit-section-goto-successor-1 section)
- (if (eq (magit-section-type it) 'button)
- (point-min)
- (magit-section-start it))
- (point-min)))))))
-
-(defun magit-section-goto-successor-1 (section)
- (or (--when-let (pcase (magit-section-type section)
- (`staged 'unstaged)
- (`unstaged 'staged)
- (`unpushed 'unpulled)
- (`unpulled 'unpushed))
- (magit-get-section `((,it) (status))))
- (--when-let (car (magit-section-siblings section 'next))
- (magit-get-section (magit-section-ident it)))
- (--when-let (car (magit-section-siblings section 'prev))
- (magit-get-section (magit-section-ident it)))
- (--when-let (magit-section-parent section)
- (or (magit-get-section (magit-section-ident it))
- (magit-section-goto-successor-1 it)))))
-
-;;; Visibility
-
-(defvar-local magit-section-visibility-cache nil)
-(put 'magit-section-visibility-cache 'permanent-local t)
-
-(defun magit-section-set-visibility-from-cache (section)
- "Set SECTION's visibility to the cached value.
-Currently the cache can only be used to remember that a section's
-body should be collapsed, not that it should be expanded. Return
-either `hide' or nil."
- (and (member (magit-section-visibility-ident section)
- magit-section-visibility-cache)
- 'hide))
-
-(cl-defun magit-section-cache-visibility
- (&optional (section magit-insert-section--current))
- (let ((ident (magit-section-visibility-ident section)))
- (if (magit-section-hidden section)
- (cl-pushnew ident magit-section-visibility-cache :test #'equal)
- (setq magit-section-visibility-cache
- (delete ident magit-section-visibility-cache)))))
-
-(defun magit-section-update-visibility-cache (section)
- (setq magit-section-visibility-cache
- (delete (magit-section-visibility-ident section)
- magit-section-visibility-cache)))
-
-(defun magit-section-visibility-ident (section)
- (let ((type (magit-section-type section))
- (value (magit-section-value section)))
- (cons type
- (cond ((not (memq type '(unpulled unpushed))) value)
- ((string-match-p "@{upstream}" value) value)
- ;; Unfortunately Git chokes on "@{push}" when the
- ;; value of `push.default' does not allow a 1:1
- ;; mapping. But collapsed logs of unpushed and
- ;; unpulled commits in the status buffer should
- ;; remain invisible after changing branches.
- ;; So we have to pretend the value is constant.
- ((string-match-p "\\`\\.\\." value) "..@{push}")
- (t "@{push}..")))))
-
-;;; Utilities
-
-(cl-defun magit-section-selected-p (section &optional (selection nil sselection))
- (and (not (eq section magit-root-section))
- (or (eq section (magit-current-section))
- (memq section (if sselection
- selection
- (setq selection (magit-region-sections))))
- (--when-let (magit-section-parent section)
- (magit-section-selected-p it selection)))))
-
-(defun magit-section-parent-value (section)
- (setq section (magit-section-parent section))
- (when section (magit-section-value section)))
-
-(defun magit-section-siblings (section &optional direction)
- "Return a list of the sibling sections of SECTION.
-
-If optional DIRECTION is `prev' then return siblings that come
-before SECTION, if it is `next' then return siblings that come
-after SECTION. For all other values return all siblings
-excluding SECTION itself."
- (-when-let (parent (magit-section-parent section))
- (let ((siblings (magit-section-children parent)))
- (pcase direction
- (`prev (cdr (member section (reverse siblings))))
- (`next (cdr (member section siblings)))
- (_ (remq section siblings))))))
-
-(defun magit-region-values (&rest types)
- "Return a list of the values of the selected sections.
-
-Also see `magit-region-sections' whose doc-string explains when a
-region is a valid section selection. If the region is not active
-or is not a valid section selection, then return nil. If optional
-TYPES is non-nil then the selection not only has to be valid; the
-types of all selected sections additionally have to match one of
-TYPES, or nil is returned."
- (mapcar 'magit-section-value (apply 'magit-region-sections types)))
-
-(defun magit-region-sections (&rest types)
- "Return a list of the selected sections.
-
-When the region is active and constitutes a valid section
-selection, then return a list of all selected sections. This is
-the case when the region begins in the heading of a section and
-ends in the heading of a sibling of that first section. When
-the selection is not valid then return nil. Most commands that
-can act on the selected sections, then instead just act on the
-current section, the one point is in.
-
-When the region looks like it would in any other buffer then
-the selection is invalid. When the selection is valid then the
-region uses the `magit-section-highlight'. This does not apply
-to diffs were things get a bit more complicated, but even here
-if the region looks like it usually does, then that's not a
-valid selection as far as this function is concerned.
-
-If optional TYPES is non-nil then the selection not only has to
-be valid; the types of all selected sections additionally have to
-match one of TYPES, or nil is returned."
- (when (use-region-p)
- (let* ((rbeg (region-beginning))
- (rend (region-end))
- (sbeg (get-text-property rbeg 'magit-section))
- (send (get-text-property rend 'magit-section)))
- (unless (memq send (list sbeg magit-root-section nil))
- (let ((siblings (magit-section-siblings sbeg 'next)) sections)
- (when (and (memq send siblings)
- (magit-section-position-in-heading-p sbeg rbeg)
- (magit-section-position-in-heading-p send rend))
- (while siblings
- (push (car siblings) sections)
- (when (eq (pop siblings) send)
- (setq siblings nil)))
- (setq sections (cons sbeg (nreverse sections)))
- (when (or (not types)
- (--all-p (memq (magit-section-type it) types) sections))
- sections)))))))
-
-(defun magit-section-position-in-heading-p (section pos)
- "Return t if POSITION is inside the heading of SECTION."
- (and (>= pos (magit-section-start section))
- (< pos (or (magit-section-content section)
- (magit-section-end section)))
- t))
-
-(defun magit-section-internal-region-p (&optional section)
- "Return t if the region is active and inside SECTION's body.
-If optional SECTION is nil, use the current section."
- (and (region-active-p)
- (or section (setq section (magit-current-section)))
- (let ((beg (get-text-property (region-beginning) 'magit-section)))
- (and (eq beg (get-text-property (region-end) 'magit-section))
- (eq beg section)))
- (not (or (magit-section-position-in-heading-p section (region-beginning))
- (magit-section-position-in-heading-p section (region-end))))
- t))
-
-(defun magit-wash-sequence (function)
- "Repeatedly call FUNCTION until it returns nil or eob is reached.
-FUNCTION has to move point forward or return nil."
- (while (and (not (eobp)) (funcall function))))
-
-(defun magit-add-section-hook (hook function &optional at append local)
- "Add to the value of section hook HOOK the function FUNCTION.
-
-Add FUNCTION at the beginning of the hook list unless optional
-APPEND is non-nil, in which case FUNCTION is added at the end.
-If FUNCTION already is a member then move it to the new location.
-
-If optional AT is non-nil and a member of the hook list, then
-add FUNCTION next to that instead. Add before or after AT, or
-replace AT with FUNCTION depending on APPEND. If APPEND is the
-symbol `replace', then replace AT with FUNCTION. For any other
-non-nil value place FUNCTION right after AT. If nil, then place
-FUNCTION right before AT. If FUNCTION already is a member of the
-list but AT is not, then leave FUNCTION where ever it already is.
-
-If optional LOCAL is non-nil, then modify the hook's buffer-local
-value rather than its global value. This makes the hook local by
-copying the default value. That copy is then modified.
-
-HOOK should be a symbol. If HOOK is void, it is first set to nil.
-HOOK's value must not be a single hook function. FUNCTION should
-be a function that takes no arguments and inserts one or multiple
-sections at point, moving point forward. FUNCTION may choose not
-to insert its section(s), when doing so would not make sense. It
-should not be abused for other side-effects. To remove FUNCTION
-again use `remove-hook'."
- (unless (boundp hook)
- (error "Cannot add function to undefined hook variable %s" hook))
- (or (default-boundp hook) (set-default hook nil))
- (let ((value (if local
- (if (local-variable-p hook)
- (symbol-value hook)
- (unless (local-variable-if-set-p hook)
- (make-local-variable hook))
- (copy-sequence (default-value hook)))
- (default-value hook))))
- (if at
- (when (setq at (member at value))
- (setq value (delq function value))
- (cond ((eq append 'replace)
- (setcar at function))
- (append
- (push function (cdr at)))
- (t
- (push (car at) (cdr at))
- (setcar at function))))
- (setq value (delq function value)))
- (unless (member function value)
- (setq value (if append
- (append value (list function))
- (cons function value))))
- (when (eq append 'replace)
- (setq value (delq at value)))
- (if local
- (set hook value)
- (set-default hook value))))
-
-;;; magit-section.el ends soon
-(provide 'magit-section)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-section.el ends here
+++ /dev/null
-;;; magit-sequence.el --- history manipulation in Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Support for Git commands that replay commits and help the user make
-;; changes along the way. Supports `cherry-pick', `revert', `rebase',
-;; `rebase--interactive' and `am'.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-;;;; Faces
-
-(defface magit-sequence-pick
- '((t :inherit default))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-stop
- '((((class color) (background light)) :foreground "DarkOliveGreen4")
- (((class color) (background dark)) :foreground "DarkSeaGreen2"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-part
- '((((class color) (background light)) :foreground "Goldenrod4")
- (((class color) (background dark)) :foreground "LightGoldenrod2"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-head
- '((((class color) (background light)) :foreground "SkyBlue4")
- (((class color) (background dark)) :foreground "LightSkyBlue1"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-drop
- '((((class color) (background light)) :foreground "IndianRed")
- (((class color) (background dark)) :foreground "IndianRed"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-done
- '((t :inherit magit-hash))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-onto
- '((t :inherit magit-sequence-done))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-;;; Common
-
-;;;###autoload
-(defun magit-sequencer-continue ()
- "Resume the current cherry-pick or revert sequence."
- (interactive)
- (if (magit-sequencer-in-progress-p)
- (if (magit-anything-unstaged-p t)
- (user-error "Cannot continue due to unstaged changes")
- (magit-run-git-sequencer
- (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue"))
- (user-error "No cherry-pick or revert in progress")))
-
-;;;###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")))
-
-;;;###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")))
-
-(defun magit-sequencer-in-progress-p ()
- (or (magit-cherry-pick-in-progress-p)
- (magit-revert-in-progress-p)))
-
-;;; Cherry-Pick
-
-;;;###autoload (autoload 'magit-cherry-pick-popup "magit-sequence" nil t)
-(magit-define-popup magit-cherry-pick-popup
- "Popup console for cherry-pick commands."
- 'magit-commands
- :man-page "git-cherry-pick"
- :switches '((?s "Add Signed-off-by lines" "--signoff")
- (?e "Edit commit messages" "--edit")
- (?x "Reference cherry in commit message" "-x")
- (?F "Attempt fast-forward" "--ff")
- (?m "Reply merge relative to parent" "--mainline="))
- :options '((?s "Strategy" "--strategy="))
- :actions '((?A "Cherry Pick" magit-cherry-pick)
- (?a "Cherry Apply" magit-cherry-apply))
- :sequence-actions '((?A "Continue" magit-sequencer-continue)
- (?s "Skip" magit-sequencer-skip)
- (?a "Abort" magit-sequencer-abort))
- :sequence-predicate 'magit-sequencer-in-progress-p
- :default-arguments '("--ff"))
-
-(defun magit-cherry-pick-read-args (prompt)
- (list (or (nreverse (magit-region-values 'commit))
- (magit-read-other-branch-or-commit prompt))
- (magit-cherry-pick-arguments)))
-
-;;;###autoload
-(defun magit-cherry-pick (commit &optional args)
- "Cherry-pick COMMIT.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then pick all of them,
-without prompting."
- (interactive (magit-cherry-pick-read-args "Cherry-pick"))
- (magit-assert-one-parent (car (if (listp commit)
- commit
- (split-string commit "\\.\\.")))
- "cherry-pick")
- (magit-run-git-sequencer "cherry-pick" args commit))
-
-;;;###autoload
-(defun magit-cherry-apply (commit &optional args)
- "Apply the changes in COMMIT but do not commit them.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then apply all of them,
-without prompting."
- (interactive (magit-cherry-pick-read-args "Apply changes from commit"))
- (magit-assert-one-parent commit "cherry-pick")
- (magit-run-git-sequencer "cherry-pick" "--no-commit"
- (remove "--ff" args) commit))
-
-(defun magit-cherry-pick-in-progress-p ()
- ;; .git/sequencer/todo does not exist when there is only one commit left.
- (file-exists-p (magit-git-dir "CHERRY_PICK_HEAD")))
-
-;;; Revert
-
-;;;###autoload (autoload 'magit-revert-popup "magit-sequence" nil t)
-(magit-define-popup magit-revert-popup
- "Popup console for revert commands."
- 'magit-commands
- :man-page "git-revert"
- :switches '((?s "Add Signed-off-by lines" "--signoff"))
- :options '((?s "Strategy" "--strategy="))
- :actions '((?V "Revert commit(s)" magit-revert)
- (?v "Revert changes" magit-revert-no-commit))
- :sequence-actions '((?V "Continue" magit-sequencer-continue)
- (?s "Skip" magit-sequencer-skip)
- (?a "Abort" magit-sequencer-abort))
- :sequence-predicate 'magit-sequencer-in-progress-p)
-
-(defun magit-revert-read-args (prompt)
- (list (or (magit-region-values 'commit)
- (magit-read-branch-or-commit prompt))
- (magit-revert-arguments)))
-
-;;;###autoload
-(defun magit-revert (commit &optional args)
- "Revert COMMIT by creating a new commit.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting."
- (interactive (magit-revert-read-args "Revert commit"))
- (magit-assert-one-parent commit "revert")
- (magit-run-git-sequencer "revert" args commit))
-
-;;;###autoload
-(defun magit-revert-no-commit (commit &optional args)
- "Revert COMMIT by applying it in reverse to the worktree.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting."
- (interactive (magit-revert-read-args "Revert changes"))
- (magit-assert-one-parent commit "revert")
- (magit-run-git-sequencer "revert" "--no-commit" args commit))
-
-(defun magit-revert-in-progress-p ()
- ;; .git/sequencer/todo does not exist when there is only one commit left.
- (file-exists-p (magit-git-dir "REVERT_HEAD")))
-
-;;; Patch
-
-;;;###autoload (autoload 'magit-am-popup "magit-sequence" nil t)
-(magit-define-popup magit-am-popup
- "Popup console for mailbox commands."
- 'magit-commands
- :man-page "git-am"
- :switches '((?3 "Fall back on 3way merge" "--3way")
- (?s "Add Signed-off-by lines" "--signoff")
- (?c "Remove text before scissors line" "--scissors")
- (?k "Inhibit removal of email cruft" "--keep")
- (?b "Limit removal of email cruft" "--keep-non-patch")
- (?d "Use author date as committer date"
- "--committer-date-is-author-date")
- (?D "Use committer date as author date" "--ignore-date"))
- :options '((?p "Remove leading slashes from paths" "-p"
- magit-popup-read-number))
- :actions '((?w "Apply patches" magit-am-apply-patches)
- (?m "Apply maildir" magit-am-apply-maildir))
- :default-arguments '("--3way")
- :default-actions 'magit-am-apply-patches
- :sequence-actions '((?w "Continue" magit-am-continue)
- (?s "Skip" magit-am-skip)
- (?a "Abort" magit-am-abort))
- :sequence-predicate 'magit-am-in-progress-p)
-
-;;;###autoload
-(defun magit-am-apply-patches (&optional files args)
- "Apply the patches FILES."
- (interactive (list (or (magit-region-values 'file)
- (list (let ((default (magit-file-at-point)))
- (read-file-name
- (if default
- (format "Apply patch (%s): " default)
- "Apply patch: ")
- nil default))))
- (magit-am-arguments)))
- (magit-run-git-sequencer "am" args "--" (mapcar 'expand-file-name files)))
-
-;;;###autoload
-(defun magit-am-apply-maildir (&optional maildir args)
- "Apply the patches from MAILDIR."
- (interactive (list (read-file-name "Apply mbox or Maildir: ")
- (magit-am-arguments)))
- (magit-run-git-sequencer "am" args (expand-file-name maildir)))
-
-;;;###autoload
-(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")))
-
-;;;###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")))
-
-;;;###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")))
-
-(defun magit-am-in-progress-p ()
- (file-exists-p (magit-git-dir "rebase-apply/applying")))
-
-;;; Rebase
-
-;;;###autoload (autoload 'magit-rebase-popup "magit-sequence" nil t)
-(magit-define-popup magit-rebase-popup
- "Key menu for rebasing."
- 'magit-commands
- :man-page "git-rebase"
- :switches '((?k "Keep empty commits" "--keep-empty")
- (?p "Preserve merges" "--preserve-merges")
- (?c "Lie about author date" "--committer-date-is-author-date")
- (?a "Autosquash" "--autosquash")
- (?A "Autostash" "--autostash")
- (?i "Interactive" "--interactive"))
- :actions '((lambda ()
- (concat (propertize "Rebase " 'face 'magit-popup-heading)
- (propertize (or (magit-get-current-branch) "HEAD")
- 'face 'magit-branch-local)
- (propertize " onto" 'face 'magit-popup-heading)))
- (?p (lambda ()
- (--when-let (magit-get-push-branch) (concat it "\n")))
- magit-rebase-onto-pushremote)
- (?u (lambda ()
- (--when-let (magit-get-upstream-branch) (concat it "\n")))
- magit-rebase-onto-upstream)
- (?e "elsewhere" magit-rebase)
- "Rebase"
- (?i "interactively" magit-rebase-interactive)
- (?m "to edit a commit" magit-rebase-edit-commit)
- (?s "subset" magit-rebase-subset)
- (?w "to reword a commit" magit-rebase-reword-commit) nil
- (?f "to autosquash" magit-rebase-autosquash))
- :sequence-actions '((?r "Continue" magit-rebase-continue)
- (?s "Skip" magit-rebase-skip)
- (?e "Edit" magit-rebase-edit)
- (?a "Abort" magit-rebase-abort))
- :sequence-predicate 'magit-rebase-in-progress-p
- :max-action-columns 2)
-
-(defun magit-git-rebase (target args)
- (magit-run-git-sequencer "rebase" target args))
-
-;;;###autoload
-(defun magit-rebase-onto-pushremote (args)
- "Rebase the current branch onto `branch.<name>.pushRemote'.
-If that variable is unset, then rebase onto `remote.pushDefault'."
- (interactive (list (magit-rebase-arguments)))
- (--if-let (magit-get-current-branch)
- (-if-let (remote (magit-get-push-remote it))
- (if (member remote (magit-list-remotes))
- (magit-git-rebase (concat remote "/" it) args)
- (user-error "Remote `%s' doesn't exist" remote))
- (user-error "No push-remote is configured for %s" it))
- (user-error "No branch is checked out")))
-
-;;;###autoload
-(defun magit-rebase-onto-upstream (args)
- "Rebase the current branch onto its upstream branch."
- (interactive (list (magit-rebase-arguments)))
- (--if-let (magit-get-current-branch)
- (-if-let (target (magit-get-upstream-branch it))
- (magit-git-rebase target args)
- (user-error "No upstream is configured for %s" it))
- (user-error "No branch is checked out")))
-
-;;;###autoload
-(defun magit-rebase (target args)
- "Rebase the current branch onto a branch read in the minibuffer.
-All commits that are reachable from head but not from the
-selected branch TARGET are being rebased."
- (interactive (list (magit-read-other-branch-or-commit "Rebase onto")
- (magit-rebase-arguments)))
- (message "Rebasing...")
- (magit-git-rebase target args)
- (message "Rebasing...done"))
-
-;;;###autoload
-(defun magit-rebase-subset (newbase start args)
- "Rebase a subset of the current branches history onto a new base.
-Rebase commits from START to `HEAD' onto NEWBASE.
-START has to be selected from a list of recent commits."
- (interactive (list (magit-read-other-branch-or-commit
- "Rebase subset onto" nil
- (magit-get-upstream-branch))
- nil
- (magit-rebase-arguments)))
- (if start
- (progn (message "Rebasing...")
- (magit-run-git-sequencer "rebase" "--onto" newbase start args)
- (message "Rebasing...done"))
- (magit-log-select
- `(lambda (commit)
- (magit-rebase-subset ,newbase (concat commit "^") (list ,@args)))
- (concat "Type %p on a commit to rebase it "
- "and commits above it onto " newbase ","))))
-
-(defun magit-rebase-interactive-1 (commit args message &optional editor)
- (declare (indent 2))
- (when commit
- (if (eq commit :merge-base)
- (setq commit (--if-let (magit-get-upstream-branch)
- (magit-git-string "merge-base" it "HEAD")
- nil))
- (when (magit-git-failure "merge-base" "--is-ancestor" commit "HEAD")
- (user-error "%s isn't an ancestor of HEAD" commit))
- (if (magit-commit-parents commit)
- (setq commit (concat commit "^"))
- (setq args (cons "--root" args)))))
- (when (and commit
- (magit-git-lines "rev-list" "--merges" (concat commit "..HEAD")))
- (magit-read-char-case "Proceed despite merge in rebase range? " nil
- (?c "[c]ontinue")
- (?s "[s]elect other" (setq commit nil))
- (?a "[a]bort" (user-error "Quit"))))
- (if commit
- (let ((process-environment process-environment))
- (when editor
- (push (concat "GIT_SEQUENCE_EDITOR=" editor) process-environment))
- (magit-run-git-sequencer "rebase" "-i" args
- (unless (member "--root" args) commit)))
- (magit-log-select
- `(lambda (commit)
- (magit-rebase-interactive-1 commit (list ,@args) ,message ,editor))
- message)))
-
-;;;###autoload
-(defun magit-rebase-interactive (commit args)
- "Start an interactive rebase sequence."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to rebase it and all commits above it,"))
-
-;;;###autoload
-(defun magit-rebase-autosquash (args)
- "Combine squash and fixup commits with their intended targets."
- (interactive (list (magit-rebase-arguments)))
- (magit-rebase-interactive-1 :merge-base (cons "--autosquash" args)
- "Type %p on a commit to squash into it and then rebase as necessary,"
- "true"))
-
-;;;###autoload
-(defun magit-rebase-edit-commit (commit args)
- "Edit a single older commit using rebase."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to edit it,"
- "perl -i -p -e '++$x if not $x and s/^pick/edit/'"))
-
-;;;###autoload
-(defun magit-rebase-reword-commit (commit args)
- "Reword a single older commit using rebase."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to reword its message,"
- "perl -i -p -e '++$x if not $x and s/^pick/reword/'"))
-
-;;;###autoload
-(defun magit-rebase-continue (&optional noedit)
- "Restart the current rebasing operation.
-In some cases this pops up a commit message buffer for you do
-edit. With a prefix argument the old message is reused as-is."
- (interactive "P")
- (if (magit-rebase-in-progress-p)
- (if (magit-anything-unstaged-p t)
- (user-error "Cannot continue rebase with unstaged changes")
- (if noedit
- (let ((process-environment process-environment))
- (push "GIT_EDITOR=true" process-environment)
- (magit-run-git-async "rebase" "--continue")
- (set-process-sentinel magit-this-process
- #'magit-sequencer-process-sentinel)
- magit-this-process)
- (magit-run-git-sequencer "rebase" "--continue")))
- (user-error "No rebase in progress")))
-
-;;;###autoload
-(defun magit-rebase-skip ()
- "Skip the current commit and restart the current rebase operation."
- (interactive)
- (if (magit-rebase-in-progress-p)
- (magit-run-git-sequencer "rebase" "--skip")
- (user-error "No rebase in progress")))
-
-;;;###autoload
-(defun magit-rebase-edit ()
- "Edit the todo list of the current rebase operation."
- (interactive)
- (if (magit-rebase-in-progress-p)
- (magit-run-git-sequencer "rebase" "--edit-todo")
- (user-error "No rebase in progress")))
-
-;;;###autoload
-(defun magit-rebase-abort ()
- "Abort the current rebase operation, restoring the original branch."
- (interactive)
- (if (magit-rebase-in-progress-p)
- (magit-run-git "rebase" "--abort")
- (user-error "No rebase in progress")))
-
-(defun magit-rebase-in-progress-p ()
- "Return t if a rebase is in progress."
- (or (file-exists-p (magit-git-dir "rebase-merge"))
- (file-exists-p (magit-git-dir "rebase-apply/onto"))))
-
-;;; Sections
-
-(defun magit-insert-sequencer-sequence ()
- "Insert section for the on-going cherry-pick or revert sequence.
-If no such sequence is in progress, do nothing."
- (let ((picking (magit-cherry-pick-in-progress-p)))
- (when (or picking (magit-revert-in-progress-p))
- (magit-insert-section (sequence)
- (magit-insert-heading (if picking "Cherry Picking" "Reverting"))
- (-when-let (lines (cdr (magit-file-lines (magit-git-dir "sequencer/todo"))))
- (dolist (line (nreverse lines))
- (when (string-match "^\\(pick\\|revert\\) \\([^ ]+\\) \\(.*\\)$" line)
- (magit-bind-match-strings (cmd hash msg) line
- (magit-insert-section (commit hash)
- (insert (propertize cmd 'face 'magit-sequence-pick)
- " " (propertize hash 'face 'magit-hash)
- " " msg "\n"))))))
- (magit-sequence-insert-sequence
- (magit-file-line (magit-git-dir (if picking
- "CHERRY_PICK_HEAD"
- "REVERT_HEAD")))
- (magit-file-line (magit-git-dir "sequencer/head")))
- (insert "\n")))))
-
-(defun magit-insert-am-sequence ()
- "Insert section for the on-going patch applying sequence.
-If no such sequence is in progress, do nothing."
- (when (magit-am-in-progress-p)
- (magit-insert-section (rebase-sequence)
- (magit-insert-heading "Applying patches")
- (let ((patches (nreverse (magit-rebase-patches)))
- patch commit)
- (while patches
- (setq patch (pop patches)
- commit (magit-rev-verify-commit
- (cadr (split-string (magit-file-line patch)))))
- (cond ((and commit patches)
- (magit-sequence-insert-commit
- "pick" commit 'magit-sequence-pick))
- (patches
- (magit-sequence-insert-am-patch
- "pick" patch 'magit-sequence-pick))
- (commit
- (magit-sequence-insert-sequence commit "ORIG_HEAD"))
- (t
- (magit-sequence-insert-am-patch
- "stop" patch 'magit-sequence-stop)
- (magit-sequence-insert-sequence nil "ORIG_HEAD")))))
- (insert ?\n))))
-
-(defun magit-sequence-insert-am-patch (type patch face)
- (magit-insert-section (file patch)
- (insert (propertize type 'face face)
- ?\s (propertize (file-name-nondirectory patch) 'face 'magit-hash)
- ?\n)))
-
-(defun magit-insert-rebase-sequence ()
- "Insert section for the on-going rebase sequence.
-If no such sequence is in progress, do nothing."
- (when (magit-rebase-in-progress-p)
- (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge")))
- (dir (if interactive "rebase-merge/" "rebase-apply/"))
- (name (-> (concat dir "head-name") magit-git-dir magit-file-line))
- (onto (-> (concat dir "onto") magit-git-dir magit-file-line))
- (onto (or (magit-rev-name onto name)
- (magit-rev-name onto "refs/heads/*") onto))
- (name (or (magit-rev-name name "refs/heads/*") name)))
- (magit-insert-section (rebase-sequence)
- (magit-insert-heading (format "Rebasing %s onto %s" name onto))
- (if interactive
- (magit-rebase-insert-merge-sequence)
- (magit-rebase-insert-apply-sequence))
- (magit-sequence-insert-sequence
- (magit-file-line
- (magit-git-dir
- (concat dir (if interactive "stopped-sha" "original-commit"))))
- onto (--map (cadr (split-string it))
- (magit-file-lines (magit-git-dir "rebase-merge/done"))))
- (insert ?\n)))))
-
-(defun magit-rebase-insert-merge-sequence ()
- (dolist (line (nreverse
- (magit-file-lines
- (magit-git-dir "rebase-merge/git-rebase-todo"))))
- (when (string-match "^\\([^# ]+\\) \\([^ ]+\\) .*$" line)
- (magit-bind-match-strings (action hash) line
- (magit-sequence-insert-commit action hash 'magit-sequence-pick)))))
-
-(defun magit-rebase-insert-apply-sequence ()
- (dolist (patch (nreverse (cdr (magit-rebase-patches))))
- (magit-sequence-insert-commit
- "pick" (cadr (split-string (magit-file-line patch))) 'magit-sequence-pick)))
-
-(defun magit-rebase-patches ()
- (directory-files (magit-git-dir "rebase-apply") t "^[0-9]\\{4\\}$"))
-
-(defun magit-sequence-insert-sequence (stop onto &optional orig)
- (let ((head (magit-rev-parse "HEAD")) done)
- (setq onto (if onto (magit-rev-parse onto) head))
- (setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD")))
- (when (and stop (not (member stop done)))
- (let ((id (magit-patch-id stop)))
- (--if-let (--first (equal (magit-patch-id it) id) done)
- (setq stop it)
- (cond
- ((--first (magit-rev-equal it 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...
- ((magit-anything-unmerged-p)
- ;; ...and time travel isn't for the faint of heart.
- (magit-sequence-insert-commit "join" stop 'magit-sequence-part))
- ((magit-anything-modified-p t)
- ;; ...and the dust hasn't settled yet...
- (magit-sequence-insert-commit
- (let ((staged (magit-commit-tree "oO" nil "HEAD"))
- (unstaged (magit-commit-worktree "oO" "--reset")))
- (cond
- ;; ...but we could end up at the same tree just by committing.
- ((or (magit-rev-equal staged stop)
- (magit-rev-equal unstaged stop)) "goal")
- ;; ...but the changes are still there, untainted.
- ((or (equal (magit-patch-id staged) id)
- (equal (magit-patch-id unstaged) id)) "same")
- ;; ...and some changes are gone and/or others were added.
- (t "work")))
- stop 'magit-sequence-part))
- ;; The commit is definitely gone...
- ((--first (magit-rev-equal it stop) done)
- ;; ...but all of its changes are still in effect.
- (magit-sequence-insert-commit "poof" stop 'magit-sequence-drop))
- (t
- ;; ...and some changes are gone and/or other changes were added.
- (magit-sequence-insert-commit "gone" stop 'magit-sequence-drop)))
- (setq stop nil))))
- (dolist (rev done)
- (apply 'magit-sequence-insert-commit
- (cond ((equal rev stop)
- ;; ...but its reincarnation lives on.
- ;; Or it didn't die in the first place.
- (list (if (and (equal rev head)
- (equal (magit-patch-id (concat stop "^"))
- (magit-patch-id (car (last orig 2)))))
- "stop" ; We haven't done anything yet.
- "same") ; There are new commits.
- rev (if (equal rev head)
- 'magit-sequence-head
- 'magit-sequence-stop)))
- ((equal rev head)
- (list "done" rev 'magit-sequence-head))
- (t
- (list "done" rev 'magit-sequence-done)))))
- (magit-sequence-insert-commit "onto" onto
- (if (equal onto head)
- 'magit-sequence-head
- 'magit-sequence-onto))))
-
-(defun magit-sequence-insert-commit (type hash face)
- (magit-insert-section (commit hash)
- (insert (propertize type 'face face) ?\s
- (magit-format-rev-summary hash) ?\n)))
-
-;;; magit-sequence.el ends soon
-(provide 'magit-sequence)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-sequence.el ends here
+++ /dev/null
-;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Support for Git stashes.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-stash-popup "magit-stash" nil t)
-(magit-define-popup magit-stash-popup
- "Popup console for stash commands."
- 'magit-commands
- :man-page "git-stash"
- :switches '((?u "Also save untracked files" "--include-untracked")
- (?a "Also save untracked and ignored files" "--all"))
- :actions '((?z "Save" magit-stash)
- (?Z "Snapshot" magit-snapshot)
- (?p "Pop" magit-stash-pop)
- (?i "Save index" magit-stash-index)
- (?I "Snapshot index" magit-snapshot-index)
- (?a "Apply" magit-stash-apply)
- (?w "Save worktree" magit-stash-worktree)
- (?W "Snapshot worktree" magit-snapshot-worktree)
- (?l "List" magit-stash-list)
- (?x "Save keeping index" magit-stash-keep-index)
- (?r "Snapshot to wipref" magit-wip-commit)
- (?v "Show" magit-stash-show)
- (?b "Branch" magit-stash-branch)
- (?k "Drop" magit-stash-drop) nil
- (?f "Format patch" magit-stash-format-patch))
- :default-action 'magit-stash
- :max-action-columns 3)
-
-;;;###autoload
-(defun magit-stash (message &optional include-untracked)
- "Create a stash of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message t t include-untracked t))
-
-;;;###autoload
-(defun magit-stash-index (message)
- "Create a stash of the index only.
-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)))
- (magit-stash-save message t nil nil t 'worktree))
-
-;;;###autoload
-(defun magit-stash-worktree (message &optional include-untracked)
- "Create a stash of unstaged changes in the working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message nil t include-untracked t 'index))
-
-;;;###autoload
-(defun magit-stash-keep-index (message &optional include-untracked)
- "Create a stash of the index and working tree, keeping index intact.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message t t include-untracked t 'index))
-
-(defun magit-stash-read-args ()
- (list (magit-stash-read-message)
- (magit-stash-read-untracked)))
-
-(defun magit-stash-read-untracked ()
- (let ((prefix (prefix-numeric-value current-prefix-arg))
- (args (magit-stash-arguments)))
- (cond ((or (= prefix 16) (member "--all" args)) 'all)
- ((or (= prefix 4) (member "--include-untracked" args)) t))))
-
-(defun magit-stash-read-message ()
- (let* ((default (format "On %s: "
- (or (magit-get-current-branch) "(no branch)")))
- (input (magit-read-string "Stash message" default)))
- (if (equal input default)
- (concat default (magit-rev-format "%h %s"))
- input)))
-
-;;;###autoload
-(defun magit-snapshot (&optional include-untracked)
- "Create a snapshot of the index and working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-snapshot-read-args))
- (magit-snapshot-save t t include-untracked t))
-
-;;;###autoload
-(defun magit-snapshot-index ()
- "Create a snapshot of the index only.
-Unstaged and untracked changes are not stashed."
- (interactive)
- (magit-snapshot-save t nil nil t))
-
-;;;###autoload
-(defun magit-snapshot-worktree (&optional include-untracked)
- "Create a snapshot of unstaged changes in the working tree.
-Untracked files are included according to popup arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-snapshot-read-args))
- (magit-snapshot-save nil t include-untracked t))
-
-(defun magit-snapshot-read-args ()
- (list (magit-stash-read-untracked)))
-
-(defun magit-snapshot-save (index worktree untracked &optional refresh)
- (magit-stash-save (concat "WIP on " (magit-stash-summary))
- index worktree untracked refresh t))
-
-;;;###autoload
-(defun magit-stash-apply (stash)
- "Apply a stash to the working tree.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index."
- (interactive (list (magit-read-stash "Apply stash" t)))
- (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
- (magit-refresh)
- (magit-run-git "stash" "apply" stash)))
-
-(defun magit-stash-pop (stash)
- "Apply a stash to the working tree and remove it from stash list.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index
-and forgo removing the stash."
- (interactive (list (magit-read-stash "Apply pop" t)))
- (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
- (magit-stash-drop stash)
- (magit-run-git "stash" "apply" stash)))
-
-;;;###autoload
-(defun magit-stash-drop (stash)
- "Remove a stash from the stash list.
-When the region is active offer to drop all contained stashes."
- (interactive (list (--if-let (magit-region-values 'stash)
- (magit-confirm t nil "Drop %i stashes" it)
- (magit-read-stash "Drop stash"))))
- (dolist (stash (if (listp stash)
- (nreverse (prog1 stash (setq stash (car stash))))
- (list stash)))
- (message "Deleted refs/%s (was %s)" stash
- (magit-rev-parse "--short" stash))
- (magit-call-git "reflog" "delete" "--updateref" "--rewrite" stash))
- (-when-let (ref (and (string-match "\\(.+\\)@{[0-9]+}$" stash)
- (match-string 1 stash)))
- (unless (string-match "^refs/" ref)
- (setq ref (concat "refs/" ref)))
- (unless (magit-rev-verify (concat ref "@{0}"))
- (magit-run-git "update-ref" "-d" ref)))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-stash-clear (ref)
- "Remove all stashes saved in REF's reflog by deleting REF."
- (interactive
- (let ((ref (or (magit-section-when 'stashes) "refs/stash")))
- (if (magit-confirm t (format "Drop all stashes in %s" ref))
- (list ref)
- (user-error "Abort"))))
- (magit-run-git "update-ref" "-d" ref))
-
-;;;###autoload
-(defun magit-stash-branch (stash branch)
- "Create and checkout a new BRANCH from STASH."
- (interactive (list (magit-read-stash "Branch stash" t)
- (magit-read-string-ns "Branch name")))
- (magit-run-git "stash" "branch" branch stash))
-
-;;;###autoload
-(defun magit-stash-format-patch (stash)
- "Create a patch from STASH"
- (interactive (list (magit-read-stash "Create patch from stash" t)))
- (with-temp-file (magit-rev-format "0001-%f.patch" stash)
- (magit-git-insert "stash" "show" "-p" stash))
- (magit-refresh))
-
-;;; Plumbing
-
-(defun magit-stash-save (message index worktree untracked
- &optional refresh keep noerror ref)
- (if (or (and index (magit-staged-files t))
- (and worktree (magit-modified-files t))
- (and untracked (magit-untracked-files (eq untracked 'all))))
- (magit-with-toplevel
- (magit-stash-store message (or ref "refs/stash")
- (magit-stash-create message index worktree untracked))
- (if (eq keep 'worktree)
- (with-temp-buffer
- (magit-git-insert "diff" "--cached")
- (magit-run-git-with-input
- "apply" "--reverse" "--cached" "--ignore-space-change" "-")
- (magit-run-git-with-input
- "apply" "--reverse" "--ignore-space-change" "-"))
- (unless (eq keep t)
- (if (eq keep 'index)
- (magit-call-git "checkout" "--" ".")
- (magit-call-git "reset" "--hard" "HEAD"))
- (when untracked
- (magit-call-git "clean" "-f" (and (eq untracked 'all) "-x")))))
- (when refresh
- (magit-refresh)))
- (unless noerror
- (user-error "No %s changes to save" (cond ((not index) "unstaged")
- ((not worktree) "staged")
- (t "local"))))))
-
-(defun magit-stash-store (message ref commit)
- (magit-update-ref ref message commit t))
-
-(defun magit-stash-create (message index worktree untracked)
- (unless (magit-rev-parse "--verify" "HEAD")
- (error "You do not have the initial commit yet"))
- (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false")
- magit-git-global-arguments))
- (default-directory (magit-toplevel))
- (summary (magit-stash-summary))
- (head "HEAD"))
- (when (and worktree (not index))
- (setq head (magit-commit-tree "pre-stash index" nil "HEAD")))
- (or (setq index (magit-commit-tree (concat "index on " summary) nil head))
- (error "Cannot save the current index state"))
- (and untracked
- (setq untracked (magit-untracked-files (eq untracked 'all)))
- (setq untracked (magit-with-temp-index nil nil
- (or (and (magit-update-files untracked)
- (magit-commit-tree
- (concat "untracked files on " summary)))
- (error "Cannot save the untracked files")))))
- (magit-with-temp-index index "-m"
- (when worktree
- (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head))
- (error "Cannot save the current worktree state")))
- (or (magit-commit-tree message nil head index untracked)
- (error "Cannot save the current worktree state")))))
-
-(defun magit-stash-summary ()
- (concat (or (magit-get-current-branch) "(no branch)")
- ": " (magit-rev-format "%h %s")))
-
-;;; Sections
-
-(defvar magit-stashes-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-stash-clear)
- map)
- "Keymap for `stashes' section.")
-
-(defvar magit-stash-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-stash-show)
- (define-key map [remap magit-delete-thing] 'magit-stash-drop)
- (define-key map "a" 'magit-stash-apply)
- (define-key map "A" 'magit-stash-pop)
- map)
- "Keymap for `stash' sections.")
-
-(magit-define-section-jumper magit-jump-to-stashes
- "Stashes" stashes "refs/stash")
-
-(cl-defun magit-insert-stashes (&optional (ref "refs/stash")
- (heading "Stashes:"))
- "Insert `stashes' section showing reflog for \"refs/stash\".
-If optional REF is non-nil show reflog for that instead.
-If optional HEADING is non-nil use that as section heading
-instead of \"Stashes:\"."
- (when (magit-rev-verify ref)
- (magit-insert-section (stashes ref (not magit-status-expand-stashes))
- (magit-insert-heading heading)
- (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
- "reflog" "--format=%gd %at %gs" ref))))
-
-;;; List Stashes
-
-;;;###autoload
-(defun magit-stash-list ()
- "List all stashes in a buffer."
- (interactive)
- (magit-mode-setup #'magit-stashes-mode "refs/stash"))
-
-(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes"
- "Mode for looking at lists of stashes."
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(cl-defun magit-stashes-refresh-buffer (ref)
- (magit-insert-section (stashesbuf)
- (magit-insert-heading (if (equal ref "refs/stash")
- "Stashes:"
- (format "Stashes [%s]:" ref)))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
- "reflog" "--format=%gd %at %gs" ref)))
-
-;;; Show Stash
-
-(defcustom magit-stash-sections-hook
- '(magit-insert-stash-worktree
- magit-insert-stash-index
- magit-insert-stash-untracked)
- "Hook run to insert sections into stash buffers."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type 'hook)
-
-;;;###autoload
-(defun magit-stash-show (stash &optional args files)
- "Show all diffs of a stash in a buffer."
- (interactive (cons (or (and (not current-prefix-arg)
- (magit-stash-at-point))
- (magit-read-stash "Show stash"))
- (-let [(args files) (magit-diff-arguments)]
- (list (delete "--stat" args) files))))
- (magit-mode-setup #'magit-stash-mode stash nil args files))
-
-(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash"
- "Mode for looking at individual stashes."
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-stash-refresh-buffer (stash _const _args _files)
- (setq header-line-format
- (concat
- "\s" (propertize (capitalize stash) 'face 'magit-section-heading)
- "\s" (magit-rev-format "%s" stash)))
- (magit-insert-section (stash)
- (run-hooks 'magit-stash-sections-hook)))
-
-(defun magit-stash-insert-section (commit range message &optional files)
- (magit-insert-section (commit commit)
- (magit-insert-heading message)
- (magit-git-wash #'magit-diff-wash-diffs
- "diff" range "-p" "--no-prefix"
- (nth 2 magit-refresh-args)
- "--" (or files (nth 3 magit-refresh-args)))))
-
-(defun magit-insert-stash-index ()
- "Insert section showing staged changes of the stash."
- (let ((stash (car magit-refresh-args)))
- (magit-stash-insert-section (format "%s^2" stash)
- (format "%s^..%s^2" stash stash)
- "Staged")))
-
-(defun magit-insert-stash-worktree ()
- "Insert section showing unstaged changes of the stash."
- (let ((stash (car magit-refresh-args)))
- (magit-stash-insert-section stash
- (format "%s^2..%s" stash stash)
- "Unstaged")))
-
-(defun magit-insert-stash-untracked ()
- "Insert section showing the untracked files commit of the stash."
- (let ((stash (car magit-refresh-args))
- (rev (concat (car magit-refresh-args) "^3")))
- (when (magit-rev-verify rev)
- (magit-stash-insert-section (format "%s^3" stash)
- (format "%s^..%s^3" stash stash)
- "Untracked files"
- (magit-git-items "ls-tree" "-z" "--name-only"
- "-r" "--full-tree" rev)))))
-
-;;; magit-stash.el ends soon
-(provide 'magit-stash)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-stash.el ends here
+++ /dev/null
-;;; magit-submodule.el --- submodule support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2015 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-submodule-popup "magit-submodule" nil t)
-(magit-define-popup magit-submodule-popup
- "Popup console for submodule commands."
- 'magit-commands nil nil
- :man-page "git-submodule"
- :actions '((?a "Add" magit-submodule-add)
- (?b "Setup" magit-submodule-setup)
- (?i "Init" magit-submodule-init)
- (?u "Update" magit-submodule-update)
- (?s "Sync" magit-submodule-sync)
- (?f "Fetch" magit-submodule-fetch)
- (?d "Deinit" magit-submodule-deinit)))
-
-;;;###autoload
-(defun magit-submodule-add (url &optional path name)
- "Add the repository at URL as a submodule.
-
-Optional PATH is the path to the submodule relative to the root
-of the superproject. If it is nil, then the path is determined
-based on the URL.
-
-Optional NAME is the name of the submodule. If it is nil, then
-PATH also becomes the name."
- (interactive
- (magit-with-toplevel
- (let ((path (magit-completing-read "Add submodules at path"
- (magit-untracked-files)
- #'magit-git-repo-p nil nil nil
- (magit-section-when [file untracked]
- (file-relative-name
- (magit-section-value it)
- default-directory)))))
- (unless path
- (user-error "No path selected"))
- (list (magit-read-string-ns
- "Remote url"
- (let ((default-directory (file-name-as-directory
- (expand-file-name path))))
- (magit-get "remote" (or (magit-get-remote) "origin") "url")))
- (directory-file-name path)
- (magit-read-string-ns
- "Name submodule" nil nil
- (or (--keep (-let [(var val) (split-string it "=")]
- (and (equal val path)
- (cadr (split-string var "\\."))))
- (magit-git-lines "config" "--list" "-f" ".gitmodules"))
- (directory-file-name path)))))))
- (magit-run-git "submodule" "add" (and name (list "--name" name)) url path))
-
-;;;###autoload
-(defun magit-submodule-setup ()
- "Clone and register missing submodules and checkout appropriate commits."
- (interactive)
- (magit-submodule-update t))
-
-;;;###autoload
-(defun magit-submodule-init ()
- "Register submodules listed in \".gitmodules\" into \".git/config\"."
- (interactive)
- (magit-with-toplevel
- (magit-run-git-async "submodule" "init")))
-
-;;;###autoload
-(defun magit-submodule-update (&optional init)
- "Clone missing submodules and checkout appropriate commits.
-With a prefix argument also register submodules in \".git/config\"."
- (interactive "P")
- (magit-with-toplevel
- (magit-run-git-async "submodule" "update" (and init "--init"))))
-
-;;;###autoload
-(defun magit-submodule-sync ()
- "Update each submodule's remote URL according to \".gitmodules\"."
- (interactive)
- (magit-with-toplevel
- (magit-run-git-async "submodule" "sync")))
-
-;;;###autoload
-(defun magit-submodule-fetch (&optional all)
- "Fetch all submodules.
-With a prefix argument fetch all remotes."
- (interactive "P")
- (magit-with-toplevel
- (magit-run-git-async "submodule" "foreach"
- (format "git fetch %s || true" (if all "--all" "")))))
-
-;;;###autoload
-(defun magit-submodule-deinit (path)
- "Unregister the submodule at PATH."
- (interactive
- (list (magit-completing-read "Deinit module" (magit-get-submodules)
- nil t nil nil (magit-section-when module))))
- (magit-with-toplevel
- (magit-run-git-async "submodule" "deinit" path)))
-
-;;; Sections
-
-;;;###autoload
-(defun magit-insert-submodules ()
- "Insert sections for all modules.
-For each section insert the path and the output of `git describe --tags'."
- (-when-let (modules (magit-get-submodules))
- (magit-insert-section (modules nil t)
- (magit-insert-heading "Modules:")
- (magit-with-toplevel
- (dolist (module modules)
- (let ((default-directory
- (expand-file-name (file-name-as-directory module))))
- (magit-insert-section (file module t)
- (insert (format "%-25s " module))
- (--when-let (magit-git-string "describe" "--tags")
- (when (string-match-p "\\`[0-9]" it)
- (insert ?\s))
- (insert it))
- (insert ?\n)))))
- (insert ?\n))))
-
-;;;###autoload
-(defun magit-insert-modules-unpulled-from-upstream ()
- "Insert sections for modules that haven't been pulled from the upstream.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unpulled from @{upstream}"
- 'modules-unpulled-from-upstream
- 'magit-get-upstream-ref
- "HEAD..%s"))
-
-;;;###autoload
-(defun magit-insert-modules-unpulled-from-pushremote ()
- "Insert sections for modules that haven't been pulled from the push-remote.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unpulled from <push-remote>"
- 'modules-unpulled-from-pushremote
- 'magit-get-push-branch
- "HEAD..%s"))
-
-;;;###autoload
-(defun magit-insert-modules-unpushed-to-upstream ()
- "Insert sections for modules that haven't been pushed to the upstream.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unmerged into @{upstream}"
- 'modules-unpushed-to-upstream
- 'magit-get-upstream-ref
- "%s..HEAD"))
-
-;;;###autoload
-(defun magit-insert-modules-unpushed-to-pushremote ()
- "Insert sections for modules that haven't been pushed to the push-remote.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unpushed to <push-remote>"
- 'modules-unpushed-to-pushremote
- 'magit-get-push-branch
- "%s..HEAD"))
-
-(defun magit--insert-modules-logs (heading type fn format)
- "For internal use, don't add to a hook."
- (-when-let (modules (magit-get-submodules))
- (magit-insert-section section ((eval type) nil t)
- (string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading)
- (magit-insert-heading
- (concat
- (propertize (match-string 1 heading) 'face 'magit-section-heading) " "
- (propertize (match-string 2 heading) 'face 'magit-branch-remote) ":"))
- (magit-with-toplevel
- (dolist (module modules)
- (let ((default-directory
- (expand-file-name (file-name-as-directory module))))
- (--when-let (and (magit-file-accessible-directory-p default-directory)
- (funcall fn))
- (magit-insert-section sec (file module t)
- (magit-insert-heading
- (concat (propertize module 'face 'magit-diff-file-heading) ":"))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'module)
- "log" "--oneline" (format format it))
- (when (> (point) (magit-section-content sec))
- (delete-char -1)))))))
- (if (> (point) (magit-section-content section))
- (insert ?\n)
- (magit-cancel-section)))))
-
-;;; magit-submodule.el ends soon
-
-(define-obsolete-function-alias 'magit-insert-unpulled-module-commits
- 'magit-insert-modules-unpulled-from-upstream "Magit 2.6.0")
-(define-obsolete-function-alias 'magit-insert-unpushed-module-commits
- 'magit-insert-modules-unpushed-to-upstream "Magit 2.6.0")
-
-(provide 'magit-submodule)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-submodule.el ends here
+++ /dev/null
-;;; magit-subtree.el --- subtree support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2015 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(require 'magit)
-
-;;;###autoload (autoload 'magit-subtree-popup "magit-subtree" nil t)
-(magit-define-popup magit-subtree-popup
- "Popup console for subtree commands."
- 'magit-commands
- :man-page "git-subtree"
- :switches '("Switches for add, merge, push, and pull"
- (?s "Squash" "--squash")
- "Switches for split"
- (?i "Ignore joins" "--ignore-joins")
- (?j "Rejoin" "--rejoin"))
- :options '("Options"
- (?p "Prefix" "--prefix=" magit-subtree-read-prefix)
- "Options for add, merge, and pull"
- (?m "Message" "--message=")
- "Options for split"
- (?a "Annotate" "--annotate=")
- (?b "Branch" "--branch=")
- (?o "Onto" "--onto=" magit-read-branch-or-commit))
- :actions '((?a "Add" magit-subtree-add)
- (?m "Merge" magit-subtree-merge)
- (?p "Push" magit-subtree-push)
- (?c "Add commit" magit-subtree-add-commit)
- (?f "Pull" magit-subtree-pull)
- (?s "Split" magit-subtree-split))
- :max-action-columns 3)
-
-(defun magit-subtree-prefix (prompt)
- (--if-let (--first (string-prefix-p "--prefix=" it)
- (magit-subtree-arguments))
- (substring it 9)
- (magit-subtree-read-prefix prompt)))
-
-(defun magit-subtree-read-prefix (prompt &optional default)
- (let* ((insert-default-directory nil)
- (topdir (magit-toplevel))
- (prefix (read-directory-name (concat prompt ": ") topdir default)))
- (if (file-name-absolute-p prefix)
- ;; At least `ido-mode's variant is not compatible.
- (if (string-prefix-p topdir prefix)
- (file-relative-name prefix topdir)
- (user-error "%s isn't inside the repository at %s" prefix topdir))
- prefix)))
-
-(defun magit-subtree-args ()
- (-filter (lambda (arg)
- (if (eq this-command 'magit-subtree-split)
- (or (equal arg "--ignore-joins")
- (equal arg "--rejoin")
- (string-prefix-p "--annotate=" arg)
- (string-prefix-p "--branch=" arg)
- (string-prefix-p "--onto=" arg))
- (or (equal arg "--squash")
- (and (string-prefix-p "--message=" arg)
- (not (eq this-command 'magit-subtree-push))))))
- (magit-subtree-arguments)))
-
-(defun magit-git-subtree (subcmd prefix &rest args)
- (magit-run-git-async "subtree" subcmd (concat "--prefix=" prefix) args))
-
-;;;###autoload
-(defun magit-subtree-add (prefix repository commit args)
- "Add COMMIT from REPOSITORY as a new subtree at PREFIX."
- (interactive (list (magit-subtree-prefix "Add subtree")
- (magit-read-string-ns "Repository")
- (magit-read-string-ns "Commit")
- (magit-subtree-args)))
- (magit-git-subtree "add" prefix args repository commit))
-
-;;;###autoload
-(defun magit-subtree-add-commit (prefix commit args)
- "Add COMMIT as a new subtree at PREFIX."
- (interactive (list (magit-subtree-prefix "Add subtree")
- (magit-read-string-ns "Commit")
- (magit-subtree-args)))
- (magit-git-subtree "add" prefix args commit))
-
-;;;###autoload
-(defun magit-subtree-merge (prefix commit args)
- "Merge COMMIT into the PREFIX subtree."
- (interactive (list (magit-subtree-prefix "Merge into subtree")
- (magit-read-string-ns "Commit")
- (magit-subtree-args)))
- (magit-git-subtree "merge" prefix args commit))
-
-;;;###autoload
-(defun magit-subtree-pull (prefix repository commit args)
- "Pull COMMIT from REPOSITORY into the PREFIX subtree."
- (interactive (list (magit-subtree-prefix "Pull into subtree")
- (magit-read-string-ns "From repository")
- (magit-read-string-ns "Commit")
- (magit-subtree-args)))
- (magit-git-subtree "pull" prefix args repository commit))
-
-;;;###autoload
-(defun magit-subtree-push (prefix repository ref args)
- "Extract the history of the subtree PREFIX and push it to REF on REPOSITORY."
- (interactive (list (magit-subtree-prefix "Push subtree")
- (magit-read-string-ns "To repository")
- (magit-read-string-ns "To reference")
- (magit-subtree-args)))
- (magit-git-subtree "push" prefix args repository ref))
-
-;;;###autoload
-(defun magit-subtree-split (prefix commit args)
- "Extract the history of the subtree PREFIX."
- (interactive (list (magit-subtree-prefix "Split subtree")
- (magit-read-string-ns "Commit")
- (magit-subtree-args)))
- (magit-git-subtree "split" prefix args commit))
-
-;;; magit-subtree.el ends soon
-(provide 'magit-subtree)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-subtree.el ends here
+++ /dev/null
-;;; magit-utils.el --- various utilities -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Contains code from GNU Emacs https://www.gnu.org/software/emacs,
-;; released under the GNU General Public License version 3 or later.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library defines several utility functions used by several
-;; other libraries which cannot depend on one another (because
-;; circular dependencies are not good). Luckily most (all) of these
-;; functions have very little (nothing) to do with Git, so we not only
-;; have to do this, it even makes sense.
-
-;; Unfortunately there are also some options which are used by several
-;; libraries which cannot depend on one another, they are defined here
-;; too.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(eval-when-compile (require 'ido))
-(declare-function ido-completing-read+ 'ido-completing-read+)
-
-(defvar magit-wip-before-change-mode)
-
-;;; Options
-
-(defcustom magit-completing-read-function 'magit-builtin-completing-read
- "Function to be called when requesting input from the user.
-
-For Helm users, the simplest way to get Helm completion is to
-turn on `helm-mode' and leave this option set to the default
-value. However, if you prefer to not use `helm-mode' but still
-want Magit to use Helm for completion, you can set this option to
-`helm--completing-read-default'."
- :group 'magit
- :type '(radio (function-item magit-builtin-completing-read)
- (function-item magit-ido-completing-read)
- (function-item helm--completing-read-default)
- (function :tag "Other")))
-
-(defcustom magit-no-confirm nil
- "A list of symbols for actions Magit should not confirm, or t.
-
-Many potentially dangerous commands by default ask the user for
-confirmation. Each of the below symbols stands for an action
-which, when invoked unintentionally or without being fully aware
-of the consequences, could lead to tears. In many cases there
-are several commands that perform variations of a certain action,
-so we don't use the command names but more generic symbols.
-
-Applying changes:
-
- `discard' Discarding one or more changes (i.e. hunks or the
- complete diff for a file) loses that change, obviously.
-
- `reverse' Reverting one or more changes can usually be undone
- by reverting the reversion.
-
- `stage-all-changes', `unstage-all-changes' When there are both
- staged and unstaged changes, then un-/staging everything would
- destroy that distinction. Of course that also applies when
- un-/staging a single change, but then less is lost and one does
- that so often that having to confirm every time would be
- unacceptable.
-
-Files:
-
- `delete' When a file that isn't yet tracked by Git is deleted
- then it is completely lost, not just the last changes. Very
- dangerous.
-
- `trash' Instead of deleting a file it can also be move to the
- system trash. Obviously much less dangerous than deleting it.
-
- Also see option `magit-delete-by-moving-to-trash'.
-
- `resurrect' A deleted file can easily be resurrected by
- \"deleting\" the deletion, which is done using the same command
- that was used to delete the same file in the first place.
-
- `rename' Renaming a file can easily be undone.
-
-Sequences:
-
- `reset-bisect' Aborting (known to Git as \"resetting\") a
- bisect operation loses all information collected so far.
-
- `abort-merge' Aborting a merge throws away all conflict
- resolutions which has already been carried out by the user.
-
- `merge-dirty' Merging with a dirty worktree can make it hard to
- go back to the state before the merge was initiated.
-
-References:
-
- `delete-unmerged-branch' Once a branch has been deleted it can
- only be restored using low-level recovery tools provided by
- Git. And even then the reflog is gone. The user always has
- to confirm the deletion of a branch by accepting the default
- choice (or selecting another branch), but when a branch has
- not been merged yet, also make sure the user is aware of that.
-
- `drop-stashes' Dropping a stash is dangerous because Git stores
- stashes in the reflog. Once a stash is removed, there is no
- going back without using low-level recovery tools provided by
- Git. When a single stash is dropped, then the user always has
- to confirm by accepting the default (or selecting another).
- This action only concerns the deletion of multiple stashes at
- once.
-
-Various:
-
- `kill-process' There seldom is a reason to kill a process.
-
-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
- 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
- for confirmation for any of these actions, you are still better
- of adding all of the respective symbols individually.
-
- When `magit-wip-before-change-mode' is enabled then these actions
- can fairly easily be undone: `discard', `reverse',
- `stage-all-changes', and `unstage-all-changes'. If and only if
- this mode is enabled then `safe-with-wip' has the same effect
- as adding all of these symbols individually."
- :package-version '(magit . "2.1.0")
- :group 'magit
- :type '(choice (const :tag "No confirmation needed" t)
- (set (const reverse) (const discard)
- (const rename) (const resurrect)
- (const trash) (const delete)
- (const abort-merge) (const merge-dirty)
- (const drop-stashes) (const resect-bisect)
- (const kill-process) (const delete-unmerged-branch)
- (const stage-all-changes) (const unstage-all-changes)
- (const safe-with-wip))))
-
-(defcustom magit-no-message nil
- "A list of messages Magit should not display.
-
-Magit displays most echo area messages using `message', but a few
-are displayed using `magit-message' instead, which takes the same
-arguments as the former, FORMAT-STRING and ARGS. `magit-message'
-forgoes printing a message if any member of this list is a prefix
-of the respective FORMAT-STRING.
-
-If Magit prints a message which causes you grief, then please
-first investigate whether there is another option which can be
-used to suppress it. If that is not the case, then ask the Magit
-maintainers to start using `magit-message' instead of `message'
-in that case. We are not proactively replacing all uses of
-`message' with `magit-message', just in case someone *might* find
-some of these messages useless.
-
-Messages which can currently be suppressed using this option are:
-* \"Turning on magit-auto-revert-mode...\""
- :package-version '(magit . "2.7.1")
- :group 'magit
- :type '(repeat string))
-
-(defcustom magit-ellipsis ?…
- "Character used to abbreviate text."
- :package-version '(magit . "2.1.0")
- :group 'magit-modes
- :type 'character)
-
-(defcustom magit-update-other-window-delay 0.2
- "Delay before automatically updating the other window.
-
-When moving around in certain buffers certain other buffers,
-which are being displayed in another window, may optionally be
-updated to display information about the section at point.
-
-When holding down a key to move by more than just one section,
-then that would update that buffer for each section on the way.
-To prevent that, updating the revision buffer is delayed, and
-this option controls for how long. For optimal experience you
-might have to adjust this delay and/or the keyboard repeat rate
-and delay of your graphical environment or operating system."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'number)
-
-;;; User Input
-
-(defun magit-completing-read
- (prompt collection &optional predicate require-match initial-input hist def)
- "Magit wrapper around `completing-read' or an alternative function.
-
-Option `magit-completing-read-function' can be used to wrap
-around another `completing-read'-like function. Unless it
-doesn't have the exact same signature, an additional wrapper is
-required. Even if it has the same signature it might be a good
-idea to wrap it, so that `magit-prompt-with-default' can be used.
-
-See `completing-read' for the meanings of the arguments, but note
-that this wrapper makes the following changes:
-
-- If REQUIRE-MATCH is nil and the user exits without a choice,
- then return nil instead of an empty string.
-
-- If REQUIRE-MATCH is non-nil and the users exits without a
- choice, then raise an user-error.
-
-- \": \" is appended to PROMPT.
-
-- If a `magit-completing-read-function' is used which in turn
- uses `magit-prompt-with-completion' and DEF is non-nil, then
- PROMPT is modified to end with \" (default DEF): \".
-
-The use of another completing function and/or wrapper obviously
-results in additional differences."
- (let ((reply (funcall magit-completing-read-function
- (concat prompt ": ") collection predicate
- require-match initial-input hist def)))
- (if (string= reply "")
- (if require-match
- (user-error "Nothing selected")
- nil)
- reply)))
-
-(defun magit-builtin-completing-read
- (prompt choices &optional predicate require-match initial-input hist def)
- "Magit wrapper for standard `completing-read' function."
- (completing-read (magit-prompt-with-default prompt def)
- choices predicate require-match
- initial-input hist def))
-
-(defun magit-ido-completing-read
- (prompt choices &optional predicate require-match initial-input hist def)
- "Ido-based `completing-read' almost-replacement.
-
-Unfortunately `ido-completing-read' is not suitable as a
-drop-in replacement for `completing-read', instead we use
-`ido-completing-read+' from the third-party package by the
-same name."
- (if (require 'ido-completing-read+ nil t)
- (ido-completing-read+ prompt choices predicate require-match
- initial-input hist def)
- (display-warning 'magit "ido-completing-read+ is not installed
-
-To use Ido completion with Magit you need to install the
-third-party `ido-completing-read+' packages. Falling
-back to built-in `completing-read' for now." :error)
- (magit-builtin-completing-read prompt choices predicate require-match
- initial-input hist def)))
-
-(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 magit-minibuffer-local-ns-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map minibuffer-local-map)
- (define-key map "\s" 'magit-whitespace-disallowed)
- (define-key map "\t" 'magit-whitespace-disallowed)
- map))
-
-(defun magit-whitespace-disallowed ()
- "Beep to tell the user that whitespace is not allowed."
- (interactive)
- (ding)
- (message "Whitespace isn't allowed here")
- (setq defining-kbd-macro nil)
- (force-mode-line-update))
-
-(defun magit-read-string (prompt &optional initial-input history default-value
- inherit-input-method no-whitespace)
- "Read a string from the minibuffer, prompting with string PROMPT.
-
-This is similar to `read-string', but
-* empty input is only allowed if DEFAULT-VALUE is non-nil in
- which case that is returned,
-* whitespace is not allowed if NO-WHITESPACE is non-nil,
-* \": \" is appended to PROMPT, and
-* an invalid DEFAULT-VALUE is silently ignored."
- (when default-value
- (when (consp default-value)
- (setq default-value (car default-value)))
- (unless (stringp default-value)
- (setq default-value nil)))
- (let* ((minibuffer-completion-table nil)
- (val (read-from-minibuffer
- (magit-prompt-with-default (concat prompt ": ") default-value)
- initial-input (and no-whitespace magit-minibuffer-local-ns-map)
- nil history default-value inherit-input-method)))
- (when (and (string= val "") default-value)
- (setq val default-value))
- (cond ((string= val "")
- (user-error "Need non-empty input"))
- ((and no-whitespace (string-match-p "[\s\t\n]" val))
- (user-error "Input contains whitespace"))
- (t val))))
-
-(defun magit-read-string-ns (prompt &optional initial-input history
- default-value inherit-input-method)
- "Call `magit-read-string' with non-nil NO-WHITESPACE."
- (magit-read-string prompt initial-input history default-value
- inherit-input-method t))
-
-(defmacro magit-read-char-case (prompt verbose &rest clauses)
- (declare (indent 2)
- (debug (form form &rest (characterp form body))))
- `(pcase (read-char-choice
- (concat ,prompt
- ,(concat (mapconcat 'cadr clauses ", ")
- (and verbose ", or [C-g] to abort") " "))
- ',(mapcar 'car clauses))
- ,@(--map `(,(car it) ,@(cddr it)) clauses)))
-
-(cl-defun magit-confirm (action &optional prompt prompt-n (items nil sitems))
- (declare (indent defun))
- (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items))
- prompt (format (concat (or prompt (magit-confirm-make-prompt action))
- "? ")
- (car items)))
- (cond ((and (not (eq action t))
- (or (eq magit-no-confirm t)
- (memq action
- `(,@magit-no-confirm
- ,@(and magit-wip-before-change-mode
- (memq 'safe-with-wip magit-no-confirm)
- `(discard reverse
- stage-all-changes
- unstage-all-changes))))))
- (or (not sitems) items))
- ((not sitems)
- (y-or-n-p prompt))
- ((= (length items) 1)
- (and (y-or-n-p prompt) items))
- ((> (length items) 1)
- (let ((buffer (get-buffer-create " *Magit Confirm*")))
- (with-current-buffer buffer
- (with-current-buffer-window
- buffer (cons 'display-buffer-below-selected
- '((window-height . fit-window-to-buffer)))
- (lambda (window _value)
- (with-selected-window window
- (unwind-protect (and (y-or-n-p prompt-n) items)
- (when (window-live-p window)
- (quit-restore-window window 'kill)))))
- (dolist (item items)
- (insert item "\n"))))))))
-
-(defun magit-confirm-files (action files &optional prompt)
- (when files
- (unless prompt
- (setq prompt (magit-confirm-make-prompt action)))
- (magit-confirm action
- (concat prompt " %s")
- (concat prompt " %i files")
- files)))
-
-(defun magit-confirm-make-prompt (action)
- (let ((prompt (symbol-name action)))
- (replace-regexp-in-string
- "-" " " (concat (upcase (substring prompt 0 1)) (substring prompt 1)))))
-
-;;; Text Utilities
-
-(defmacro magit-bind-match-strings (varlist string &rest body)
- "Bind variables to submatches according to VARLIST then evaluate BODY.
-Bind the symbols in VARLIST to submatches of the current match
-data, starting with 1 and incrementing by 1 for each symbol. If
-the last match was against a string then that has to be provided
-as STRING."
- (declare (indent 2) (debug (listp form body)))
- (let ((s (cl-gensym "string"))
- (i 0))
- `(let ((,s ,string))
- (let ,(save-match-data
- (--map (list it (list 'match-string (cl-incf i) s)) varlist))
- ,@body))))
-
-(defun magit-delete-line ()
- "Delete the rest of the current line."
- (delete-region (point) (1+ (line-end-position))))
-
-(defun magit-delete-match (&optional num)
- "Delete text matched by last search.
-If optional NUM is specified only delete that subexpression."
- (delete-region (match-beginning (or num 0))
- (match-end (or num 0))))
-
-(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)))))
-
-(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)))))
-
-;;; Kludges
-
-(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)))
-
-(defun magit-message (format-string &rest args)
- "Display a message at the bottom of the screen, or not.
-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)
- (apply #'message format-string args)))
-
-;;; magit-utils.el ends soon
-(provide 'magit-utils)
-;; Local Variables:
-;; coding: utf-8
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-utils.el ends here
+++ /dev/null
-;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library defines tree global modes which automatically commit
-;; snapshots to branch specific work-in-progress refs before and after
-;; making changes, and two commands which can be used to do so on
-;; demand.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-log)
-
-;;; Options
-
-(defgroup magit-wip nil
- "Automatically commit to work-in-progress refs."
- :group 'magit-extensions)
-
-(defcustom magit-wip-after-save-local-mode-lighter " sWip"
- "Lighter for Magit-Wip-After-Save-Local mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-(defcustom magit-wip-after-apply-mode-lighter " aWip"
- "Lighter for Magit-Wip-After-Apply mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-(defcustom magit-wip-before-change-mode-lighter " cWip"
- "Lighter for Magit-Wip-Before-Change mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-(defcustom magit-wip-namespace "refs/wip/"
- "Namespace used for work-in-progress refs.
-The wip refs are named \"<namespace/>index/<branchref>\"
-and \"<namespace/>wtree/<branchref>\". When snapshots
-are created while the `HEAD' is detached then \"HEAD\"
-is used as `branch-ref'."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-;;; Modes
-
-(define-minor-mode magit-wip-after-save-local-mode
- "After saving, also commit to a worktree work-in-progress ref.
-
-After saving the current file-visiting buffer this mode also
-commits the changes to the worktree work-in-progress ref for
-the current branch.
-
-This mode should be enabled globally by turning on the globalized
-variant `magit-wip-after-save-mode'."
- :package-version '(magit . "2.1.0")
- :lighter magit-wip-after-save-local-mode-lighter
- (if magit-wip-after-save-local-mode
- (if (and buffer-file-name (magit-inside-worktree-p))
- (add-hook 'after-save-hook 'magit-wip-commit-buffer-file t t)
- (setq magit-wip-after-save-local-mode nil)
- (user-error "Need a worktree and a file"))
- (remove-hook 'after-save-hook 'magit-wip-commit-buffer-file t)))
-
-(defun magit-wip-after-save-local-mode-turn-on ()
- (and buffer-file-name
- (ignore-errors (magit-inside-worktree-p))
- (magit-file-tracked-p buffer-file-name)
- (magit-wip-after-save-local-mode)))
-
-;;;###autoload
-(define-globalized-minor-mode magit-wip-after-save-mode
- magit-wip-after-save-local-mode magit-wip-after-save-local-mode-turn-on
- :package-version '(magit . "2.1.0")
- :group 'magit-wip)
-
-(defun magit-wip-commit-buffer-file ()
- "Commit visited file to a worktree work-in-progress ref.
-
-Also see `magit-wip-after-save-mode' which calls this function
-automatically whenever a buffer visiting a tracked file is saved."
- (interactive)
- (--when-let (magit-wip-get-ref)
- (magit-with-toplevel
- (let ((file (file-relative-name buffer-file-name)))
- (magit-wip-commit-worktree
- it (list file) (if (called-interactively-p 'any)
- (format "wip-save %s after save" file)
- (format "autosave %s after save" file)))))))
-
-;;;###autoload
-(define-minor-mode magit-wip-after-apply-mode
- "Commit to work-in-progress refs.
-
-After applying a change using any \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected files to the current wip refs. For each branch there
-may be two wip refs; one contains snapshots of the files as found
-in the worktree and the other contains snapshots of the entries
-in the index."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :lighter magit-wip-after-change-mode-lighter
- :global t)
-
-(defun magit-wip-commit-after-apply (&optional files msg)
- (when magit-wip-after-apply-mode
- (magit-wip-commit files msg)))
-
-;;;###autoload
-(define-minor-mode magit-wip-before-change-mode
- "Commit to work-in-progress refs before certain destructive changes.
-
-Before invoking a revert command or an \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected tracked files to the current wip refs. For each branch
-there may be two wip refs; one contains snapshots of the files
-as found in the worktree and the other contains snapshots of the
-entries in the index.
-
-Only changes to files which could potentially be affected by the
-command which is about to be called are committed."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :lighter magit-wip-before-change-mode-lighter
- :global t)
-
-(defun magit-wip-commit-before-change (&optional files msg)
- (when magit-wip-before-change-mode
- (magit-with-toplevel
- (magit-wip-commit files msg))))
-
-;;; Core
-
-(defun magit-wip-commit (&optional files msg)
- "Commit all tracked files to the work-in-progress refs.
-
-Interactively, commit all changes to all tracked files using
-a generic commit message. With a prefix-argument the commit
-message is read in the minibuffer.
-
-Non-interactively, only commit changes to FILES using MSG as
-commit message."
- (interactive (list nil (if current-prefix-arg
- (magit-read-string "Wip commit message")
- "wip-save tracked files")))
- (--when-let (magit-wip-get-ref)
- (magit-wip-commit-index it files msg)
- (magit-wip-commit-worktree it files msg)))
-
-(defun magit-wip-commit-index (ref files msg &optional cached-only)
- (let* ((wipref (concat magit-wip-namespace "index/" ref))
- (parent (magit-wip-get-parent ref wipref)))
- (when (magit-git-failure "diff-index" "--quiet"
- (and cached-only "--cached")
- parent "--" files)
- (magit-wip-update-wipref wipref (magit-git-string "write-tree")
- parent files msg "index"))))
-
-(defun magit-wip-commit-worktree (ref files msg)
- (let* ((wipref (concat magit-wip-namespace "wtree/" ref))
- (parent (magit-wip-get-parent ref wipref))
- (tree (magit-with-temp-index parent "--reset"
- (if files
- (magit-call-git "add" "--" files)
- (magit-with-toplevel
- (magit-call-git "add" "-u" ".")))
- (magit-git-string "write-tree"))))
- (when (magit-git-failure "diff-tree" "--quiet" parent tree "--" files)
- (magit-wip-update-wipref wipref tree parent files msg "worktree"))))
-
-(defun magit-wip-update-wipref (wipref tree parent files msg start-msg)
- (let ((len (length files)))
- (unless (and msg (not (= (aref msg 0) ?\s)))
- (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)))))
- msg)))
- (unless (equal parent wipref)
- (setq start-msg (concat "restart autosaving " start-msg))
- (magit-update-ref wipref start-msg
- (magit-git-string "commit-tree" "--no-gpg-sign"
- "-p" parent "-m" start-msg
- (concat parent "^{tree}")))
- (setq parent wipref))
- (magit-update-ref wipref msg
- (magit-git-string "commit-tree" "--no-gpg-sign"
- "-p" parent "-m" msg tree))))
-
-(defun magit-wip-get-ref ()
- (let ((ref (or (magit-git-string "symbolic-ref" "HEAD") "HEAD")))
- (when (magit-rev-verify ref)
- ref)))
-
-(defun magit-wip-get-parent (ref wipref)
- (if (and (magit-rev-verify wipref)
- (equal (magit-git-string "merge-base" wipref ref)
- (magit-rev-verify ref)))
- wipref
- ref))
-
-;;; Log
-
-(defun magit-wip-log-current (branch args files count)
- "Show log for the current branch and its wip refs.
-With a negative prefix argument only show the worktree wip ref.
-The absolute numeric value of the prefix argument controls how
-many \"branches\" of each wip ref are shown."
- (interactive
- (nconc (list (or (magit-get-current-branch) "HEAD"))
- (magit-log-arguments)
- (list (prefix-numeric-value current-prefix-arg))))
- (magit-wip-log branch args files count))
-
-(defun magit-wip-log (branch args files count)
- "Show log for a branch and its wip refs.
-With a negative prefix argument only show the worktree wip ref.
-The absolute numeric value of the prefix argument controls how
-many \"branches\" of each wip ref are shown."
- (interactive
- (nconc (list (magit-completing-read
- "Log branch and its wip refs"
- (-snoc (magit-list-local-branch-names) "HEAD")
- nil t nil 'magit-revision-history
- (or (magit-branch-at-point)
- (magit-get-current-branch)
- "HEAD")))
- (magit-log-arguments)
- (list (prefix-numeric-value current-prefix-arg))))
- (unless (equal branch "HEAD")
- (setq branch (concat "refs/heads/" branch)))
- (magit-log (nconc (list branch)
- (magit-wip-log-get-tips
- (concat magit-wip-namespace "wtree/" branch)
- (abs count))
- (and (>= count 0)
- (magit-wip-log-get-tips
- (concat magit-wip-namespace "index/" branch)
- (abs count))))
- args files))
-
-(defun magit-wip-log-get-tips (wipref count)
- (-when-let (reflog (magit-git-lines "reflog" wipref))
- (let (tips)
- (while (and reflog (> count 1))
- (setq reflog (cl-member "^[^ ]+ [^:]+: restart autosaving"
- reflog :test #'string-match-p))
- (when (and (cadr reflog)
- (string-match "^[^ ]+ \\([^:]+\\)" (cadr reflog)))
- (push (match-string 1 (cadr reflog)) tips))
- (setq reflog (cddr reflog))
- (cl-decf count))
- (cons wipref (nreverse tips)))))
-
-;;; magit-wip.el ends soon
-(provide 'magit-wip)
-;; Local Variables:
-;; indent-tabs-mode: nil
-;; End:
-;;; magit-wip.el ends here
+++ /dev/null
-;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2016 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Kyle Meyer <kyleNOSPAMkyleam.com>
-;; Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-;; Former-Maintainers:
-;; Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-;; Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-;; Phil Jackson <philNOSPAMshellarchive.co.uk>
-;; Rémi Vanicat <vanicat@debian.org>
-;; Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-
-;; Package-Requires: ((emacs "24.4") (async "20150909.2257") (dash "20151021.113") (with-editor "20160408.201") (git-commit "20160425.430") (magit-popup "20160512.328"))
-;; Keywords: git tools vc
-;; Homepage: https://github.com/magit/magit
-
-;; Magit requires at least GNU Emacs 24.4 and Git 1.9.4.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Magit is an interface to the version control system Git,
-;; implemented as an Emacs package. Magit aspires to be a complete
-;; Git porcelain. While we cannot (yet) claim, that Magit wraps and
-;; improves upon each and every Git command, it is complete enough to
-;; allow even experienced Git users to perform almost all of their
-;; daily version control tasks directly from within Emacs. While many
-;; fine Git clients exist, only Magit and Git itself deserve to be
-;; called porcelains.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'with-editor)
-(require 'git-commit)
-(require 'magit-core)
-(require 'magit-diff)
-(require 'magit-apply)
-(require 'magit-log)
-
-(require 'format-spec)
-(require 'package nil t) ; used in `magit-version'
-
-(eval-when-compile (require 'dired-x))
-(declare-function dired-jump 'dired-x)
-(eval-when-compile (require 'eshell))
-(declare-function eshell-parse-arguments 'eshell)
-(eval-when-compile (require 'message))
-(declare-function message-goto-body 'message)
-
-(defconst magit--minimal-git "1.9.4")
-(defconst magit--minimal-emacs "24.4")
-
-;;; Options
-;;;; Status Mode
-
-(defgroup magit-status nil
- "Inspect and manipulate Git repositories."
- :group 'magit-modes)
-
-(defcustom magit-status-mode-hook nil
- "Hook run after entering Magit-Status mode."
- :group 'magit-status
- :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)
- "Hook run to insert headers into the status buffer.
-
-This hook is run by `magit-insert-status-headers', which in turn
-has to be a member of `magit-status-sections-hook' to be used at
-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))
-
-(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-unpulled-from-upstream
- magit-insert-unpulled-from-pushremote
- magit-insert-unpushed-to-upstream
- magit-insert-unpushed-to-pushremote)
- "Hook run to insert sections into a status buffer."
- :package-version '(magit . "2.4.0")
- :group 'magit-status
- :type 'hook)
-
-(defvar magit-status-refresh-hook nil
- "Hook run after a status buffer has been refreshed.")
-
-(make-obsolete-variable 'magit-status-refresh-hook "\
-use `magit-pre-refresh-hook', `magit-post-refresh-hook',
- `magit-refresh-buffer-hook', or `magit-status-mode-hook' instead.
-
- If you want to run a function every time the status buffer is
- refreshed, in order to do something with that buffer, then use:
-
- (add-hook 'magit-refresh-buffer-hook
- (lambda ()
- (when (derived-mode-p 'magit-status-mode)
- ...)))
-
- If your hook function should run regardless of whether the
- status buffer exists or not, then use `magit-pre-refresh-hook'
- or `magit-post-refresh-hook'.
-
- If your hook function only has to be run once, when the buffer
- is first created, then `magit-status-mode-hook' instead.
-" "Magit 2.4.0")
-
-(defcustom magit-status-expand-stashes t
- "Whether the list of stashes is expanded initially."
- :package-version '(magit . "2.3.0")
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-status-show-hashes-in-headers nil
- "Whether headers in the status buffer show hashes.
-The functions which respect this option are
-`magit-insert-head-branch-header',
-`magit-insert-upstream-branch-header', and
-`magit-insert-push-branch-header'."
- :package-version '(magit . "2.4.0")
- :group 'magit-status
- :type 'boolean)
-
-;;;; Refs Mode
-
-(defgroup magit-refs nil
- "Inspect and manipulate Git branches and tags."
- :group 'magit-modes)
-
-(defcustom magit-refs-mode-hook nil
- "Hook run after entering Magit-Refs mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :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)
- "Hook run to insert sections into a references buffer."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :type 'hook)
-
-(defcustom magit-refs-show-commit-count nil
- "Whether to show commit counts in Magit-Refs mode buffers.
-
-all Show counts for branches and tags.
-branch Show counts for branches only.
-nil Never show counts.
-
-To change the value in an existing buffer use the command
-`magit-refs-show-commit-count'"
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :safe (lambda (val) (memq val '(all branch nil)))
- :type '(choice (const all :tag "For branches and tags")
- (const branch :tag "For branches only")
- (const nil :tag "Never")))
-(put 'magit-refs-show-commit-count 'safe-local-variable 'symbolp)
-(put 'magit-refs-show-commit-count 'permanent-local t)
-
-(defcustom magit-refs-show-margin 'branch
- "Whether to initially show the margin in refs buffers.
-
-When non-nil the committer name and date are initially displayed
-in the margin of refs buffers. The margin can be shown or hidden
-in the current buffer using the command `magit-toggle-margin'."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :safe (lambda (val) (memq val '(all branch nil)))
- :type '(choice (const all :tag "For branches and tags")
- (const branch :tag "For branches only")
- (const nil :tag "Never")))
-
-(defcustom magit-visit-ref-create nil
- "Whether `magit-visit-ref' may create new branches.
-
-When this is non-nil, then \"visiting\" a remote branch in a
-refs buffer works by creating a new local branch which tracks
-the remote branch and then checking out the new local branch."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :group 'magit-commands
- :type 'boolean)
-
-;;;; Miscellaneous
-
-(defcustom magit-branch-read-upstream-first t
- "When creating a branch, read upstream before name of new branch."
- :package-version '(magit . "2.2.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-branch-prefer-remote-upstream nil
- "Whether to favor remote upstreams when creating new branches.
-
-When a new branch is created, Magit offers the branch, commit, or
-stash as the default starting point of the new branch. If there
-is no such thing at point, then it falls back to offer the
-current branch as starting-point. The user may then accept that
-default or pick something else.
-
-If the chosen starting-point is a branch, then it may also be set
-as the upstream of the new branch, depending on the value of the
-Git variable `branch.autoSetupMerge'. By default this is done
-for remote branches, but not for local branches.
-
-You might prefer to always use some remote branch as upstream.
-If the chosen starting-point is (1) a local branch, (2) whose
-name is a member of the value of this option, (3) the upstream of
-that local branch is a remote branch with the same name, and (4)
-that remote branch can be fast-forwarded to the local branch,
-then the chosen branch is used as starting-point, but its own
-upstream is used as the upstream of the new branch.
-
-Assuming the chosen branch matches these conditions you would end
-up with with e.g.:
-
- feature --upstream--> origin/master
-
-instead of
-
- feature --upstream--> master --upstream--> origin/master
-
-Which you prefer is a matter of personal preference. If you do
-prefer the former, then you should add branches such as \"master\",
-\"next\", and \"maint\" to the value of this options."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(repeat string))
-
-(defcustom magit-branch-popup-show-variables t
- "Whether the `magit-branch-popup' shows Git variables.
-This defaults to t to avoid changing key bindings. When set to
-nil, no variables are displayed directly in this popup, instead
-the sub-popup `magit-branch-config-popup' has to be used to view
-and change branch related variables."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-repository-directories nil
- "Directories containing Git repositories.
-Magit checks these directories for Git repositories and offers
-them as choices when `magit-status' is used with a prefix
-argument."
- :group 'magit
- :type '(repeat string))
-
-(defcustom magit-repository-directories-depth 3
- "The maximum depth to look for Git repositories.
-When looking for a Git repository below the directories in
-`magit-repository-directories', only descend this many levels
-deep."
- :group 'magit
- :type 'integer)
-
-;;;; Faces
-
-(defface magit-header-line
- '((t :inherit magit-section-heading))
- "Face for the `header-line'."
- :group 'magit-faces)
-
-(defface magit-dimmed
- '((((class color) (background light)) :foreground "grey50")
- (((class color) (background dark)) :foreground "grey50"))
- "Face for text that shouldn't stand out."
- :group 'magit-faces)
-
-(defface magit-hash
- '((((class color) (background light)) :foreground "grey60")
- (((class color) (background dark)) :foreground "grey40"))
- "Face for the sha1 part of the log output."
- :group 'magit-faces)
-
-(defface magit-tag
- '((((class color) (background light)) :foreground "Goldenrod4")
- (((class color) (background dark)) :foreground "LightGoldenrod2"))
- "Face for tag labels shown in log buffer."
- :group 'magit-faces)
-
-(defface magit-branch-remote
- '((((class color) (background light)) :foreground "DarkOliveGreen4")
- (((class color) (background dark)) :foreground "DarkSeaGreen2"))
- "Face for remote branch head labels shown in log buffer."
- :group 'magit-faces)
-
-(defface magit-branch-local
- '((((class color) (background light)) :foreground "SkyBlue4")
- (((class color) (background dark)) :foreground "LightSkyBlue1"))
- "Face for local branches."
- :group 'magit-faces)
-
-(defface magit-branch-current
- '((((class color) (background light)) :inherit magit-branch-local :box t)
- (((class color) (background dark)) :inherit magit-branch-local :box t))
- "Face for current branch."
- :group 'magit-faces)
-
-(defface magit-head
- '((((class color) (background light)) :inherit magit-branch-local)
- (((class color) (background dark)) :inherit magit-branch-local))
- "Face for the symbolic ref \"HEAD\"."
- :group 'magit-faces)
-
-(defface magit-refname
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for refnames without a dedicated face."
- :group 'magit-faces)
-
-(defface magit-refname-stash
- '((t :inherit magit-refname))
- "Face for wip refnames."
- :group 'magit-faces)
-
-(defface magit-refname-wip
- '((t :inherit magit-refname))
- "Face for wip refnames."
- :group 'magit-faces)
-
-(defface magit-signature-good
- '((t :foreground "green"))
- "Face for good signatures."
- :group 'magit-faces)
-
-(defface magit-signature-bad
- '((t :foreground "red"))
- "Face for bad signatures."
- :group 'magit-faces)
-
-(defface magit-signature-untrusted
- '((t :foreground "cyan"))
- "Face for good untrusted signatures."
- :group 'magit-faces)
-
-(defface magit-cherry-unmatched
- '((t :foreground "cyan"))
- "Face for unmatched cherry commits."
- :group 'magit-faces)
-
-(defface magit-cherry-equivalent
- '((t :foreground "magenta"))
- "Face for equivalent cherry commits."
- :group 'magit-faces)
-
-(defface magit-filename
- '((t :weight normal))
- "Face for filenames."
- :group 'magit-faces)
-
-;;; Inspect
-;;;; Status Mode
-;;;;; Status Core
-
-(defvar magit-status-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "jz" 'magit-jump-to-stashes)
- (define-key map "jt" 'magit-jump-to-tracked)
- (define-key map "jn" 'magit-jump-to-untracked)
- (define-key map "ju" 'magit-jump-to-unstaged)
- (define-key map "js" 'magit-jump-to-staged)
- (define-key map "jfu" 'magit-jump-to-unpulled-from-upstream)
- (define-key map "jfp" 'magit-jump-to-unpulled-from-pushremote)
- (define-key map "jpu" 'magit-jump-to-unpushed-to-upstream)
- (define-key map "jpp" 'magit-jump-to-unpushed-to-pushremote)
- map)
- "Keymap for `magit-status-mode'.")
-
-(eval-after-load 'dired-x
- '(define-key magit-status-mode-map [remap dired-jump] 'magit-dired-jump))
-
-(define-derived-mode magit-status-mode magit-mode "Magit"
- "Mode for looking at Git status.
-
-This mode is documented in info node `(magit)Status buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] to visit the change or commit at point.
-
-Type \\[magit-dispatch-popup] to see available prefix popups.
-
-Staging and applying changes is documented in info node
-`(magit)Staging and unstaging' and info node `(magit)Applying'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\<magit-status-mode-map>\
-Type \\[magit-commit-popup] to create a commit.
-
-\\{magit-status-mode-map}"
- :group 'magit-status
- (hack-dir-local-variables-non-file-buffer))
-
-;;;###autoload
-(defun magit-status (&optional directory)
- "Show the status of the current Git repository in a buffer.
-With a prefix argument prompt for a repository to be shown.
-With two prefix arguments prompt for an arbitrary directory.
-If that directory isn't the root of an existing repository
-then offer to initialize it as a new repository."
- (interactive
- (list (and (or current-prefix-arg (not (magit-toplevel)))
- (magit-read-repository
- (>= (prefix-numeric-value current-prefix-arg) 16)))))
- (if directory
- (let ((toplevel (magit-toplevel directory)))
- (setq directory (file-name-as-directory (expand-file-name directory)))
- (if (and toplevel (string-equal directory toplevel))
- (magit-status-internal directory)
- (when (y-or-n-p
- (if toplevel
- (format "%s is a repository. Create another in %s? "
- toplevel directory)
- (format "Create repository in %s? " directory)))
- (magit-init directory))))
- (magit-status-internal default-directory)))
-
-(put 'magit-status 'interactive-only 'magit-status-internal)
-
-;;;###autoload
-(defun magit-status-internal (directory)
- (magit-tramp-asserts directory)
- (let ((default-directory directory))
- (magit-mode-setup #'magit-status-mode)))
-
-;;;;; Standard Status Sections
-
-(defvar magit-status-sections-hook-1 nil)
-
-(defun magit-status-refresh-buffer ()
- (magit-git-exit-code "update-index" "--refresh")
- (magit-insert-section (status)
- (if (-all-p #'functionp magit-status-sections-hook)
- (run-hooks 'magit-status-sections-hook)
- (message "`magit-status-sections-hook' contains entries that are \
-no longer valid.\nUsing standard value instead. Please re-configure")
- (sit-for 5)
- (let ((magit-status-sections-hook-1
- (eval (car (get 'magit-status-sections-hook 'standard-value)))))
- (run-hooks 'magit-status-sections-hook-1))))
- (run-hooks 'magit-status-refresh-hook))
-
-(defun magit-insert-status-headers ()
- "Insert header sections appropriate for `magit-status-mode' buffers.
-The sections are inserted by running the functions on the hook
-`magit-status-headers-hook'."
- (if (magit-rev-verify "HEAD")
- (magit-insert-headers magit-status-headers-hook)
- (insert "In the beginning there was darkness\n\n")))
-
-(defun magit-insert-error-header ()
- "Insert the message about the Git error that just occured.
-
-This function is only aware of the last error that occur when Git
-was run for side-effects. If, for example, an error occurs while
-generating a diff, then that error won't be inserted. Refreshing
-the status buffer causes this section to disappear again."
- (when magit-this-error
- (magit-insert-section (error 'git)
- (insert (propertize (format "%-10s" "GitError! ")
- 'face 'magit-section-heading))
- (insert (propertize magit-this-error 'face 'font-lock-warning-face))
- (-when-let (key (car (where-is-internal 'magit-process-buffer)))
- (insert (format " [Type `%s' for details]" (key-description key))))
- (insert ?\n))
- (setq magit-this-error nil)))
-
-(cl-defun magit-insert-head-branch-header
- (&optional (branch (magit-get-current-branch)))
- "Insert a header line about BRANCH.
-When BRANCH is nil, use the current branch or, if none, the
-detached `HEAD'."
- (let ((output (magit-rev-format "%h %s" (or branch "HEAD"))))
- (string-match "^\\([^ ]+\\) \\(.*\\)" output)
- (magit-bind-match-strings (commit summary) output
- (if branch
- (magit-insert-section (branch branch)
- (insert (format "%-10s" "Head: "))
- (when magit-status-show-hashes-in-headers
- (insert (propertize commit 'face 'magit-hash) ?\s))
- (insert (propertize branch 'face 'magit-branch-local))
- (insert ?\s summary ?\n))
- (magit-insert-section (commit commit)
- (insert (format "%-10s" "Head: "))
- (insert (propertize commit 'face 'magit-hash))
- (insert ?\s summary ?\n))))))
-
-(cl-defun magit-insert-upstream-branch-header
- (&optional (branch (magit-get-current-branch))
- (pull (magit-get-upstream-branch branch))
- keyword)
- "Insert a header line about branch usually pulled into current branch."
- (when pull
- (magit-insert-section (branch pull)
- (insert (format "%-10s"
- (or keyword
- (if (magit-get-boolean "branch" branch "rebase")
- "Rebase: "
- "Merge: "))))
- (--when-let (and magit-status-show-hashes-in-headers
- (magit-rev-format "%h" pull))
- (insert (propertize it 'face 'magit-hash) ?\s))
- (insert (propertize pull 'face
- (if (string= (magit-get "branch" branch "remote") ".")
- 'magit-branch-local
- 'magit-branch-remote)))
- (insert ?\s)
- (if (magit-rev-verify pull)
- (insert (or (magit-rev-format "%s" pull) ""))
- (insert (propertize "is missing" 'face 'font-lock-warning-face)))
- (insert ?\n))))
-
-(cl-defun magit-insert-push-branch-header
- (&optional (branch (magit-get-current-branch))
- (push (magit-get-push-branch branch)))
- "Insert a header line about the branch the current branch is pushed to."
- (when push
- (magit-insert-section (branch push)
- (insert (format "%-10s" "Push: "))
- (--when-let (and magit-status-show-hashes-in-headers
- (magit-rev-format "%h" push))
- (insert (propertize it 'face 'magit-hash) ?\s))
- (insert (propertize push 'face 'magit-branch-remote) ?\s)
- (if (magit-rev-verify push)
- (insert (or (magit-rev-format "%s" push) ""))
- (insert (propertize "is missing" 'face 'font-lock-warning-face)))
- (insert ?\n))))
-
-(defun magit-insert-tags-header ()
- "Insert a header line about the current and/or next tag."
- (let* ((this-tag (magit-get-current-tag nil t))
- (next-tag (magit-get-next-tag nil t))
- (this-cnt (cadr this-tag))
- (next-cnt (cadr next-tag))
- (this-tag (car this-tag))
- (next-tag (car next-tag))
- (both-tags (and this-tag next-tag t)))
- (when (or this-tag next-tag)
- (magit-insert-section (tag (or this-tag next-tag))
- (insert (format "%-10s" (if both-tags "Tags: " "Tag: ")))
- (when this-tag
- (insert (magit-format-status-tag-sentence this-tag this-cnt nil)))
- (when both-tags
- (insert ", "))
- (when next-tag
- (insert (magit-format-status-tag-sentence next-tag next-cnt t)))
- (insert ?\n)))))
-
-(defun magit-format-status-tag-sentence (tag count next)
- (concat (propertize tag 'face 'magit-tag)
- (and (> count 0)
- (format " (%s)"
- (propertize (format "%s" count) 'face
- (if next 'magit-tag 'magit-branch-local))))))
-
-(defun magit-insert-diff-filter-header ()
- "Insert a header line showing the effective diff filters."
- (when magit-diff-section-file-args
- (magit-insert-section (filter 'diff)
- (insert (propertize (format "%-10s" "Filter! ")
- 'face 'magit-section-heading))
- (insert (mapconcat #'identity magit-diff-section-file-args " "))
- (insert ?\n))))
-
-(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked)
-
-(defvar magit-untracked-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map "s" 'magit-stage)
- map)
- "Keymap for the `untracked' section.")
-
-(defun magit-insert-untracked-files ()
- "Maybe insert a list or tree of untracked files.
-Do so depending on the value of `status.showUntrackedFiles'."
- (let ((show (or (magit-get "status.showUntrackedFiles") "normal")))
- (unless (equal show "no")
- (if (equal show "all")
- (-when-let (files (magit-untracked-files))
- (magit-insert-section (untracked)
- (magit-insert-heading "Untracked files:")
- (magit-insert-un/tracked-files-1 files nil)
- (insert ?\n)))
- (-when-let
- (files (--mapcat (and (eq (aref it 0) ??)
- (list (substring it 3)))
- (magit-git-items "status" "-z" "--porcelain")))
- (magit-insert-section (untracked)
- (magit-insert-heading "Untracked files:")
- (dolist (file files)
- (magit-insert-section (file file)
- (insert (propertize file 'face 'magit-filename) ?\n)))
- (insert ?\n)))))))
-
-(defun magit-insert-un/tracked-files-1 (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 'face 'magit-filename) ?\n)))
- (magit-insert-section (file dir t)
- (insert (propertize dir 'file 'magit-filename) ?\n)
- (magit-insert-heading)
- (setq files (magit-insert-un/tracked-files-1 files dir))))))
- files)
-
-;;;;; Auxiliary Status Sections
-
-(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked)
-
-(defun magit-insert-tracked-files ()
- "Insert a tree of tracked files."
- (-when-let (files (magit-list-files))
- (magit-insert-section (tracked nil t)
- (magit-insert-heading "Tracked files:")
- (magit-insert-un/tracked-files-1 files nil)
- (insert ?\n))))
-
-(defun magit-insert-user-header ()
- "Insert a header line about the current user."
- (let ((name (magit-get "user.name"))
- (email (magit-get "user.email")))
- (when (and name email)
- (magit-insert-section (user name)
- (insert (format "%-10s" "User: "))
- (insert (propertize name 'face 'magit-log-author))
- (insert " <" email ">\n")))))
-
-(defun magit-insert-repo-header ()
- "Insert a header line showing the path to the repository top-level."
- (let ((topdir (magit-toplevel)))
- (magit-insert-section (repo topdir)
- (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir))))))
-
-(defun magit-insert-remote-header ()
- "Insert a header line about the remote of the current branch.
-
-If no remote is configured for the current branch, then fall back
-showing the \"origin\" remote, or if that does not exist the first
-remote in alphabetic order."
- (--when-let (or (magit-get-remote)
- (let ((remotes (magit-list-remotes)))
- (or (car (member "origin" remotes))
- (car remotes))))
- (magit-insert-section (remote it)
- (insert (format "%-10s" "Remote: "))
- (insert (propertize it 'face 'magit-branch-remote) ?\s)
- (insert (magit-get "remote" it "url") ?\n))))
-
-;;;;; Status Miscellaneous
-
-(defun ido-enter-magit-status ()
- "Drop into `magit-status' from file switching.
-
-To make this command available use something like:
-
- (add-hook \\='ido-setup-hook
- (lambda ()
- (define-key ido-completion-map
- (kbd \"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:
-
- (define-key ido-common-completion-map
- (kbd \"C-x g\") 'ido-enter-magit-status)"
- (interactive)
- (with-no-warnings ; FIXME these are internal variables
- (setq ido-exit 'fallback fallback 'magit-status))
- (exit-minibuffer))
-
-(defun magit-status-maybe-update-revision-buffer (&optional _)
- "When moving in the status buffer, update the revision buffer.
-If there is no revision buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-status-mode)
- (magit-log-maybe-update-revision-buffer-1)))
-
-(defun magit-status-maybe-update-blob-buffer (&optional _)
- "When moving in the status buffer, update the blob buffer.
-If there is no blob buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-status-mode)
- (magit-log-maybe-update-blob-buffer-1)))
-
-;;;; Refs Mode
-
-(defvar magit-refs-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-y" 'magit-refs-set-show-commit-count)
- map)
- "Keymap for `magit-refs-mode'.")
-
-(define-derived-mode magit-refs-mode magit-mode "Magit Refs"
- "Mode which lists and compares references.
-
-This mode is documented in info node `(magit)References buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit or branch at point.
-
-Type \\[magit-branch-popup] to see available branch commands.
-Type \\[magit-merge-popup] to merge the branch or commit at point.
-Type \\[magit-cherry-pick-popup] to apply the commit at point.
-Type \\[magit-reset] to reset HEAD to the commit at point.
-
-\\{magit-refs-mode-map}"
- :group 'magit-refs
- (hack-dir-local-variables-non-file-buffer))
-
-;;;###autoload (autoload 'magit-show-refs-popup "magit" nil t)
-(magit-define-popup magit-show-refs-popup
- "Popup console for `magit-show-refs'."
- 'magit-refs
- :man-page "git-branch"
- :switches '((?m "Merged to HEAD" "--merged")
- (?M "Merged to master" "--merged=master")
- (?n "Not merged to HEAD" "--no-merged")
- (?N "Not merged to master" "--no-merged=master"))
- :options '((?c "Contains" "--contains=" magit-read-branch-or-commit)
- (?m "Merged" "--merged=" magit-read-branch-or-commit)
- (?n "Not merged" "--no-merged=" magit-read-branch-or-commit))
- :actions '((?y "Show refs, comparing them with HEAD"
- magit-show-refs-head)
- (?c "Show refs, comparing them with current branch"
- magit-show-refs-current)
- (?o "Show refs, comparing them with other branch"
- magit-show-refs))
- :default-action 'magit-show-refs-head
- :use-prefix 'popup)
-
-;;;###autoload
-(defun magit-show-refs-head (&optional args)
- "List and compare references in a dedicated buffer.
-Refs are compared with `HEAD'."
- (interactive (list (magit-show-refs-arguments)))
- (magit-show-refs nil args))
-
-;;;###autoload
-(defun magit-show-refs-current (&optional args)
- "List and compare references in a dedicated buffer.
-Refs are compared with the current branch or `HEAD' if
-it is detached."
- (interactive (list (magit-show-refs-arguments)))
- (magit-show-refs (magit-get-current-branch) args))
-
-;;;###autoload
-(defun magit-show-refs (&optional ref args)
- "List and compare references in a dedicated buffer.
-Refs are compared with a branch read form the user."
- (interactive (list (magit-read-other-branch "Compare with")
- (magit-show-refs-arguments)))
- (magit-mode-setup #'magit-refs-mode ref args))
-
-(defun magit-refs-refresh-buffer (&rest _ignore)
- (setq magit-set-buffer-margin-refresh (not magit-show-margin))
- (unless (magit-rev-verify (or (car magit-refresh-args) "HEAD"))
- (setq magit-refs-show-commit-count nil))
- (magit-insert-section (branchbuf)
- (run-hooks 'magit-refs-sections-hook)))
-
-(defun magit-insert-branch-description ()
- "Insert header containing the description of the current branch.
-Insert a header line with the name and description of the
-current branch. The description is taken from the Git variable
-`branch.<NAME>.description'; if that is undefined then no header
-line is inserted at all."
- (let ((branch (magit-get-current-branch)))
- (--when-let (magit-git-lines
- "config" (format "branch.%s.description" branch))
- (magit-insert-section (branchdesc branch t)
- (magit-insert-heading branch ": " (car it))
- (insert (mapconcat 'identity (cdr it) "\n"))
- (insert "\n\n")))))
-
-(defconst magit-refs-branch-line-re
- (concat "^"
- "\\(?:[ \\*]\\) "
- "\\(?1:([^)]+)\\|[^ ]+?\\)" ; branch
- "\\(?: +\\)"
- "\\(?2:[0-9a-fA-F]+\\) " ; sha1
- "\\(?:\\["
- "\\(?4:[^:]+\\)" ; upstream
- "\\(?:: \\(?:"
- "\\(?7:gone\\)\\|" ; gone
- "\\(?:ahead \\(?5:[0-9]+\\)\\)?" ; ahead
- "\\(?:, \\)?"
- "\\(?:behind \\(?6:[0-9]+\\)\\)?" ; behind
- "\\)\\)?"
- "\\] \\)?"
- "\\(?3:.*\\)")) ; message
-
-(defconst magit-refs-symref-line-re "^ \\([^ ]+\\) +-> \\(.+\\)")
-
-(defvar magit-refs-local-branch-format "%4c %-25n %U%m\n"
- "Format used for local branches in refs buffers.")
-(defvar magit-refs-remote-branch-format "%4c %-25n %m\n"
- "Format used for remote branches in refs buffers.")
-(defvar magit-refs-symref-format "%4c %-25n -> %m\n"
- "Format used for symrefs in refs buffers.")
-(defvar magit-refs-tags-format "%4c %-25n %m\n"
- "Format used for tags in refs buffers.")
-(defvar magit-refs-indent-cherry-lines 3
- "Indentation of cherries in refs buffers.")
-
-(defvar magit-branch-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-visit-ref)
- (define-key map [remap magit-delete-thing] 'magit-branch-delete)
- (define-key map "R" 'magit-branch-rename)
- map)
- "Keymap for `branch' sections.")
-
-(defvar magit-remote-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-remote-remove)
- (define-key map "R" 'magit-remote-rename)
- map)
- "Keymap for `remote' sections.")
-
-(defun magit-refs-set-show-commit-count ()
- "Change for which refs the commit count is shown."
- (interactive)
- (setq-local magit-refs-show-commit-count
- (magit-read-char-case "Show commit counts for " nil
- (?a "[a]ll refs" 'all)
- (?b "[b]ranches only" t)
- (?n "[n]othing" nil)))
- (magit-refresh))
-
-(defun magit-visit-ref ()
- "Visit the reference or revision at point.
-
-In most places use `magit-show-commit' to visit the reference or
-revision at point.
-
-In `magit-refs-mode', when there is a reference at point, instead
-checkout that reference. When option `magit-visit-ref-create' is
-non-nil and point is on remote branch, then create a local branch
-with the same name and check it out.
-
-With a prefix argument only focus on the reference at point, i.e.
-the commit counts and cherries are updated to be relative to that
-reference, but it is not checked out."
- (interactive)
- (if (derived-mode-p 'magit-refs-mode)
- (magit-section-case
- (([branch * branchbuf]
- [tag * branchbuf])
- (let ((ref (magit-section-value (magit-current-section))))
- (if current-prefix-arg
- (magit-show-refs ref)
- (if (magit-section-when [branch remote])
- (let ((start ref)
- (arg "-b"))
- (string-match "^[^/]+/\\(.+\\)" ref)
- (setq ref (match-string 1 ref))
- (when (magit-branch-p ref)
- (if (yes-or-no-p
- (format "Branch %s already exists. Recreate it?" ref))
- (setq arg "-B")
- (user-error "Abort")))
- (magit-run-git "checkout" arg ref start))
- (magit-run-git "checkout" ref))
- (setcar magit-refresh-args ref)
- (magit-refresh))))
- ([commit * branchbuf]
- (call-interactively #'magit-show-commit)))
- (call-interactively #'magit-show-commit)))
-
-(defun magit-insert-local-branches ()
- "Insert sections showing all local branches."
- (magit-insert-section (local nil)
- (magit-insert-heading "Branches:")
- (let ((current (magit-get-current-branch))
- (branches (magit-list-local-branch-names)))
- (dolist (line (magit-git-lines "branch" "-vv"
- (cadr magit-refresh-args)))
- (cond
- ((string-match magit-refs-branch-line-re line)
- (magit-bind-match-strings
- (branch hash message upstream ahead behind gone) line
- (when (string-match-p "(HEAD detached" branch)
- (setq branch nil))
- (magit-insert-branch
- branch magit-refs-local-branch-format current branches
- 'magit-branch-local hash message upstream ahead behind gone)))
- ((string-match magit-refs-symref-line-re line)
- (magit-bind-match-strings (symref ref) line
- (magit-insert-symref symref ref 'magit-branch-local))))))
- (insert ?\n)))
-
-(defun magit-insert-remote-branches ()
- "Insert sections showing all remote-tracking branches."
- (dolist (remote (magit-list-remotes))
- (magit-insert-section (remote remote)
- (magit-insert-heading
- (let ((pull (magit-get "remote" remote "url"))
- (push (magit-get "remote" remote "pushurl")))
- (format "%s (%s):" (capitalize remote)
- (concat pull (and pull push ", ") push))))
- (let ((current (magit-get-current-branch))
- (branches (magit-list-local-branch-names)))
- (dolist (line (magit-git-lines "branch" "-vvr"
- (cadr magit-refresh-args)))
- (cond
- ((string-match magit-refs-branch-line-re line)
- (magit-bind-match-strings (branch hash message) line
- (when (string-match-p (format "^%s/" remote) branch)
- (magit-insert-branch
- branch magit-refs-remote-branch-format current branches
- 'magit-branch-remote hash message))))
- ((string-match magit-refs-symref-line-re line)
- (magit-bind-match-strings (symref ref) line
- (magit-insert-symref symref ref 'magit-branch-remote))))))
- (insert ?\n))))
-
-(defun magit-insert-branch (branch format &rest args)
- "For internal use, don't add to a hook."
- (unless magit-refs-show-commit-count
- (setq format (replace-regexp-in-string "%[0-9]\\([cC]\\)" "%1\\1" format t)))
- (if (equal branch "HEAD")
- (magit-insert-section it (commit (magit-rev-parse "HEAD") t)
- (apply #'magit-insert-branch-1 it nil format args))
- (magit-insert-section it (branch branch t)
- (apply #'magit-insert-branch-1 it branch format args))))
-
-(defun magit-insert-branch-1
- (section branch format current branches face
- &optional hash message upstream ahead behind gone)
- "For internal use, don't add to a hook."
- (let* ((head (or (car magit-refresh-args) current "HEAD"))
- (count (and branch
- (magit-refs-format-commit-count branch head format)))
- (mark (cond ((or (equal branch head)
- (and (not branch) (equal head "HEAD")))
- (if (equal branch current)
- (propertize "@" 'face 'magit-head)
- (propertize "#" 'face 'magit-tag)))
- ((equal branch current)
- (propertize "." 'face 'magit-head)))))
- (when upstream
- (setq upstream (propertize upstream 'face
- (if (member upstream branches)
- 'magit-branch-local
- 'magit-branch-remote))))
- (magit-insert-heading
- (format-spec
- format
- `((?a . ,(or ahead ""))
- (?b . ,(or behind ""))
- (?c . ,(or mark count ""))
- (?C . ,(or mark " "))
- (?h . ,(or (propertize hash 'face 'magit-hash) ""))
- (?m . ,(or message ""))
- (?n . ,(propertize (or branch "(detached)") 'face face))
- (?u . ,(or upstream ""))
- (?U . ,(if upstream
- (format (propertize "[%s%s] " 'face 'magit-dimmed)
- upstream
- (cond
- (gone
- (concat ": " (propertize gone 'face 'error)))
- ((or ahead behind)
- (concat ": "
- (and ahead (format "ahead %s" ahead))
- (and ahead behind ", ")
- (and behind (format "behind %s" behind))))
- (t "")))
- "")))))
- (when magit-show-margin
- (magit-refs-format-margin branch))
- (magit-refs-insert-cherry-commits head branch section)))
-
-(defun magit-insert-symref (symref ref face)
- "For internal use, don't add to a hook."
- (magit-insert-section (commit symref)
- (insert
- (format-spec (if magit-refs-show-commit-count
- magit-refs-symref-format
- (replace-regexp-in-string "%[0-9]\\([cC]\\)" "%1\\1"
- magit-refs-symref-format t))
- `((?c . "")
- (?n . ,(propertize symref 'face face))
- (?m . ,(propertize ref 'face face)))))))
-
-(defvar magit-tag-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-visit-ref)
- (define-key map [remap magit-delete-thing] 'magit-tag-delete)
- map)
- "Keymap for `tag' sections.")
-
-(defun magit-insert-tags ()
- "Insert sections showing all tags."
- (-when-let (tags (magit-git-lines "tag" "-l" "-n"))
- (magit-insert-section (tags)
- (magit-insert-heading "Tags:")
- (let ((head (or (car magit-refresh-args)
- (magit-get-current-branch)
- "HEAD"))
- (format (if magit-refs-show-commit-count
- magit-refs-tags-format
- (replace-regexp-in-string
- "%[0-9]\\([cC]\\)" "%1\\1" magit-refs-tags-format t))))
- (dolist (tag (nreverse tags))
- (string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag)
- (let* ((message (match-string 2 tag))
- (tag (match-string 1 tag))
- (count (magit-refs-format-commit-count tag head format t))
- (mark (and (equal tag head)
- (propertize "#" 'face 'magit-tag))))
- (magit-insert-section section (tag tag t)
- (magit-insert-heading
- (format-spec format
- `((?n . ,(propertize tag 'face 'magit-tag))
- (?c . ,(or mark count ""))
- (?m . ,(or message "")))))
- (when (and magit-show-margin
- (eq magit-refs-show-margin 'all))
- (magit-refs-format-margin (concat tag "^{commit}")))
- (magit-refs-insert-cherry-commits head tag section)))))
- (insert ?\n))))
-
-(defun magit-refs-insert-cherry-commits (head ref section)
- (if (magit-section-hidden section)
- (setf (magit-section-washer section)
- (apply-partially #'magit-refs-insert-cherry-commits-1
- head ref section))
- (magit-refs-insert-cherry-commits-1 head ref section)))
-
-(defun magit-refs-insert-cherry-commits-1 (head ref section)
- (let ((start (point)))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" "--abbrev" head ref magit-refresh-args)
- (unless (= (point) start)
- (insert (propertize "\n" 'magit-section section)))))
-
-(defun magit-refs-format-commit-count (ref head format &optional tag-p)
- (and (string-match-p "%-?[0-9]+c" format)
- (if tag-p
- (eq magit-refs-show-commit-count 'all)
- magit-refs-show-commit-count)
- (let ((count (cadr (magit-rev-diff-count head ref))))
- (and (> count 0)
- (propertize (number-to-string count) 'face 'magit-dimmed)))))
-
-(defun magit-refs-format-margin (commit)
- (save-excursion
- (goto-char (line-beginning-position 0))
- (let ((line (magit-rev-format "%ct%cN" commit)))
- (magit-format-log-margin (substring line 10)
- (substring line 0 10)))))
-
-;;;; Files
-
-;;;###autoload
-(defun magit-find-file (rev file)
- "View FILE from REV.
-Switch to a buffer visiting blob REV:FILE,
-creating one if none already exists."
- (interactive (magit-find-file-read-args "Find file"))
- (switch-to-buffer (magit-find-file-noselect rev file)))
-
-;;;###autoload
-(defun magit-find-file-other-window (rev file)
- "View FILE from REV, in another window.
-Like `magit-find-file', but create a new window or reuse an
-existing one."
- (interactive (magit-find-file-read-args "Find file in other window"))
- (switch-to-buffer-other-window (magit-find-file-noselect rev file)))
-
-(defun magit-find-file-read-args (prompt)
- (let ((rev (magit-read-branch-or-commit "Find file from revision")))
- (list rev (magit-read-file-from-rev rev prompt))))
-
-(defvar magit-read-file-hist nil)
-
-(defun magit-read-file-from-rev (rev prompt &optional default)
- (let ((files (magit-revision-files rev)))
- (magit-completing-read
- prompt files nil t nil 'magit-read-file-hist
- (car (member (or default (magit-current-file)) files)))))
-
-(defun magit-read-changed-file (rev-or-range prompt &optional default)
- (magit-read-file-choice
- prompt
- (magit-changed-files rev-or-range)
- default
- (concat "No file changed in " rev-or-range)))
-
-(defun magit-get-revision-buffer (rev file &optional create)
- (funcall (if create 'get-buffer-create 'get-buffer)
- (format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev))))
-
-(defun magit-get-revision-buffer-create (rev file)
- (magit-get-revision-buffer rev file t))
-
-(defvar magit-find-file-hook nil)
-
-(defun magit-find-file-noselect (rev file)
- "Read FILE from REV into a buffer and return the buffer.
-FILE must be relative to the top directory of the repository."
- (let ((topdir (magit-toplevel)))
- (when (file-name-absolute-p file)
- (setq file (file-relative-name file topdir)))
- (or (magit-get-revision-buffer rev file)
- (with-current-buffer (magit-get-revision-buffer-create rev file)
- (let ((inhibit-read-only t))
- (erase-buffer)
- (magit-git-insert "cat-file" "-p" (concat rev ":" file)))
- (setq magit-buffer-revision (magit-rev-format "%H" rev)
- magit-buffer-refname rev
- magit-buffer-file-name (expand-file-name file topdir))
- (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)))
- (normal-mode t))
- (setq buffer-read-only t)
- (set-buffer-modified-p nil)
- (goto-char (point-min))
- (magit-blob-mode 1)
- (run-hooks 'magit-find-file-hook)
- (current-buffer)))))
-
-(defvar magit-find-index-hook nil)
-
-(defun magit-find-file-index-noselect (file &optional revert)
- "Read FILE from the index into a buffer and return the buffer.
-FILE must to be relative to the top directory of the repository."
- (let* ((bufname (concat file ".~{index}~"))
- (origbuf (get-buffer bufname))
- (default-directory (magit-toplevel)))
- (with-current-buffer (get-buffer-create bufname)
- (when (or (not origbuf) revert
- (y-or-n-p (format "%s already exists; revert it? " bufname)))
- (let ((inhibit-read-only t)
- (temp (car (split-string
- (or (magit-git-string "checkout-index" "--temp" file)
- (error "Error making temp file"))
- "\t"))))
- (erase-buffer)
- (insert-file-contents temp nil nil nil t)
- (delete-file temp)))
- (setq magit-buffer-revision "{index}"
- magit-buffer-refname "{index}"
- magit-buffer-file-name (expand-file-name file))
- (let ((buffer-file-name magit-buffer-file-name))
- (normal-mode t))
- (setq buffer-read-only t)
- (set-buffer-modified-p nil)
- (goto-char (point-min))
- (run-hooks 'magit-find-index-hook)
- (current-buffer))))
-
-(defun magit-update-index ()
- "Update the index with the contents of the current buffer.
-The current buffer has to be visiting a file in the index, which
-is done using `magit-find-index-noselect'."
- (interactive)
- (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)))
- (let ((index (make-temp-file "index"))
- (buffer (current-buffer)))
- (when magit-wip-before-change-mode
- (magit-wip-commit-before-change (list file) " before un-/stage"))
- (with-temp-file index
- (insert-buffer-substring buffer))
- (magit-call-git "update-index" "--cacheinfo"
- (substring (magit-git-string "ls-files" "-s" file) 0 6)
- (magit-git-string "hash-object" "-t" "blob" "-w"
- (concat "--path=" file)
- "--" index)
- file)
- (set-buffer-modified-p nil)
- (when magit-wip-after-apply-mode
- (magit-wip-commit-after-apply (list file) " after un-/stage")))
- (message "Abort")))
- (--when-let (magit-mode-get-buffer 'magit-status-mode)
- (with-current-buffer it (magit-refresh)))
- t)
-
-;;;###autoload
-(defun magit-dired-jump (&optional other-window)
- "Visit file at point using Dired.
-With a prefix argument, visit in other window. If there
-is no file at point then instead visit `default-directory'."
- (interactive "P")
- (dired-jump other-window (--if-let (magit-file-at-point)
- (expand-file-name it)
- default-directory)))
-
-;;;###autoload
-(defun magit-checkout-file (rev file)
- "Checkout FILE from REV."
- (interactive
- (let ((rev (magit-read-branch-or-commit
- "Checkout from revision" magit-buffer-revision)))
- (list rev (magit-read-file-from-rev rev "Checkout file"))))
- (magit-with-toplevel
- (magit-run-git "checkout" rev "--" file)))
-
-;;; Manipulate
-;;;; Init
-
-;;;###autoload
-(defun magit-init (directory)
- "Initialize a Git repository, then show its status.
-
-If the directory is below an existing repository, then the user
-has to confirm that a new one should be created inside. If the
-directory is the root of the existing repository, then the user
-has to confirm that it should be reinitialized.
-
-Non-interactively DIRECTORY is (re-)initialized unconditionally."
- (interactive
- (let ((directory (file-name-as-directory
- (expand-file-name
- (read-directory-name "Create repository in: ")))))
- (-when-let (toplevel (magit-toplevel directory))
- (setq toplevel (expand-file-name toplevel))
- (unless (y-or-n-p (if (string-equal toplevel directory)
- (format "Reinitialize existing repository %s? "
- directory)
- (format "%s is a repository. Create another in %s? "
- toplevel directory)))
- (user-error "Abort")))
- (list directory)))
- ;; `git init' does not understand the meaning of "~"!
- (magit-call-git "init" (magit-convert-git-filename
- (expand-file-name directory)))
- (magit-status-internal directory))
-
-;;;; Branch
-;;;;; Branch Popup
-
-;;;###autoload (autoload 'magit-branch-popup "magit" nil t)
-(magit-define-popup magit-branch-popup
- "Popup console for branch commands."
- 'magit-commands
- :man-page "git-branch"
- :actions '((?b "Checkout" magit-checkout)
- (?n "Create new branch" magit-branch)
- (?C "Configure..." magit-branch-config-popup)
- (?c "Checkout new branch" magit-branch-and-checkout)
- (?s "Create new spin-off" magit-branch-spinoff)
- (?m "Rename" magit-branch-rename)
- (?w "Checkout new worktree" magit-worktree-checkout)
- (?W "Create new worktree" magit-worktree-branch)
- (?x "Reset" magit-branch-reset) nil nil
- (?k "Delete" magit-branch-delete))
- :default-action 'magit-checkout
- :max-action-columns 3
- :setup-function 'magit-branch-popup-setup)
-
-(defvar magit-branch-config-variables)
-
-(defun magit-branch-popup-setup (val def)
- (magit-popup-default-setup val def)
- (when magit-branch-popup-show-variables
- (magit-popup-put :variables (magit-popup-convert-variables
- val magit-branch-config-variables))))
-
-;;;###autoload
-(defun magit-checkout (revision)
- "Checkout REVISION, updating the index and the working tree.
-If REVISION is a local branch then that becomes the current
-branch. If it is something else then `HEAD' becomes detached.
-Checkout fails if the working tree or the staging area contain
-changes.
-\n(git checkout REVISION)."
- (interactive (list (magit-read-other-branch-or-commit "Checkout")))
- (magit-run-git "checkout" revision))
-
-;;;###autoload
-(defun magit-branch (branch start-point &optional args)
- "Create BRANCH at branch or revision START-POINT.
-\n(git branch [ARGS] BRANCH START-POINT)."
- (interactive (magit-branch-read-args "Create branch"))
- (magit-call-git "branch" args branch start-point)
- (--when-let (and (magit-get-upstream-branch branch)
- (magit-get-indirect-upstream-branch start-point))
- (magit-call-git "branch" (concat "--set-upstream-to=" it) branch))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-branch-and-checkout (branch start-point &optional args)
- "Create and checkout BRANCH at branch or revision START-POINT.
-\n(git checkout [ARGS] -b BRANCH START-POINT)."
- (interactive (magit-branch-read-args "Create and checkout branch"))
- (if (string-match-p "^stash@{[0-9]+}$" start-point)
- (magit-run-git "stash" "branch" branch start-point)
- (magit-call-git "checkout" args "-b" branch start-point)
- (--when-let (and (magit-get-upstream-branch branch)
- (magit-get-indirect-upstream-branch start-point))
- (magit-call-git "branch" (concat "--set-upstream-to=" it) branch))
- (magit-refresh)))
-
-(defun magit-branch-read-args (prompt)
- (let ((args (magit-branch-arguments)) start branch)
- (cond (magit-branch-read-upstream-first
- (setq start (magit-read-starting-point prompt))
- (setq branch (magit-read-string-ns
- "Branch name"
- (let ((def (mapconcat #'identity
- (cdr (split-string start "/"))
- "/")))
- (and (member start (magit-list-remote-branch-names))
- (not (member def (magit-list-local-branch-names)))
- def)))))
- (t
- (setq branch (magit-read-string-ns "Branch name"))
- (setq start (magit-read-starting-point prompt))))
- (list branch start args)))
-
-;;;###autoload
-(defun magit-branch-spinoff (branch &rest args)
- "Create new branch from the unpushed commits.
-
-Create and checkout a new branch starting at and tracking the
-current branch. That branch in turn is reset to the last commit
-it shares with its upstream. If the current branch has no
-upstream or no unpushed commits, then the new branch is created
-anyway and the previously current branch is not touched.
-
-This is useful to create a feature branch after work has already
-began on the old branch (likely but not necessarily \"master\").
-
-If the current branch is a member of the value of option
-`magit-branch-prefer-remote-upstream' (which see), then the
-current branch will be used as the starting point as usual, but
-the upstream of the starting-point may be used as the upstream
-of the new branch, instead of the starting-point itself."
- (interactive (list (magit-read-string "Spin off branch")
- (magit-branch-arguments)))
- (when (magit-branch-p branch)
- (user-error "Branch %s already exists" branch))
- (-if-let (current (magit-get-current-branch))
- (let (tracked base)
- (magit-call-git "checkout" args "-b" branch current)
- (--when-let (magit-get-indirect-upstream-branch current)
- (magit-call-git "branch" "--set-upstream-to" it branch))
- (when (and (setq tracked (magit-get-upstream-branch current))
- (setq base (magit-git-string "merge-base" current tracked))
- (not (magit-rev-eq base current)))
- (magit-call-git "update-ref" "-m"
- (format "reset: moving to %s" base)
- (concat "refs/heads/" current) base))
- (magit-refresh))
- (magit-run-git "checkout" "-b" branch)))
-
-;;;###autoload
-(defun magit-branch-reset (branch to &optional args set-upstream)
- "Reset a branch to the tip of another branch or any other commit.
-
-When the branch being reset is the current branch, then do a
-hard reset. If there are any uncommitted changes, then the user
-has to confirming the reset because those changes would be lost.
-
-This is useful when you have started work on a feature branch but
-realize it's all crap and want to start over.
-
-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-branch-at-point))
- (branch (magit-read-local-branch "Reset branch" atpoint)))
- (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-branch-arguments)
- current-prefix-arg)))
- (unless (member "--force" args)
- (setq args (cons "--force" args)))
- (if (equal branch (magit-get-current-branch))
- (if (and (magit-anything-modified-p)
- (not (yes-or-no-p "Uncommitted changes will be lost. Proceed?")))
- (user-error "Abort")
- (magit-reset-hard to)
- (when (and set-upstream (magit-branch-p to))
- (magit-set-branch*merge/remote branch to)))
- (magit-branch branch to args)))
-
-;;;###autoload
-(defun magit-branch-delete (branches &optional force)
- "Delete one or multiple branches.
-If the region marks multiple branches, then offer to delete
-those, otherwise prompt for a single branch to be deleted,
-defaulting to the branch at point."
- (interactive
- (let ((branches (magit-region-values 'branch))
- (force current-prefix-arg))
- (if (if (> (length branches) 1)
- (magit-confirm t nil "Delete %i branches" branches)
- (setq branches
- (list (magit-read-branch (if current-prefix-arg
- "Force delete branch"
- "Delete branch")
- (magit-get-previous-branch)))))
- (unless force
- (--when-let (-intersection
- (-union (magit-list-unmerged-branches)
- (magit-list-unmerged-to-upstream-branches))
- branches)
- (if (magit-confirm 'delete-unmerged-branch
- "Delete unmerged branch %s"
- "Delete %i unmerged branches" it)
- (setq force t)
- (or (setq branches (-difference branches it))
- (user-error "Abort")))))
- (user-error "Abort"))
- (list branches force)))
- (let* ((refs (-map #'magit-ref-fullname branches))
- (ambiguous (--filter (not it) refs)))
- (when ambiguous
- (user-error
- "%s ambiguous. Please cleanup using git directly."
- (let ((len (length ambiguous)))
- (cond
- ((= len 1)
- (format "%s is" (--first (not (magit-ref-fullname it)) branches)))
- ((= len (length refs))
- (format "These %s names are" len))
- (t
- (format "%s of these names are" len))))))
- (cond
- ((string-match "^refs/remotes/\\([^/]+\\)" (car refs))
- (let* ((remote (match-string 1 (car refs)))
- (offset (1+ (length remote))))
- (magit-run-git-async
- "push" remote (--map (concat ":" (substring it offset)) branches))))
- ((> (length branches) 1)
- (magit-run-git "branch" (if force "-D" "-d")
- (delete (magit-get-current-branch) branches)))
- (t ; And now for something completely different.
- (let* ((branch (car branches))
- (prompt (format "Branch %s is checked out. " branch)))
- (when (equal branch (magit-get-current-branch))
- (pcase (if (or (equal branch "master")
- (not (magit-rev-verify "master")))
- (magit-read-char-case prompt nil
- (?d "[d]etach HEAD & delete" 'detach)
- (?a "[a]bort" 'abort))
- (magit-read-char-case prompt nil
- (?d "[d]etach HEAD & delete" 'detach)
- (?c "[c]heckout master & delete" 'master)
- (?a "[a]bort" 'abort)))
- (`detach (magit-call-git "checkout" "--detach"))
- (`master (magit-call-git "checkout" "master"))
- (`abort (user-error "Abort")))
- (setq force t))
- (magit-run-git "branch" (if force "-D" "-d") branch))))))
-
-(put 'magit-branch-delete 'interactive-only t)
-
-;;;###autoload
-(defun magit-branch-rename (old new &optional force)
- "Rename branch OLD to NEW.
-With prefix, forces the rename even if NEW already exists.
-\n(git branch -m|-M OLD NEW)."
- (interactive
- (let ((branch (magit-read-local-branch "Rename branch")))
- (list branch
- (magit-read-string-ns (format "Rename branch '%s' to" branch)
- nil 'magit-revision-history)
- current-prefix-arg)))
- (unless (string= old new)
- (magit-run-git "branch" (if force "-M" "-m") old new)))
-
-;;;;; Branch Config Popup
-
-(defvar magit-branch-config-branch nil)
-
-;;;###autoload
-(defun magit-branch-config-popup (branch)
- "Popup console for setting branch variables."
- (interactive
- (list (if (or current-prefix-arg
- (and (eq magit-current-popup 'magit-branch-popup)
- magit-branch-popup-show-variables))
- (magit-read-local-branch "Configure branch")
- (magit-get-current-branch))))
- (let ((magit-branch-config-branch branch))
- (magit-invoke-popup 'magit-branch-config-popup nil nil)))
-
-(defvar magit-branch-config-variables
- '((lambda ()
- (concat
- (propertize "Configure " 'face 'magit-popup-heading)
- (propertize (magit-branch-config-branch) 'face 'magit-branch-local)))
- (?d "branch.%s.description"
- magit-edit-branch*description
- magit-format-branch*description)
- (?u "branch.%s.merge"
- magit-set-branch*merge/remote
- magit-format-branch*merge/remote)
- (?r "branch.%s.rebase"
- magit-cycle-branch*rebase
- magit-format-branch*rebase)
- (?p "branch.%s.pushRemote"
- magit-cycle-branch*pushRemote
- magit-format-branch*pushRemote)
- "Configure repository defaults"
- (?\M-r "pull.rebase"
- magit-cycle-pull.rebase
- magit-format-pull.rebase)
- (?\M-p "remote.pushDefault"
- magit-cycle-remote.pushDefault
- magit-format-remote.pushDefault)
- "Configure branch creation"
- (?U "branch.autoSetupMerge"
- magit-cycle-branch*autoSetupMerge
- magit-format-branch*autoSetupMerge)
- (?R "branch.autoSetupRebase"
- magit-cycle-branch*autoSetupRebase
- magit-format-branch*autoSetupRebase)))
-
-(defvar magit-branch-config-popup
- `(:man-page "git-branch"
- :variables ,magit-branch-config-variables
- :default-action magit-checkout
- :setup-function magit-branch-config-popup-setup))
-
-(defun magit-branch-config-popup-setup (val def)
- (magit-popup-default-setup val def)
- (setq-local magit-branch-config-branch magit-branch-config-branch))
-
-(defun magit-branch-config-branch (&optional prompt)
- (if prompt
- (or (and (not current-prefix-arg)
- (or magit-branch-config-branch
- (magit-get-current-branch)))
- (magit-read-local-branch prompt))
- (or magit-branch-config-branch
- (magit-get-current-branch)
- "<name>")))
-
-;;;###autoload
-(defun magit-edit-branch*description (branch)
- "Edit the description of the current branch.
-With a prefix argument edit the description of another branch.
-
-The description for the branch named NAME is stored in the Git
-variable `branch.<name>.description'."
- (interactive (list (magit-branch-config-branch "Edit branch description")))
- (magit-run-git-with-editor "branch" "--edit-description" branch))
-
-(defun magit-edit-branch*description-check-buffers ()
- (and buffer-file-name
- (string-match-p "/BRANCH_DESCRIPTION\\'" buffer-file-name)
- (add-hook 'with-editor-post-finish-hook
- (lambda ()
- (when (derived-mode-p 'magit-popup-mode)
- (magit-refresh-popup-buffer)))
- nil t)))
-
-(add-hook 'find-file-hook 'magit-edit-branch*description-check-buffers)
-
-(defun magit-format-branch*description ()
- (let* ((branch (magit-branch-config-branch))
- (width (+ (length branch) 19))
- (var (format "branch.%s.description" branch)))
- (concat var " " (make-string (- width (length var)) ?\s)
- (-if-let (value (magit-get var))
- (propertize value 'face 'magit-popup-option-value)
- (propertize "unset" 'face 'magit-popup-disabled-argument)))))
-
-;;;###autoload
-(defun magit-set-branch*merge/remote (branch upstream)
- "Set or unset the upstream of the current branch.
-With a prefix argument do so for another branch.
-
-When the branch in question already has an upstream then simply
-unsets it. Invoke this command again to set another upstream.
-
-Together the Git variables `branch.<name>.remote' and
-`branch.<name>.merge' define the upstream branch of the local
-branch named NAME. The value of `branch.<name>.remote' is the
-name of the upstream remote. The value of `branch.<name>.merge'
-is the full reference of the upstream branch, on the remote.
-
-Non-interactively, when UPSTREAM is non-nil, then always set it
-as the new upstream, regardless of whether another upstream was
-already set. When nil, then always unset."
- (interactive
- (let ((branch (magit-branch-config-branch "Change upstream of branch")))
- (list branch (and (not (magit-get-upstream-branch branch))
- (magit-read-upstream-branch)))))
- (if upstream
- (-let (((remote . merge) (magit-split-branch-name upstream)))
- (magit-call-git "config" (format "branch.%s.remote" branch) remote)
- (magit-call-git "config" (format "branch.%s.merge" branch)
- (concat "refs/heads/" merge)))
- (magit-call-git "branch" "--unset-upstream" branch))
- (when (called-interactively-p 'any)
- (magit-refresh)))
-
-(defun magit-format-branch*merge/remote ()
- (let* ((branch (magit-branch-config-branch))
- (width (+ (length branch) 20))
- (varM (format "branch.%s.merge" branch))
- (varR (format "branch.%s.remote" branch))
- (face (if (equal (magit-get varR) ".")
- 'magit-branch-local
- 'magit-branch-remote)))
- (concat varM (make-string (- width (length varM)) ?\s)
- (-if-let (value (magit-get varM))
- (propertize value 'face face)
- (propertize "unset" 'face 'magit-popup-disabled-argument))
- "\n " varR (make-string (- width (length varR)) ?\s)
- (-if-let (value (magit-get varR))
- (propertize value 'face face)
- (propertize "unset" 'face 'magit-popup-disabled-argument)))))
-
-;;;###autoload
-(defun magit-cycle-branch*rebase (branch)
- "Cycle the value of `branch.<name>.rebase' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variables `branch.<name>.rebase' controls whether pulling
-into the branch named NAME is done by rebasing that branch onto
-the fetched branch or by merging that branch.
-
-When `true' then pulling is done by rebasing.
-When `false' then pulling is done by merging.
-
-When that variable is undefined then the value of `pull.rebase'
-is used instead. It defaults to `false'."
- (interactive (list (magit-branch-config-branch
- "Cycle branch.<name>.rebase for")))
- (magit-popup-set-variable (format "branch.%s.rebase" branch)
- '("true" "false")
- "false" "pull.rebase"))
-
-(defun magit-format-branch*rebase ()
- (let ((branch (magit-branch-config-branch)))
- (magit-popup-format-variable (format "branch.%s.rebase" branch)
- '("true" "false")
- "false" "pull.rebase"
- (+ (length branch) 20))))
-
-;;;###autoload
-(defun magit-cycle-branch*pushRemote (branch)
- "Cycle the value of `branch.<name>.pushRemote' for the current branch.
-With a prefix argument cycle the value for another branch.
-
-The Git variable `branch.<name>.pushRemote' specifies the remote
-that the branch named NAME is usually pushed to. The value has
-to be the name of an existing remote.
-
-If that variable is undefined, then the value of the Git variable
-`remote.pushDefault' is used instead, provided that it is defined,
-which by default it is not."
- (interactive (list (magit-branch-config-branch
- "Cycle branch.<name>.pushRemote for")))
- (magit-popup-set-variable (format "branch.%s.pushRemote" branch)
- (magit-list-remotes)
- "remote.pushDefault"))
-
-(defun magit-format-branch*pushRemote ()
- (let ((branch (magit-branch-config-branch)))
- (magit-popup-format-variable (format "branch.%s.pushRemote" branch)
- (magit-list-remotes)
- nil "remote.pushDefault"
- (+ (length branch) 20))))
-
-;;;###autoload
-(defun magit-cycle-pull.rebase ()
- "Cycle the repository-local value of `pull.rebase'.
-
-The Git variable `pull.rebase' specifies whether pulling is done
-by rebasing or by merging. It can be overwritten using the Git
-variable `branch.<name>.rebase'.
-
-When `true' then pulling is done by rebasing.
-When `false' (the default) then pulling is done by merging."
- (interactive)
- (magit-popup-set-variable "pull.rebase" '("true" "false") "false"))
-
-(defun magit-format-pull.rebase ()
- (magit-popup-format-variable "pull.rebase" '("true" "false") "false" nil 19))
-
-;;;###autoload
-(defun magit-cycle-remote.pushDefault ()
- "Cycle the repository-local value of `remote.pushDefault'.
-
-The Git variable `remote.pushDefault' specifies the remote that
-local branches are usually pushed to. It can be overwritten
-using the Git variable `branch.<name>.pushRemote'."
- (interactive)
- (magit-popup-set-variable "remote.pushDefault" (magit-list-remotes)))
-
-(defun magit-format-remote.pushDefault ()
- (magit-popup-format-variable "remote.pushDefault"
- (magit-list-remotes) nil nil 19))
-
-;;;###autoload
-(defun magit-cycle-branch*autoSetupMerge ()
- "Cycle the repository-local value of `branch.autoSetupMerge'.
-
-The Git variable `branch.autoSetupMerge' under what circumstances
-creating a branch (named NAME) should result in the variables
-`branch.<name>.merge' and `branch.<name>.remote' being set
-according to the starting point used to create the branch. If
-the starting point isn't a branch, then these variables are never
-set.
-
-When `always' then the variables are set regardless of whether
-the starting point is a local or a remote branch.
-
-When `true' (the default) then the variable are set when the
-starting point is a remote branch, but not when it is a local
-branch.
-
-When `false' then the variables are never set."
- (interactive)
- (magit-popup-set-variable "branch.autoSetupMerge"
- '("always" "true" "false") "true"))
-
-(defun magit-format-branch*autoSetupMerge ()
- (magit-popup-format-variable "branch.autoSetupMerge"
- '("always" "true" "false") "true" nil 23))
-
-;;;###autoload
-(defun magit-cycle-branch*autoSetupRebase ()
- "Cycle the repository-local value of `branch.autoSetupRebase'.
-
-The Git variable `branch.autoSetupRebase' specifies whether
-creating a branch (named NAME) should result in the variable
-`branch.<name>.rebase' being set to `true'.
-
-When `always' then the variable is set regardless of whether the
-starting point is a local or a remote branch.
-
-When `local' then the variable are set when the starting point
-is a local branch, but not when it is a remote branch.
-
-When `remote' then the variable are set when the starting point
-is a remote branch, but not when it is a local branch.
-
-When `never' (the default) then the variable is never set."
- (interactive)
- (magit-popup-set-variable "branch.autoSetupRebase"
- '("always" "local" "remote" "never") "never"))
-
-(defun magit-format-branch*autoSetupRebase ()
- (magit-popup-format-variable "branch.autoSetupRebase"
- '("always" "local" "remote" "never")
- "never" nil 23))
-
-;;;; Merge
-
-;;;###autoload (autoload 'magit-merge-popup "magit" nil t)
-(magit-define-popup magit-merge-popup
- "Popup console for merge commands."
- 'magit-commands
- :man-page "git-merge"
- :switches '((?f "Fast-forward only" "--ff-only")
- (?n "No fast-forward" "--no-ff")
- (?s "Squash" "--squash"))
- :options '((?s "Strategy" "--strategy="))
- :actions '((?m "Merge" magit-merge)
- (?e "Merge and edit message" magit-merge-editmsg)
- (?p "Preview merge" magit-merge-preview)
- (?n "Merge but don't commit" magit-merge-nocommit))
- :sequence-actions '((?m "Commit merge" magit-commit)
- (?a "Abort merge" magit-merge-abort))
- :sequence-predicate 'magit-merge-state
- :default-action 'magit-merge
- :max-action-columns 2)
-
-;;;###autoload
-(defun magit-merge (rev &optional args nocommit)
- "Merge commit REV into the current branch; using default message.
-
-Unless there are conflicts or a prefix argument is used create a
-merge commit using a generic commit message and without letting
-the user inspect the result. With a prefix argument pretend the
-merge failed to give the user the opportunity to inspect the
-merge.
-
-\(git merge --no-edit|--no-commit [ARGS] REV)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)
- current-prefix-arg))
- (magit-merge-assert)
- (magit-run-git "merge" (if nocommit "--no-commit" "--no-edit") args rev))
-
-;;;###autoload
-(defun magit-merge-editmsg (rev &optional args)
- "Merge commit REV into the current branch; and edit message.
-Perform the merge and prepare a commit message but let the user
-edit it.
-\n(git merge --edit --no-ff [ARGS] rev)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)))
- (magit-merge-assert)
- (cl-pushnew "--no-ff" args :test #'equal)
- (with-editor "GIT_EDITOR"
- (let ((magit-process-popup-time -1))
- (magit-run-git-async "merge" "--edit" args rev))))
-
-;;;###autoload
-(defun magit-merge-nocommit (rev &optional args)
- "Merge commit REV into the current branch; pretending it failed.
-Pretend the merge failed to give the user the opportunity to
-inspect the merge and change the commit message.
-\n(git merge --no-commit --no-ff [ARGS] rev)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)))
- (magit-merge-assert)
- (cl-pushnew "--no-ff" args :test #'equal)
- (magit-run-git "merge" "--no-commit" args rev))
-
-;;;###autoload
-(defun magit-merge-preview (rev)
- "Preview result of merging REV into the current branch."
- (interactive (list (magit-read-other-branch-or-commit "Preview merge")))
- (magit-mode-setup #'magit-merge-preview-mode rev))
-
-(define-derived-mode magit-merge-preview-mode magit-diff-mode "Magit Merge"
- "Mode for previewing a merge."
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-merge-preview-refresh-buffer (rev)
- (let* ((branch (magit-get-current-branch))
- (head (or branch (magit-rev-verify "HEAD"))))
- (setq header-line-format
- (propertize (format "Preview merge of %s into %s"
- rev (or branch "HEAD"))
- 'face 'magit-header-line))
- (magit-insert-section (diffbuf)
- (magit-git-wash #'magit-diff-wash-diffs
- "merge-tree" (magit-git-string "merge-base" head rev) head rev))))
-
-;;;###autoload
-(defun magit-merge-abort ()
- "Abort the current merge operation.
-\n(git merge --abort)"
- (interactive)
- (if (file-exists-p (magit-git-dir "MERGE_HEAD"))
- (when (magit-confirm 'abort-merge)
- (magit-run-git-async "merge" "--abort"))
- (user-error "No merge in progress")))
-
-(defun magit-checkout-stage (file arg)
- "During a conflict checkout and stage side, or restore conflict."
- (interactive
- (let ((file (magit-completing-read "Checkout file"
- (magit-tracked-files) nil nil nil
- 'magit-read-file-hist
- (magit-current-file))))
- (cond ((member file (magit-unmerged-files))
- (list file (magit-checkout-read-stage file)))
- ((yes-or-no-p (format "Restore conflicts in %s? " file))
- (list file "--merge"))
- (t
- (user-error "Quit")))))
- (pcase (cons arg (cddr (car (magit-file-status file))))
- ((or `("--ours" ?D ,_)
- `("--theirs" ,_ ?D))
- (magit-run-git "rm" "--" file))
- (_ (if (equal arg "--merge")
- ;; This fails if the file was deleted on one
- ;; side. And we cannot do anything about it.
- (magit-run-git "checkout" "--merge" "--" file)
- (magit-call-git "checkout" arg "--" file)
- (magit-run-git "add" "-u" "--" file)))))
-
-(defun magit-merge-state ()
- (file-exists-p (magit-git-dir "MERGE_HEAD")))
-
-(defun magit-merge-assert ()
- (or (not (magit-anything-modified-p))
- (magit-confirm 'merge-dirty
- "Merging with dirty worktree is risky. Continue")
- (user-error "Abort")))
-
-(defun magit-checkout-read-stage (file)
- (magit-read-char-case (format "For %s checkout: " file) t
- (?o "[o]ur stage" "--ours")
- (?t "[t]heir stage" "--theirs")
- (?c "[c]onflict" "--merge")))
-
-(defun magit-insert-merge-log ()
- "Insert section for the on-going merge.
-Display the heads that are being merged.
-If no merge is in progress, do nothing."
- (-when-let (heads (mapcar 'magit-get-shortname
- (magit-file-lines (magit-git-dir "MERGE_HEAD"))))
- (magit-insert-section (commit (car heads))
- (magit-insert-heading
- (format "Merging %s:" (mapconcat 'identity heads ", ")))
- (magit-insert-log
- (concat (magit-git-string "merge-base" "--octopus" "HEAD" (car heads))
- ".." (car heads))
- (let ((args magit-log-section-arguments))
- (unless (member "--decorate=full" magit-log-section-arguments)
- (push "--decorate=full" args))
- args)))))
-
-;;;; Reset
-
-;;;###autoload (autoload 'magit-reset-popup "magit" nil t)
-(magit-define-popup magit-reset-popup
- "Popup console for reset commands."
- 'magit-commands
- :man-page "git-reset"
- :actions '((?m "reset mixed (HEAD and index)" magit-reset-head)
- (?s "reset soft (HEAD only)" magit-reset-soft)
- (?h "reset hard (HEAD, index, and files)" magit-reset-hard)
- (?i "reset index (index only)" magit-reset-index))
- :max-action-columns 1)
-
-;;;###autoload
-(defun magit-reset-index (commit)
- "Reset the index to COMMIT.
-Keep the head and working tree as-is, so if COMMIT refers to the
-head this effectively unstages all changes.
-\n(git reset COMMIT .)"
- (interactive (list (magit-read-branch-or-commit "Reset index to")))
- (magit-reset-internal nil commit "."))
-
-;;;###autoload
-(defun magit-reset (commit &optional hard)
- "Reset the head and index to COMMIT, but not the working tree.
-With a prefix argument also reset the working tree.
-\n(git reset --mixed|--hard COMMIT)"
- (interactive (list (magit-read-branch-or-commit
- (if current-prefix-arg
- "Hard reset to"
- "Reset head to"))
- current-prefix-arg))
- (magit-reset-internal (if hard "--hard" "--mixed") commit))
-
-;;;###autoload
-(defun magit-reset-head (commit)
- "Reset the head and index to COMMIT, but not the working tree.
-\n(git reset --mixed COMMIT)"
- (interactive (list (magit-read-branch-or-commit "Reset head to")))
- (magit-reset-internal "--mixed" commit))
-
-;;;###autoload
-(defun magit-reset-soft (commit)
- "Reset the head to COMMIT, but not the index and working tree.
-\n(git reset --soft REVISION)"
- (interactive (list (magit-read-branch-or-commit "Soft reset to")))
- (magit-reset-internal "--soft" commit))
-
-;;;###autoload
-(defun magit-reset-hard (commit)
- "Reset the head, index, and working tree to COMMIT.
-\n(git reset --hard REVISION)"
- (interactive (list (magit-read-branch-or-commit "Hard reset to")))
- (magit-reset-internal "--hard" commit))
-
-(defun magit-reset-internal (arg commit &optional path)
- (when (and (not (member arg '("--hard" nil)))
- (equal (magit-rev-parse commit)
- (magit-rev-parse "HEAD~")))
- (with-temp-buffer
- (magit-git-insert "show" "-s" "--format=%B" "HEAD")
- (when git-commit-major-mode
- (funcall git-commit-major-mode))
- (git-commit-setup-font-lock)
- (git-commit-save-message)))
- (let ((cmd (if (and (equal commit "HEAD") (not arg)) "unstage" "reset")))
- (magit-wip-commit-before-change nil (concat " before " cmd))
- (magit-run-git "reset" arg commit "--" path)
- (when (equal cmd "unstage")
- (magit-wip-commit-after-apply nil " after unstage"))))
-
-;;;; Files
-
-(defun magit-file-rename (file newname)
- "Rename the FILE to NEWNAME.
-If FILE isn't tracked in Git fallback to using `rename-file'."
- (interactive
- (let* ((file (magit-read-file "Rename file"))
- (newname (read-file-name (format "Rename %s to file: " file))))
- (list (expand-file-name file (magit-toplevel))
- (expand-file-name newname))))
- (if (magit-file-tracked-p file)
- (let ((oldbuf (get-file-buffer file)))
- (when (and oldbuf (buffer-modified-p oldbuf))
- (user-error "Save %s before moving it" file))
- (when (file-exists-p newname)
- (user-error "%s already exists" newname))
- (magit-run-git "mv" file newname)
- (when oldbuf
- (with-current-buffer oldbuf
- (let ((buffer-read-only buffer-read-only))
- (set-visited-file-name newname))
- (if (fboundp 'vc-refresh-state)
- (vc-refresh-state)
- (with-no-warnings
- (vc-find-file-hook))))))
- (rename-file file newname current-prefix-arg)
- (magit-refresh)))
-
-(defun magit-file-untrack (file)
- "Untrack FILE.
-Stop tracking FILE in Git but do not remove it from the working
-tree."
- (interactive (list (magit-read-tracked-file "Untrack file")))
- (magit-run-git "rm" "--cached" "--" file))
-
-(defun magit-file-delete (file &optional force)
- "Delete FILE.
-With a prefix argument FORCE do so even when FILE has uncommitted
-changes.
-
-If FILE isn't tracked in Git fallback to using `delete-file'."
- (interactive (list (magit-read-file "Delete file")))
- (if (magit-file-tracked-p file)
- (magit-run-git "rm" (and force "--force") "--" file)
- (delete-file (expand-file-name file (magit-toplevel)) t)
- (magit-refresh)))
-
-(defun magit-read-tracked-file (prompt)
- (magit-read-file prompt t))
-
-(defun magit-read-file (prompt &optional tracked-only)
- (let ((choices (nconc (magit-list-files)
- (unless tracked-only (magit-untracked-files)))))
- (magit-completing-read prompt choices nil t nil nil
- (car (member (or (magit-section-when (file))
- (magit-file-relative-name
- nil tracked-only))
- choices)))))
-
-(defun magit-read-files (prompt initial-contents)
- (mapconcat 'identity
- (completing-read-multiple (or prompt "File,s: ")
- (magit-list-files)
- nil nil initial-contents) ","))
-
-(defun magit-read-file-choice (prompt files &optional error default)
- "Read file from FILES.
-
-If FILES has only one member, return that instead of prompting.
-If FILES has no members, give a user error. ERROR can be given
-to provide a more informative error.
-
-If DEFAULT is non-nil, use this as the default value instead of
-`magit-current-file'."
- (pcase (length files)
- (0 (user-error (or error "No file choices")))
- (1 (car files))
- (_ (magit-completing-read
- prompt files nil t nil 'magit-read-file-hist
- (car (member (or default (magit-current-file)) files))))))
-
-;;; Miscellaneous
-;;;; Worktree
-
-;;;###autoload
-(defun magit-worktree-checkout (path branch)
- (interactive
- (let ((branch (magit-read-local-branch "Checkout")))
- (list (read-directory-name (format "Checkout %s in new worktree: " branch))
- branch)))
- "Checkout BRANCH in a new worktree at PATH."
- (magit-run-git "worktree" "add" path branch)
- (magit-diff-visit-directory path))
-
-;;;###autoload
-(defun magit-worktree-branch (path branch start-point &optional force)
- "Create a new BRANCH and check it out in a new worktree at PATH."
- (interactive
- `(,(read-directory-name "Create worktree: ")
- ,@(butlast (magit-branch-read-args "Create and checkout branch"))
- ,current-prefix-arg))
- (magit-run-git "worktree" "add" (if force "-B" "-b") branch path start-point)
- (magit-diff-visit-directory path))
-
-(defun magit-worktree-delete (worktree)
- "Delete a worktree, defaulting to the worktree at point.
-The primary worktree cannot be deleted."
- (interactive
- (list (magit-completing-read "Delete worktree"
- (cdr (magit-list-worktrees))
- nil t nil nil
- (magit-section-when (worktree)))))
- (if (file-directory-p (expand-file-name ".git" worktree))
- (user-error "Deleting %s would delete the shared .git directory" worktree)
- (let ((primary (file-name-as-directory (caar (magit-list-worktrees)))))
- (when (if magit-delete-by-moving-to-trash
- (magit-confirm-files 'trash (list "worktree"))
- (magit-confirm-files 'delete (list "worktree")))
- (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
- (delete-directory worktree t magit-delete-by-moving-to-trash))
- (if (file-exists-p default-directory)
- (magit-run-git "worktree" "prune")
- (let ((default-directory primary))
- (magit-run-git "worktree" "prune")))))))
-
-(defun magit-worktree-status (worktree)
- "Show the status for the worktree at point.
-If there is no worktree at point, then read one in the
-minibuffer. If the worktree at point is the one whose
-status is already being displayed in the current buffer,
-then show it in Dired instead."
- (interactive
- (list (or (magit-section-when (worktree))
- (magit-completing-read
- "Show status for worktree"
- (cl-delete (directory-file-name (magit-toplevel))
- (magit-list-worktrees)
- :test #'equal :key #'car)))))
- (magit-diff-visit-directory worktree))
-
-(defvar magit-worktree-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-worktree-status)
- (define-key map [remap magit-delete-thing] 'magit-worktree-delete)
- map)
- "Keymap for `worktree' sections.")
-
-(defun magit-insert-worktrees ()
- "Insert sections for all worktrees.
-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:")
- (let* ((cols
- (mapcar (-lambda ((path barep commit branch))
- (cons (cond
- (branch (propertize branch
- 'face 'magit-branch-local))
- (commit (propertize (magit-rev-abbrev commit)
- 'face 'magit-hash))
- (barep "(bare)"))
- path))
- worktrees))
- (align (1+ (-max (--map (string-width (car it)) cols)))))
- (pcase-dolist (`(,head . ,path) cols)
- (magit-insert-section (worktree path)
- (insert head)
- (indent-to align)
- (insert (let ((r (file-relative-name path))
- (a (abbreviate-file-name path)))
- (if (< (string-width r) (string-width a)) r a)))
- (insert ?\n))))
- (insert ?\n)))))
-
-;;;; Tag
-
-;;;###autoload (autoload 'magit-tag-popup "magit" nil t)
-(magit-define-popup magit-tag-popup
- "Popup console for tag commands."
- 'magit-commands
- :man-page "git-tag"
- :switches '((?a "Annotate" "--annotate")
- (?s "Sign" "--sign")
- (?f "Force" "--force"))
- :actions '((?t "Create" magit-tag)
- (?k "Delete" magit-tag-delete)
- (?p "Prune" magit-tag-prune))
- :default-action 'magit-tag)
-
-;;;###autoload
-(defun magit-tag (name rev &optional args)
- "Create a new tag with the given NAME at REV.
-With a prefix argument annotate the tag.
-\n(git tag [--annotate] NAME REV)"
- (interactive (list (magit-read-tag "Tag name")
- (magit-read-branch-or-commit "Place tag on")
- (let ((args (magit-tag-arguments)))
- (when current-prefix-arg
- (cl-pushnew "--annotate" args))
- args)))
- (magit-run-git-with-editor "tag" args name rev))
-
-;;;###autoload
-(defun magit-tag-delete (tags)
- "Delete one or more tags.
-If the region marks multiple tags (and nothing else), then offer
-to delete those, otherwise prompt for a single tag to be deleted,
-defaulting to the tag at point.
-\n(git tag -d TAGS)"
- (interactive (list (--if-let (magit-region-values 'tag)
- (magit-confirm t nil "Delete %i tags" it)
- (magit-read-tag "Delete tag" t))))
- (magit-run-git "tag" "-d" tags))
-
-(defun magit-tag-prune (tags remote-tags remote)
- "Offer to delete tags missing locally from REMOTE, and vice versa."
- (interactive
- (let* ((remote (magit-read-remote "Prune tags using remote"))
- (tags (magit-list-tags))
- (rtags (prog2 (message "Determining remote tags...")
- (magit-remote-list-tags remote)
- (message "Determining remote tags...done")))
- (ltags (-difference tags rtags))
- (rtags (-difference rtags tags)))
- (unless (or ltags rtags)
- (message "Same tags exist locally and remotely"))
- (unless (magit-confirm t "Delete %s locally"
- "Delete %i tags locally" ltags)
- (setq ltags nil))
- (unless (magit-confirm t "Delete %s from remote"
- "Delete %i tags from remote" rtags)
- (setq rtags nil))
- (list ltags rtags remote)))
- (when tags
- (magit-call-git "tag" "-d" tags))
- (when remote-tags
- (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags))))
-
-;;;; Notes
-
-;;;###autoload (autoload 'magit-notes-popup "magit" nil t)
-(magit-define-popup magit-notes-popup
- "Popup console for notes commands."
- 'magit-commands
- :man-page "git-tag"
- :switches '("Switch for prune"
- (?n "Dry run" "--dry-run"))
- :options '("Option for edit and remove"
- (?r "Manipulate ref" "--ref=" magit-notes-popup-read-ref)
- "Option for merge"
- (?s "Merge strategy" "--strategy="))
- :actions '((?T "Edit" magit-notes-edit)
- (?r "Remove" magit-notes-remove)
- (?m "Merge" magit-notes-merge)
- (?p "Prune" magit-notes-prune)
- (?s "Set ref" magit-notes-set-ref)
- (?S "Set display refs" magit-notes-set-display-refs))
- :sequence-actions '((?c "Commit merge" magit-notes-merge-commit)
- (?a "Abort merge" magit-notes-merge-abort))
- :sequence-predicate 'magit-notes-merging-p
- :default-action 'magit-notes-edit)
-
-(defun magit-notes-edit (commit &optional ref)
- "Edit the note attached to COMMIT.
-REF is the notes ref used to store the notes.
-
-Interactively or when optional REF is nil use the value of Git
-variable `core.notesRef' or \"refs/notes/commits\" if that is
-undefined."
- (interactive (magit-notes-read-args "Edit notes"))
- (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
- "edit" commit))
-
-(defun magit-notes-remove (commit &optional ref)
- "Remove the note attached to COMMIT.
-REF is the notes ref from which the note is removed.
-
-Interactively or when optional REF is nil use the value of Git
-variable `core.notesRef' or \"refs/notes/commits\" if that is
-undefined."
- (interactive (magit-notes-read-args "Remove notes"))
- (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
- "remove" commit))
-
-(defun magit-notes-merge (ref)
- "Merge the notes ref REF into the current notes ref.
-
-The current notes ref is the value of Git variable
-`core.notesRef' or \"refs/notes/commits\" if that is undefined.
-
-When there are conflict, then they have to resolved in the
-temporary worktree \".git/NOTES_MERGE_WORKTREE\". When
-done use `magit-notes-merge-commit' to finish. To abort
-use `magit-notes-merge-abort'."
- (interactive (list (magit-read-string-ns "Merge reference")))
- (magit-run-git-with-editor "notes" "merge" ref))
-
-(defun magit-notes-merge-commit ()
- "Commit the current notes ref merge.
-Also see `magit-notes-merge'."
- (interactive)
- (magit-run-git-with-editor "notes" "merge" "--commit"))
-
-(defun magit-notes-merge-abort ()
- "Abort the current notes ref merge.
-Also see `magit-notes-merge'."
- (interactive)
- (magit-run-git-with-editor "notes" "merge" "--abort"))
-
-(defun magit-notes-prune (&optional dry-run)
- "Remove notes about unreachable commits."
- (interactive (list (and (member "--dry-run" (magit-notes-arguments)) t)))
- (when dry-run
- (magit-process-buffer))
- (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run")))
-
-(defun magit-notes-set-ref (ref &optional global)
- "Set the current notes ref to REF.
-The ref is made current by setting the value of the Git variable
-`core.notesRef'. With a prefix argument GLOBAL change the global
-value, else the value in the current repository. When this is
-undefined, then \"refs/notes/commit\" is used.
-
-Other `magit-notes-*' commands, as well as the sub-commands
-of Git's `note' command, default to operate on that ref."
- (interactive
- (list (magit-completing-read "Set notes ref"
- (nconc (list "refs/" "refs/notes/")
- (magit-list-notes-refnames))
- nil nil
- (--when-let (magit-get "core.notesRef")
- (if (string-match "^refs/notes/\\(.+\\)" it)
- (match-string 1 it)
- it)))
- current-prefix-arg))
- (if ref
- (magit-run-git "config" (and global "--global") "core.notesRef"
- (if (string-prefix-p "refs/" ref)
- ref
- (concat "refs/notes/" ref)))
- (magit-run-git "config" (and global "--global")
- "--unset" "core.notesRef")))
-
-(defun magit-notes-set-display-refs (refs &optional global)
- "Set notes refs to be display in addition to \"core.notesRef\".
-REFS is a colon separated list of notes refs. The values are
-stored in the Git variable `notes.displayRef'. With a prefix
-argument GLOBAL change the global values, else the values in
-the current repository."
- (interactive
- (list (magit-completing-read "Set additional notes ref(s)"
- (nconc (list "refs/" "refs/notes/")
- (magit-list-notes-refnames))
- nil nil
- (mapconcat #'identity
- (magit-get-all "notes.displayRef")
- ":"))
- current-prefix-arg))
- (when (and refs (atom refs))
- (setq refs (split-string refs ":")))
- (when global
- (setq global "--global"))
- (magit-git-success "config" "--unset-all" global "notes.displayRef")
- (dolist (ref refs)
- (magit-call-git "config" "--add" global "notes.displayRef" ref))
- (magit-refresh))
-
-(defun magit-notes-read-args (prompt)
- (list (magit-read-branch-or-commit prompt)
- (--when-let (--first (string-match "^--ref=\\(.+\\)" it)
- (magit-notes-arguments))
- (match-string 1 it))))
-
-(defun magit-notes-popup-read-ref (prompt &optional initial-input)
- (magit-completing-read prompt (nconc (list "refs/" "refs/notes/")
- (magit-list-notes-refnames))
- nil nil initial-input))
-
-(defun magit-notes-merging-p ()
- (let ((dir (magit-git-dir "NOTES_MERGE_WORKTREE")))
- (and (file-directory-p dir)
- (directory-files dir nil "^[^.]"))))
-
-;;;; File Mode
-
-(defvar magit-file-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "\C-xg" 'magit-status)
- (define-key map "\C-x\M-g" 'magit-dispatch-popup)
- (define-key map "\C-c\M-g" 'magit-file-popup)
- map)
- "Keymap for `magit-file-mode'.")
-
-;;;###autoload (autoload 'magit-file-popup "magit" nil t)
-(magit-define-popup magit-file-popup
- "Popup console for Magit commands in file-visiting buffers."
- :actions '((?s "Stage" magit-stage-file)
- (?d "Diff" magit-diff-buffer-file)
- (?l "Log" magit-log-buffer-file)
- (?b "Blame" magit-blame-popup)
- (?u "Unstage" magit-unstage-file)
- (?D "Diff..." magit-diff-buffer-file-popup)
- (?L "Log..." magit-log-buffer-file-popup)
- (?p "Find blob" magit-blob-previous)
- (?c "Commit" magit-commit-popup))
- :max-action-columns 4)
-
-(defvar magit-file-mode-lighter "")
-
-(define-minor-mode magit-file-mode
- "Enable some Magit features in file-visiting buffers.
-
-Currently this only adds the following key bindings.
-\n\\{magit-file-mode-map}"
- :package-version '(magit . "2.2.0")
- :lighter magit-file-mode-lighter
- :keymap magit-file-mode-map)
-
-(defun magit-file-mode-turn-on ()
- (and buffer-file-name
- (ignore-errors (magit-inside-worktree-p))
- (magit-file-mode)))
-
-;;;###autoload
-(define-globalized-minor-mode global-magit-file-mode
- magit-file-mode magit-file-mode-turn-on
- :package-version '(magit . "2.2.0")
- :group 'magit-modes)
-
-;;;; Blob Mode
-
-(defvar magit-blob-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "n" 'magit-blob-next)
- (define-key map "p" 'magit-blob-previous)
- (define-key map "q" 'magit-kill-this-buffer)
- map)
- "Keymap for `magit-blob-mode'.")
-
-(define-minor-mode magit-blob-mode
- "Enable some Magit features in blob-visiting buffers.
-
-Currently this only adds the following key bindings.
-\n\\{magit-blob-mode-map}"
- :package-version '(magit . "2.3.0"))
-
-(defun magit-blob-next ()
- "Visit the next blob which modified the current file."
- (interactive)
- (if magit-buffer-file-name
- (magit-blob-visit (or (magit-blob-successor magit-buffer-revision
- magit-buffer-file-name)
- magit-buffer-file-name)
- (line-number-at-pos))
- (if (buffer-file-name (buffer-base-buffer))
- (user-error "You have reached the end of time")
- (user-error "Buffer isn't visiting a file or blob"))))
-
-(defun magit-blob-previous ()
- "Visit the previous blob which modified the current file."
- (interactive)
- (-if-let (file (or magit-buffer-file-name
- (buffer-file-name (buffer-base-buffer))))
- (--if-let (magit-blob-ancestor magit-buffer-revision file)
- (magit-blob-visit it (line-number-at-pos))
- (user-error "You have reached the beginning of time"))
- (user-error "Buffer isn't visiting a file or blob")))
-
-(defun magit-blob-visit (blob-or-file line)
- (if (stringp blob-or-file)
- (find-file blob-or-file)
- (-let [(rev file) blob-or-file]
- (magit-find-file rev file)
- (let ((str (magit-rev-format "%ct%s" rev)))
- (message "%s (%s ago)" (substring str 10)
- (magit-format-duration
- (abs (truncate (- (float-time)
- (string-to-number
- (substring str 0 10)))))
- magit-duration-spec)))))
- (goto-char (point-min))
- (forward-line (1- line)))
-
-(defun magit-blob-ancestor (rev file)
- (let ((lines (magit-with-toplevel
- (magit-git-lines "log" "-2" "--format=%H" "--name-only"
- "--follow" (or rev "HEAD") "--" file))))
- (if rev (cddr lines) (butlast lines 2))))
-
-(defun magit-blob-successor (rev file)
- (let ((lines (magit-with-toplevel
- (magit-git-lines "log" "--format=%H" "--name-only" "--follow"
- "HEAD" "--" file))))
- (catch 'found
- (while lines
- (if (equal (nth 2 lines) rev)
- (throw 'found (list (nth 0 lines) (nth 1 lines)))
- (setq lines (nthcdr 2 lines)))))))
-
-(defun magit-kill-this-buffer ()
- "Kill the current buffer."
- (interactive)
- (kill-buffer (current-buffer)))
-
-;;;; Dispatch Popup
-
-;;;###autoload (autoload 'magit-dispatch-popup "magit" nil t)
-(magit-define-popup magit-dispatch-popup
- "Popup console for dispatching other popups."
- 'magit-commands nil nil
- :actions '("Popup and dwim commands"
- (?A "Cherry-picking" magit-cherry-pick-popup)
- (?b "Branching" magit-branch-popup)
- (?B "Bisecting" magit-bisect-popup)
- (?c "Committing" magit-commit-popup)
- (?d "Diffing" magit-diff-popup)
- (?D "Change diffs" magit-diff-refresh-popup)
- (?e "Ediff dwimming" magit-ediff-dwim)
- (?E "Ediffing" magit-ediff-popup)
- (?f "Fetching" magit-fetch-popup)
- (?F "Pulling" magit-pull-popup)
- (?l "Logging" magit-log-popup)
- (?L "Change logs" magit-log-refresh-popup)
- (?m "Merging" magit-merge-popup)
- (?M "Remoting" magit-remote-popup)
- (?o "Submodules" magit-submodule-popup)
- (?P "Pushing" magit-push-popup)
- (?r "Rebasing" magit-rebase-popup)
- (?t "Tagging" magit-tag-popup)
- (?T "Notes" magit-notes-popup)
- (?V "Reverting" magit-revert-popup)
- (?w "Apply patches" magit-am-popup)
- (?W "Format patches" magit-patch-popup)
- (?X "Resetting" magit-reset-popup)
- (?y "Show Refs" magit-show-refs-popup)
- (?z "Stashing" magit-stash-popup)
- (?! "Running" magit-run-popup)
- "Applying changes"
- (?a "Apply" magit-apply)
- (?s "Stage" magit-stage)
- (?u "Unstage" magit-unstage)
- nil
- (?v "Reverse" magit-reverse)
- (?S "Stage all" magit-stage-modified)
- (?U "Unstage all" magit-unstage-all)
- nil
- (?k "Discard" magit-discard)
- "\
- g refresh current buffer
- TAB toggle section at point
- RET visit thing at point
-
- C-h m show all key bindings" nil)
- :max-action-columns 4)
-
-;;;; Git Popup
-
-(defvar magit-git-command-history nil)
-
-;;;###autoload (autoload 'magit-run-popup "magit" nil t)
-(magit-define-popup magit-run-popup
- "Popup console for running raw Git commands."
- 'magit-commands nil nil
- :actions '((?! "Git Subcommand (in topdir)" magit-git-command-topdir)
- (?k "Gitk" magit-run-gitk)
- (?p "Git Subcommand (in pwd)" magit-git-command)
- (?a "Gitk --all" magit-run-gitk-all)
- (?s "Shell command (in topdir)" magit-shell-command-topdir)
- (?b "Gitk --branches" magit-run-gitk-branches)
- (?S "Shell command (in pwd)" magit-shell-command)
- (?g "Git Gui" magit-run-git-gui))
- :default-action 'magit-git-command
- :max-action-columns 2)
-
-;;;###autoload
-(defun magit-git-command (args directory)
- "Execute a Git subcommand asynchronously, displaying the output.
-With a prefix argument run Git in the root of the current
-repository, otherwise in `default-directory'."
- (interactive (magit-read-shell-command "Git subcommand (pwd: %s)"))
- (require 'eshell)
- (with-temp-buffer
- (insert args)
- (setq args (mapcar 'eval (eshell-parse-arguments (point-min)
- (point-max))))
- (setq default-directory directory)
- (let ((magit-git-global-arguments
- ;; A human will want globbing by default.
- (remove "--literal-pathspecs"
- magit-git-global-arguments)))
- (magit-run-git-async args)))
- (magit-process-buffer))
-
-;;;###autoload
-(defun magit-git-command-topdir (args directory)
- "Execute a Git subcommand asynchronously, displaying the output.
-Run Git in the top-level directory of the current repository.
-\n(fn)" ; arguments are for internal use
- (interactive (magit-read-shell-command "Git subcommand (pwd: %s)" t))
- (magit-git-command args directory))
-
-;;;###autoload
-(defun magit-shell-command (args directory)
- "Execute a shell command asynchronously, displaying the output.
-With a prefix argument run the command in the root of the current
-repository, otherwise in `default-directory'."
- (interactive (magit-read-shell-command "Shell command (pwd: %s)"))
- (require 'eshell)
- (with-temp-buffer
- (insert args)
- (setq args (mapcar 'eval (eshell-parse-arguments (point-min)
- (point-max))))
- (setq default-directory directory)
- (apply #'magit-start-process (car args) nil (cdr args)))
- (magit-process-buffer))
-
-;;;###autoload
-(defun magit-shell-command-topdir (args directory)
- "Execute a shell command asynchronously, displaying the output.
-Run the command in the top-level directory of the current repository.
-\n(fn)" ; arguments are for internal use
- (interactive (magit-read-shell-command "Shell command (pwd: %s)" t))
- (magit-shell-command args directory))
-
-(defun magit-read-shell-command (prompt &optional root)
- (let ((dir (if (or root current-prefix-arg)
- (or (magit-toplevel)
- (user-error "Not inside a Git repository"))
- default-directory)))
- (list (magit-read-string (format prompt (abbreviate-file-name dir))
- nil 'magit-git-command-history)
- dir)))
-
-;;;; Read Repository
-
-(defun magit-read-repository (&optional read-directory-name)
- "Read a Git repository in the minibuffer, with completion.
-
-The completion choices are the basenames of top-levels of
-repositories found in the directories specified by option
-`magit-repository-directories'. In case of name conflicts
-the basenames are prefixed with the name of the respective
-parent directories. The returned value is the actual path
-to the selected repository.
-
-With prefix argument simply read a directory name using
-`read-directory-name'."
- (if (and (not read-directory-name) magit-repository-directories)
- (let* ((repos (magit-list-repos-uniquify
- (--map (cons (file-name-nondirectory it) it)
- (magit-list-repos))))
- (reply (magit-completing-read "Git repository" repos)))
- (file-name-as-directory
- (or (cdr (assoc reply repos))
- (if (file-directory-p reply)
- (expand-file-name reply)
- (user-error "Not a repository or a directory: %s" reply)))))
- (file-name-as-directory
- (read-directory-name "Git repository: "
- (or (magit-toplevel) default-directory)))))
-
-(defun magit-list-repos ()
- (--mapcat (magit-list-repos-1 it magit-repository-directories-depth)
- magit-repository-directories))
-
-(defun magit-list-repos-1 (directory depth)
- (cond ((file-readable-p (expand-file-name ".git" directory))
- (list directory))
- ((and (> depth 0) (magit-file-accessible-directory-p directory))
- (--mapcat (when (file-directory-p it)
- (magit-list-repos-1 it (1- depth)))
- (directory-files directory t "^[^.]" t)))))
-
-(defun magit-list-repos-uniquify (alist)
- (let (result (dict (make-hash-table :test 'equal)))
- (dolist (a (delete-dups alist))
- (puthash (car a) (cons (cdr a) (gethash (car a) dict)) dict))
- (maphash
- (lambda (key value)
- (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 (- (length key))))))
- it)
- value))))))
- dict)
- result))
-
-;;;; Revision Stack
-
-(defvar magit-revision-stack nil)
-
-(defcustom magit-pop-revision-stack-format
- '("[%N: %h] " "%N: %H\n %s\n" "\\[\\([0-9]+\\)[]:]")
- "Control how `magit-pop-revision-stack' inserts a revision.
-
-The command `magit-pop-revision-stack' inserts a representation
-of the revision last pushed to the `magit-revision-stack' into
-the current buffer. It inserts text at point and/or near the end
-of the buffer, and removes the consumed revision from the stack.
-
-The entries on the stack have the format (HASH TOPLEVEL) and this
-option has the format (POINT-FORMAT EOB-FORMAT INDEX-REGEXP), all
-of which may be nil or a string (though either one of EOB-FORMAT
-or POINT-FORMAT should be a string, and if INDEX-REGEXP is
-non-nil, then the two formats should be too).
-
-First INDEX-REGEXP is used to find the previously inserted entry,
-by searching backward from point. The first submatch must match
-the index number. That number is incremented by one, and becomes
-the index number of the entry to be inserted. If you don't want
-to number the inserted revisions, then use nil for INDEX-REGEXP.
-
-If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
-should contain \"%N\", which is replaced with the number that was
-determined in the previous step.
-
-Both formats, if non-nil and after removing %N, are then expanded
-using `git show --format=FORMAT ...' inside TOPLEVEL.
-
-The expansion of POINT-FORMAT is inserted at point, and the
-expansion of EOB-FORMAT is inserted at the end of the buffer (if
-the buffer ends with a comment, then it is inserted right before
-that)."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type '(list (choice (string :tag "Insert at point format")
- (cons (string :tag "Insert at point format")
- (repeat (string :tag "Argument to git show")))
- (const :tag "Don't insert at point" nil))
- (choice (string :tag "Insert at eob format")
- (cons (string :tag "Insert at eob format")
- (repeat (string :tag "Argument to git show")))
- (const :tag "Don't insert at eob" nil))
- (choice (regexp :tag "Find index regexp")
- (const :tag "Don't number entries" nil))))
-
-(defun magit-pop-revision-stack (rev toplevel)
- "Insert a representation of a revision into the current buffer.
-
-Pop a revision from the `magit-revision-stack' and insert it into
-the current buffer according to `magit-pop-revision-stack-format'.
-Revisions can be put on the stack using `magit-copy-section-value'
-and `magit-copy-buffer-revision'.
-
-If the stack is empty or with a prefix argument instead read a
-revision in the minibuffer. By using the minibuffer history this
-allows selecting an item which was popped earlier or to insert an
-arbitrary reference or revision without first pushing it onto the
-stack.
-
-When reading the revision from the minibuffer, then it might not
-be possible to guess the correct repository. When this command
-is called inside a repository (e.g. while composing a commit
-message), then that repository is used. Otherwise (e.g. while
-composing an email) then the repository recorded for the top
-element of the stack is used (even though we insert another
-revision). If not called inside a repository and with an empty
-stack, or with two prefix arguments, then read the repository in
-the minibuffer too."
- (interactive
- (if (or current-prefix-arg (not magit-revision-stack))
- (let ((default-directory
- (or (and (not (= (prefix-numeric-value current-prefix-arg) 16))
- (or (magit-toplevel)
- (cadr (car magit-revision-stack))))
- (magit-read-repository))))
- (list (magit-read-branch-or-commit "Insert revision")
- default-directory))
- (push (caar magit-revision-stack) magit-revision-history)
- (pop magit-revision-stack)))
- (if rev
- (-let [(pnt-format eob-format idx-format) magit-pop-revision-stack-format]
- (let ((default-directory toplevel)
- (idx (and idx-format
- (save-excursion
- (if (re-search-backward idx-format nil t)
- (number-to-string
- (1+ (string-to-number (match-string 1))))
- "1"))))
- pnt-args eob-args)
- (when (listp pnt-format)
- (setq pnt-args (cdr pnt-format)
- pnt-format (car pnt-format)))
- (when (listp eob-format)
- (setq eob-args (cdr eob-format)
- eob-format (car eob-format)))
- (when pnt-format
- (when idx-format
- (setq pnt-format
- (replace-regexp-in-string "%N" idx pnt-format t t)))
- (magit-rev-insert-format pnt-format rev pnt-args)
- (backward-delete-char 1))
- (when eob-format
- (when idx-format
- (setq eob-format
- (replace-regexp-in-string "%N" idx eob-format t t)))
- (save-excursion
- (goto-char (point-max))
- (skip-syntax-backward ">s-")
- (beginning-of-line)
- (if (and comment-start (looking-at comment-start))
- (while (looking-at comment-start)
- (forward-line -1))
- (forward-line)
- (unless (= (current-column) 0)
- (insert ?\n)))
- (insert ?\n)
- (magit-rev-insert-format eob-format rev eob-args)
- (backward-delete-char 1)))))
- (user-error "Revision stack is empty")))
-
-(define-key git-commit-mode-map
- (kbd "C-c C-w") 'magit-pop-revision-stack)
-
-(defun magit-copy-section-value ()
- "Save the value of the current section for later use.
-
-Save the section value to the `kill-ring', and, provided that
-the current section is a commit, branch, or tag section, push
-the (referenced) revision to the `magit-revision-stack' for use
-with `magit-pop-revision-stack'.
-
-When the current section is a branch or a tag, and a prefix
-argument is used, then save the revision at its tip to the
-`kill-ring' instead of the reference name.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above."
- (interactive)
- (if (use-region-p)
- (copy-region-as-kill (mark) (point) 'region)
- (-when-let* ((section (magit-current-section))
- (value (magit-section-value section)))
- (magit-section-case
- ((branch commit module-commit tag)
- (let ((default-directory default-directory) ref)
- (magit-section-case
- ((branch tag)
- (setq ref value))
- (module-commit
- (setq default-directory
- (file-name-as-directory
- (expand-file-name (magit-section-parent-value section)
- (magit-toplevel))))))
- (setq value (magit-rev-parse value))
- (push (list value default-directory) magit-revision-stack)
- (kill-new (message "%s" (or (and current-prefix-arg ref)
- value)))))
- (t (kill-new (message "%s" value)))))))
-
-(defun magit-copy-buffer-revision ()
- "Save the revision of the current buffer for later use.
-
-Save the revision shown in the current buffer to the `kill-ring'
-and push it to the `magit-revision-stack'.
-
-This command is mainly intended for use in `magit-revision-mode'
-buffers, the only buffers where it is always unambiguous exactly
-which revision should be saved.
-
-Most other Magit buffers usually show more than one revision, in
-some way or another, so this command has to select one of them,
-and that choice might not always be the one you think would have
-been the best pick.
-
-In such buffers it is often more useful to save the value of
-the current section instead, using `magit-copy-section-value'.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above."
- (interactive)
- (if (use-region-p)
- (copy-region-as-kill (mark) (point) 'region)
- (-when-let (rev (cond ((memq major-mode '(magit-cherry-mode
- magit-log-select-mode
- magit-reflog-mode
- magit-refs-mode
- magit-revision-mode
- magit-stash-mode
- magit-stashes-mode))
- (car magit-refresh-args))
- ((memq major-mode '(magit-diff-mode
- magit-log-mode))
- (let ((r (caar magit-refresh-args)))
- (if (string-match "\\.\\.\\.?\\(.+\\)" r)
- (match-string 1 r)
- r)))
- ((eq major-mode 'magit-status-mode) "HEAD")))
- (when (magit-rev-verify-commit rev)
- (setq rev (magit-rev-parse rev))
- (push (list rev default-directory) magit-revision-stack)
- (kill-new (message "%s" rev))))))
-
-;;; magit.el ends soon
-
-(defconst magit-font-lock-keywords
- (eval-when-compile
- `((,(concat "(\\(magit-define-section-jumper\\)\\_>"
- "[ \t'\(]*"
- "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
- (1 'font-lock-keyword-face)
- (2 'font-lock-function-name-face nil t))
- (,(concat "(" (regexp-opt '("magit-insert-section"
- "magit-section-case"
- "magit-section-when"
- "magit-bind-match-strings"
- "magit-with-temp-index"
- "magit-with-blob"
- "magit-with-toplevel") t)
- "\\_>")
- . 1))))
-
-(font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords)
-
-(defvar magit-version 'undefined
- "The version of Magit that you're using.
-Use the function by the same name instead of this variable.")
-
-;;;###autoload
-(defun magit-version ()
- "Return the version of Magit currently in use.
-When called interactive also show the used versions of Magit,
-Git, and Emacs in the echo area."
- (interactive)
- (let ((magit-git-global-arguments nil)
- (toplib (or load-file-name buffer-file-name))
- debug)
- (unless (and toplib
- (equal (file-name-nondirectory toplib) "magit.el"))
- (setq toplib (locate-library "magit.el")))
- (push toplib debug)
- (when toplib
- (let* ((topdir (file-name-directory toplib))
- (gitdir (expand-file-name
- ".git" (file-name-directory
- (directory-file-name topdir))))
- (static (locate-library "magit-version.el" nil (list topdir))))
- (or (progn
- (push 'repo debug)
- (when (and (file-exists-p gitdir)
- ;; It is a repo, but is it the Magit repo?
- (file-exists-p
- (expand-file-name "../lisp/magit.el" gitdir)))
- (push t debug)
- ;; Inside the repo the version file should only exist
- ;; while running make.
- (when (and static (not noninteractive))
- (ignore-errors (delete-file static)))
- (setq magit-version
- (let ((default-directory topdir))
- (magit-git-string "describe" "--tags" "--dirty")))))
- (progn
- (push 'static debug)
- (when (and static (file-exists-p static))
- (push t debug)
- (load-file static)
- magit-version))
- (when (featurep 'package)
- (push 'elpa debug)
- (ignore-errors
- (--when-let (assq 'magit package-alist)
- (push t debug)
- (setq magit-version
- (and (fboundp 'package-desc-version)
- (package-version-join
- (package-desc-version (cadr it)))))))))))
- (if (stringp magit-version)
- (when (called-interactively-p 'any)
- (message "Magit %s, Git %s, Emacs %s, %s"
- (or magit-version "(unknown)")
- (or (magit-git-version t) "(unknown)")
- emacs-version
- system-type))
- (setq debug (reverse debug))
- (setq magit-version 'error)
- (when magit-version
- (push magit-version debug))
- (message "Cannot determine Magit's version %S" debug))
- magit-version))
-
-(defun magit-startup-asserts ()
- (let ((version (magit-git-version)))
- (when (and version
- (version< version magit--minimal-git)
- (not (equal (getenv "TRAVIS") "true")))
- (display-warning 'magit (format "\
-Magit requires Git >= %s, you are using %s.
-
-If this comes as a surprise to you, because you do actually have
-a newer version installed, then that probably means that the
-older version happens to appear earlier on the `$PATH'. If you
-always start Emacs from a shell, then that can be fixed in the
-shell's init file. If you start Emacs by clicking on an icon,
-or using some sort of application launcher, then you probably
-have to adjust the environment as seen by graphical interface.
-For X11 something like ~/.xinitrc should work.
-
-If you use Tramp to work inside remote Git repositories, then you
-have to make sure a suitable Git is used on the remote machines
-too.\n" magit--minimal-git version) :error)))
- (when (version< emacs-version magit--minimal-emacs)
- (display-warning 'magit (format "\
-Magit requires Emacs >= %s, you are using %s.
-
-If this comes as a surprise to you, because you do actually have
-a newer version installed, then that probably means that the
-older version happens to appear earlier on the `$PATH'. If you
-always start Emacs from a shell, then that can be fixed in the
-shell's init file. If you start Emacs by clicking on an icon,
-or using some sort of application launcher, then you probably
-have to adjust the environment as seen by graphical interface.
-For X11 something like ~/.xinitrc should work.\n"
- magit--minimal-emacs emacs-version)
- :error))
- (--each '((magit-log-edit . git-commit)
- (git-commit-mode . git-commit)
- (git-rebase-mode . git-rebase))
- (when (or (featurep (car it)) (locate-library (symbol-name (car it))))
- (display-warning 'magit (format "%s has to be removed
-
-Magit is no longer compatible with the library `%s',
-which was used in earlier releases. Please remove it, so that
-Magit can use the successor `%s' without the obsolete
-library getting in the way. Then restart Emacs.\n"
- (car it) (car it) (cdr it)) :error))))
-
-(defvar magit--remotes-using-recent-git nil)
-
-(defun magit-tramp-asserts (directory)
- (-when-let (remote (file-remote-p directory))
- (unless (member remote magit--remotes-using-recent-git)
- (-if-let (version (let ((default-directory directory))
- (magit-git-version)))
- (if (version<= magit--minimal-git version)
- (push version magit--remotes-using-recent-git)
- (display-warning 'magit (format "\
-Magit requires Git >= %s, but on %s the version is %s.
-
-If multiple Git versions are installed on the host then the
-problem might be that TRAMP uses the wrong executable.
-
-First check the value of `magit-git-executable'. Its value is
-used when running git locally as well as when running it on a
-remote host. The default value is \"git\", except on Windows
-where an absolute path is used for performance reasons.
-
-If the value already is just \"git\" but TRAMP never-the-less
-doesn't use the correct executable, then consult the info node
-`(tramp)Remote programs'.\n" magit--minimal-git remote version) :error))
- (display-warning 'magit (format "\
-Magit cannot find Git on %s.
-
-First check the value of `magit-git-executable'. Its value is
-used when running git locally as well as when running it on a
-remote host. The default value is \"git\", except on Windows
-where an absolute path is used for performance reasons.
-
-If the value already is just \"git\" but TRAMP never-the-less
-doesn't find the executable, then consult the info node
-`(tramp)Remote programs'.\n" remote) :error)))))
-
-(define-obsolete-function-alias 'global-magit-file-buffer-mode
- 'global-magit-file-mode "Magit 2.3.0")
-
-(define-obsolete-function-alias 'magit-insert-head-header
- 'magit-insert-head-branch-header "Magit 2.4.0")
-
-(define-obsolete-function-alias 'magit-insert-upstream-header
- 'magit-insert-upstream-branch-header "Magit 2.4.0")
-
-(define-obsolete-function-alias 'magit-insert-pull-branch-header
- 'magit-insert-upstream-branch-header "Magit 2.4.0")
-
-(provide 'magit)
-
-(cl-eval-when (load eval)
- (require 'magit-sequence)
- (require 'magit-commit)
- (require 'magit-remote)
- (require 'magit-bisect)
- (require 'magit-stash)
- (require 'magit-blame)
- (unless (load "magit-autoloads" t t)
- (require 'magit-submodule)
- (require 'magit-subtree)
- (require 'magit-ediff)
- (require 'magit-extras)
- (require 'git-rebase)))
-
-(if after-init-time
- (progn (magit-startup-asserts)
- (magit-version))
- (add-hook 'after-init-hook #'magit-startup-asserts t)
- (add-hook 'after-init-hook #'magit-version t))
-
-;; Local Variables:
-;; coding: utf-8
-;; indent-tabs-mode: nil
-;; End:
-;;; magit.el ends here
+++ /dev/null
-This is magit.info, produced by makeinfo version 5.2 from magit.texi.
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- You can redistribute this document and/or modify it under the terms
- of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- This document is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Magit: (magit). Using Git from Emacs with Magit.
-END-INFO-DIR-ENTRY
-
-\1f
-Indirect:
-magit.info-1: 1222
-magit.info-2: 310059
-\1f
-Tag Table:
-(Indirect)
-Node: Top\7f1222
-Node: Introduction\7f6369
-Node: Installation\7f11062
-Node: Updating from an older release\7f11437
-Node: Installing from an Elpa archive\7f13032
-Node: Installing from the Git repository\7f14371
-Node: Post-installation tasks\7f17167
-Node: Getting started\7f18556
-Node: Interface concepts\7f24291
-Node: Modes and Buffers\7f24565
-Node: Switching Buffers\7f26311
-Node: Naming Buffers\7f30969
-Node: Quitting Windows\7f33804
-Node: Automatic Refreshing of Magit Buffers\7f35436
-Node: Automatic Saving of File-Visiting Buffers\7f38204
-Node: Automatic Reverting of File-Visiting Buffers\7f39389
-Node: Risk of Reverting Automatically\7f44385
-Node: Sections\7f46768
-Node: Section movement\7f47709
-Node: Section visibility\7f51636
-Node: Section hooks\7f55227
-Node: Section types and values\7f57508
-Node: Section options\7f58778
-Node: Popup buffers and prefix commands\7f59250
-Node: Completion and confirmation\7f60564
-Node: Running Git\7f63470
-Node: Viewing Git output\7f63706
-Node: Running Git manually\7f64706
-Node: Git executable\7f66832
-Node: Global Git arguments\7f68839
-Node: Inspecting\7f69646
-Node: Status buffer\7f70773
-Node: Status sections\7f73296
-Node: Status header sections\7f78705
-Node: Status options\7f81262
-Node: Logging\7f81986
-Node: Refreshing logs\7f84722
-Node: Log Buffer\7f86107
-Node: Select from log\7f89196
-Node: Reflog\7f90136
-Node: Diffing\7f90614
-Node: Refreshing diffs\7f93634
-Node: Diff buffer\7f96615
-Node: Diff options\7f98517
-Node: Revision buffer\7f100273
-Node: Ediffing\7f101228
-Node: References buffer\7f104818
-Node: References sections\7f109528
-Node: Bisecting\7f110403
-Node: Visiting blobs\7f111899
-Node: Blaming\7f112408
-Node: Manipulating\7f115728
-Node: Repository setup\7f116044
-Node: Staging and unstaging\7f117084
-Node: Staging from file-visiting buffers\7f121173
-Node: Applying\7f122341
-Node: Committing\7f124234
-Node: Initiating a commit\7f124817
-Node: Editing commit messages\7f128129
-Node: Branching\7f138525
-Node: The two remotes\7f138725
-Node: The branch popup\7f141269
-Node: The branch config popup\7f147358
-Node: Merging\7f153264
-Node: Resolving conflicts\7f155432
-Ref: orgradiotarget1\7f156517
-Node: Rebasing\7f160389
-Node: Editing rebase sequences\7f164030
-Node: Information about in-progress rebase\7f167060
-Ref: Information about in-progress rebase-Footnote-1\7f173896
-Node: Cherry picking\7f174482
-Node: Reverting\7f176088
-Node: Resetting\7f177451
-Node: Stashing\7f178963
-Node: Transferring\7f182137
-Node: Remotes\7f182375
-Node: Fetching\7f183661
-Node: Pulling\7f185027
-Node: Pushing\7f185873
-Node: Creating and sending patches\7f190617
-Node: Applying patches\7f191312
-Node: Miscellaneous\7f192310
-Node: Tagging\7f192613
-Node: Notes\7f193398
-Node: Submodules\7f195923
-Node: Subtree\7f197235
-Node: Common commands\7f198483
-Node: Wip modes\7f200228
-Node: Minor mode for buffers visiting files\7f206964
-Node: Minor mode for buffers visiting blobs\7f210438
-Node: Customizing\7f211243
-Node: Per-repository configuration\7f212915
-Node: Essential settings\7f214549
-Node: Safety\7f214873
-Node: Performance\7f216706
-Node: Plumbing\7f224665
-Node: Calling Git\7f225293
-Node: Getting a value from Git\7f226816
-Node: Calling Git for effect\7f229920
-Node: Section plumbing\7f236424
-Node: Creating sections\7f236652
-Node: Section selection\7f240551
-Node: Matching sections\7f242231
-Node: Refreshing buffers\7f247433
-Node: Conventions\7f250568
-Node: Confirmation and completion\7f250745
-Node: Theming Faces\7f251643
-Node: FAQ\7f259794
-Node: Magit is slow\7f261407
-Node: I changed several thousand files at once and now Magit is unusable\7f261608
-Node: I am having problems committing\7f262324
-Node: Diffs are collapsed after un-/staging\7f262770
-Node: I don't understand how branching and pushing work\7f264248
-Node: I don't like the key binding in v24\7f264623
-Node: I cannot install the pre-requisites for Magit v2\7f264962
-Node: I am using an Emacs release older than v244\7f265427
-Node: I am using a Git release older than v194\7f267040
-Node: I am using MS Windows and cannot push with Magit\7f268027
-Node: I am using OS X and SOMETHING works in shell but not in Magit\7f268631
-Node: How to install the gitman info manual?\7f269422
-Node: How can I show Git's output?\7f271963
-Node: Diffs contain control sequences\7f272750
-Node: Expanding a file to show the diff causes it to disappear\7f273755
-Node: Point is wrong in the ‘COMMIT_EDITMSG’ buffer\7f274290
-Node: The mode-line information isn't always up-to-date\7f275320
-Node: Can Magit be used as ‘ediff-version-control-package’?\7f276388
-Node: How to show diffs for gpg-encrypted files?\7f278432
-Node: Emacs 245 hangs when loading Magit\7f279029
-Node: Symbol's value as function is void ‘--some’\7f279604
-Node: Where is the branch manager\7f279938
-Node: Keystroke Index\7f280229
-Node: Command Index\7f310059
-Node: Function Index\7f339776
-Node: Variable Index\7f352607
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
+++ /dev/null
-This is magit.info, produced by makeinfo version 5.2 from magit.texi.
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- You can redistribute this document and/or modify it under the terms
- of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- This document is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-INFO-DIR-SECTION Emacs
-START-INFO-DIR-ENTRY
-* Magit: (magit). Using Git from Emacs with Magit.
-END-INFO-DIR-ENTRY
-
-\1f
-File: magit.info, Node: Top, Next: Introduction, Up: (dir)
-
-Magit User Manual
-*****************
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- You can redistribute this document and/or modify it under the terms
- of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- This document is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
-* Menu:
-
-* Introduction::
-* Installation::
-* Getting started::
-* Interface concepts::
-* Inspecting::
-* Manipulating::
-* Transferring::
-* Miscellaneous::
-* Customizing::
-* Plumbing::
-* FAQ::
-* Keystroke Index::
-* Command Index::
-* Function Index::
-* Variable Index::
-
-— The Detailed Node Listing —
-
-
-Installation
-
-* Updating from an older release::
-* Installing from an Elpa archive::
-* Installing from the Git repository::
-* Post-installation tasks::
-
-
-
-
-Interface concepts
-
-* Modes and Buffers::
-* Sections::
-* Popup buffers and prefix commands::
-* Completion and confirmation::
-* Running Git::
-
-Modes and Buffers
-
-* Switching Buffers::
-* Naming Buffers::
-* Quitting Windows::
-* Automatic Refreshing of Magit Buffers::
-* Automatic Saving of File-Visiting Buffers::
-* Automatic Reverting of File-Visiting Buffers::
-
-
-Sections
-
-* Section movement::
-* Section visibility::
-* Section hooks::
-* Section types and values::
-* Section options::
-
-
-
-
-Running Git
-
-* Viewing Git output::
-* Running Git manually::
-* Git executable::
-* Global Git arguments::
-
-Inspecting
-
-* Status buffer::
-* Logging::
-* Diffing::
-* Ediffing::
-* References buffer::
-* Bisecting::
-* Visiting blobs::
-* Blaming::
-
-Status buffer
-
-* Status sections::
-* Status header sections::
-* Status options::
-
-
-Logging
-
-* Refreshing logs::
-* Log Buffer::
-* Select from log::
-* Reflog::
-
-
-Diffing
-
-* Refreshing diffs::
-* Diff buffer::
-* Diff options::
-* Revision buffer::
-
-
-
-References buffer
-
-* References sections::
-
-Manipulating
-
-* Repository setup::
-* Staging and unstaging::
-* Applying::
-* Committing::
-* Branching::
-* Merging::
-* Resolving conflicts::
-* Rebasing::
-* Cherry picking::
-* Resetting::
-* Stashing::
-
-
-Staging and unstaging
-
-* Staging from file-visiting buffers::
-
-
-
-Committing
-
-* Initiating a commit::
-* Editing commit messages::
-
-
-Branching
-
-* The two remotes::
-* The branch popup::
-* The branch config popup::
-
-
-
-
-Rebasing
-
-* Editing rebase sequences::
-* Information about in-progress rebase::
-
-
-Cherry picking
-
-* Reverting::
-
-Transferring
-
-* Remotes::
-* Fetching::
-* Pulling::
-* Pushing::
-* Creating and sending patches::
-* Applying patches::
-
-
-
-Miscellaneous
-
-* Tagging::
-* Notes::
-* Submodules::
-* Subtree::
-* Common commands::
-* Wip modes::
-* Minor mode for buffers visiting files::
-* Minor mode for buffers visiting blobs::
-
-
-
-Customizing
-
-* Per-repository configuration::
-* Essential settings::
-
-
-Essential settings
-
-* Safety::
-* Performance::
-
-Plumbing
-
-* Calling Git::
-* Section plumbing::
-* Refreshing buffers::
-* Conventions::
-
-Calling Git
-
-* Getting a value from Git::
-* Calling Git for effect::
-
-
-Section plumbing
-
-* Creating sections::
-* Section selection::
-* Matching sections::
-
-
-
-Conventions
-
-* Confirmation and completion::
-* Theming Faces::
-
-FAQ
-
-* Magit is slow::
-* I changed several thousand files at once and now Magit is unusable::
-* I am having problems committing::
-* Diffs are collapsed after un-/staging::
-* I don't understand how branching and pushing work::
-* I don’t like the key binding in v2.4: I don't like the key binding in v24.
-* I cannot install the pre-requisites for Magit v2::
-* I am using an Emacs release older than v24.4: I am using an Emacs release older than v244.
-* I am using a Git release older than v1.9.4: I am using a Git release older than v194.
-* I am using MS Windows and cannot push with Magit::
-* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
-* How to install the gitman info manual?::
-* How can I show Git's output?::
-* Diffs contain control sequences::
-* Expanding a file to show the diff causes it to disappear::
-* Point is wrong in the ‘COMMIT_EDITMSG’ buffer::
-* The mode-line information isn't always up-to-date::
-* Can Magit be used as ‘ediff-version-control-package’?::
-* How to show diffs for gpg-encrypted files?::
-* Emacs 24.5 hangs when loading Magit: Emacs 245 hangs when loading Magit.
-* Symbol's value as function is void ‘--some’::
-* Where is the branch manager::
-
-\1f
-File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
-
-1 Introduction
-**************
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Staging and otherwise applying changes is one of the most important
-features in a Git porcelain and here Magit outshines anything else,
-including Git itself. Git’s own staging interface (‘git add --patch’)
-is so cumbersome that many users only use it in exceptional cases. In
-Magit staging a hunk or even just part of a hunk is as trivial as
-staging all changes made to a file.
-
- The most visible part of Magit’s interface is the status buffer,
-which displays information about the current repository. Its content is
-created by running several Git commands and making their output
-actionable. Among other things, it displays information about the
-current branch, lists unpulled and unpushed changes and contains
-sections displaying the staged and unstaged changes. That might sound
-noisy, but, since sections are collapsible, it’s not.
-
- To stage or unstage a change one places the cursor on the change and
-then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the
-region is active (i.e. when there is a selection) several files or
-hunks, or even just part of a hunk. The change or changes that these
-commands - and many others - would act on are highlighted.
-
- Magit also implements several other "apply variants" in addition to
-staging and unstaging. One can discard or reverse a change, or apply it
-to the working tree. Git’s own porcelain only supports this for staging
-and unstaging and you would have to do something like ‘git diff ... |
-??? | git apply ...’ to discard, revert, or apply a single hunk on the
-command line. In fact that’s exactly what Magit does internally (which
-is what lead to the term "apply variants").
-
- Magit isn’t just for Git experts, but it does assume some prior
-experience with Git as well as Emacs. That being said, many users have
-reported that using Magit was what finally taught them what Git is
-capable of and how to use it to its fullest. Other users wished they
-had switched to Emacs sooner so that they would have gotten their hands
-on Magit earlier.
-
- While one has to know the basic features of Emacs to be able to make
-full use of Magit, acquiring just enough Emacs skills doesn’t take long
-and is worth it, even for users who prefer other editors. Vim users are
-advised to give Evil (https://bitbucket.org/lyro/evil/wiki/Home), the
-"Extensible VI Layer for Emacs", and Spacemacs
-(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused
-on Evil" a try.
-
- Magit provides a consistent and efficient Git porcelain. After a
-short learning period, you will be able to perform most of your daily
-version control tasks faster than you would on the command line. You
-will likely also start using features that seemed too daunting in the
-past.
-
- Magit fully embraces Git. It exposes many advanced features using a
-simple but flexible interface instead of only wrapping the trivial ones
-like many GUI clients do. Of course Magit supports logging, cloning,
-pushing, and other commands that usually don’t fail in spectacular ways;
-but it also supports tasks that often cannot be completed in a single
-step. Magit fully supports tasks such as merging, rebasing,
-cherry-picking, reverting, and blaming by not only providing a command
-to initiate these tasks but also by displaying context sensitive
-information along the way and providing commands that are useful for
-resolving conflicts and resuming the sequence after doing so.
-
- Magit wraps and in many cases improves upon at least the following
-Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’,
-‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’,
-‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’,
-‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’,
-‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’,
-‘submodule’, and ‘tag’. Many more Magit porcelain commands are
-implemented on top of Git plumbing commands.
-
-\1f
-File: magit.info, Node: Installation, Next: Getting started, Prev: Introduction, Up: Top
-
-2 Installation
-**************
-
-Magit can be installed using Emacs’ package manager or manually from its
-development repository.
-
-* Menu:
-
-* Updating from an older release::
-* Installing from an Elpa archive::
-* Installing from the Git repository::
-* Post-installation tasks::
-
-\1f
-File: magit.info, Node: Updating from an older release, Next: Installing from an Elpa archive, Up: Installation
-
-2.1 Updating from an older release
-==================================
-
-When updating from ‘1.2.*’ or ‘1.4.*’, you should first uninstall Magit
-and some of its dependencies and restart Emacs before installing the
-latest release.
-
- • The old Magit installation has to be removed because some macros
- have changed and using the old definitions when building the new
- release would lead to very strange results, including compile
- errors. This is due to a limitation in Emacs’ package manager or
- rather Emacs itself: it’s not possible to reliably unload a feature
- or even all features belonging to a package.
-
- • Furthermore the old dependencies ‘git-commit-mode’ and
- ‘git-rebase-mode’ have to be removed because they are no longer
- used by the ‘2.1.0’ release and later, and get in the way of their
- successors ‘git-commit’ and ‘git-rebase’.
-
- So please uninstall the packages ‘magit’, ‘git-commit-mode’, and
-‘git-rebase-mode’. Then quit Emacs and start a new instance. Only then
-follow the instructions in either one of the next two sections.
-
- Also note that starting with the ‘2.1.0’ release, Magit requires at
-least Emacs ‘24.4’ and Git ‘1.9.4’. You should make sure you have at
-least these releases installed before updating Magit. And if you
-connect to remote hosts using Tramp, then you should also make sure to
-install a recent enough Git version on these hosts.
-
-\1f
-File: magit.info, Node: Installing from an Elpa archive, Next: Installing from the Git repository, Prev: Updating from an older release, Up: Installation
-
-2.2 Installing from an Elpa archive
-===================================
-
-If you are updating from a release older than ‘2.1.0’, then you have to
-first uninstall the old version. See *note Updating from an older
-release: Updating from an older release.
-
- Magit is available from Melpa and Melpa-Stable. If you haven’t used
-Emacs’ package manager before, then it is high time you familiarize
-yourself with it by reading the documentation in the Emacs manual, see
-*note (emacs)Packages::. Then add one of the archives to
-‘package-archives’:
-
- • To use Melpa:
-
- (require 'package)
- (add-to-list 'package-archives
- '("melpa" . "http://melpa.org/packages/") t)
-
- • To use Melpa-Stable:
-
- (require 'package)
- (add-to-list 'package-archives
- '("melpa-stable" . "http://stable.melpa.org/packages/") t)
-
- Once you have added your preferred archive, you need to update the
-local package list using:
-
- M-x package-refresh-contents RET
-
- Once you have done that, you can install Magit and its dependencies
-using:
-
- M-x package-install RET magit RET
-
- Now see *note Post-installation tasks: Post-installation tasks.
-
-\1f
-File: magit.info, Node: Installing from the Git repository, Next: Post-installation tasks, Prev: Installing from an Elpa archive, Up: Installation
-
-2.3 Installing from the Git repository
-======================================
-
-If you are updating from a release older than ‘2.1.0’, then you have to
-first uninstall the old version. See *note Updating from an older
-release: Updating from an older release.
-
- Magit depends on the ‘dash’ and ‘with-editor’ library which are
-available from Melpa and Melpa-Stable. Install them using ‘M-x
-package-install RET <package> RET’. Of course you may also install them
-manually from their development repository, but I won’t cover that here.
-
- (An older release of Magit is also available from Marmalade, but no
-new versions will be uploaded in the future. Marmalade’s maintainer has
-stopped responding to requests from package maintainers who are having
-difficulties or require him to create an account so that they can upload
-their packages in the first place.)
-
- Then clone the Magit repository:
-
- $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit
- $ cd ~/.emacs.d/site-lisp/magit
-
- Then compile the libraries and generate the info manuals:
-
- $ make
-
- If you haven’t installed ‘dash’ and ‘with-editor’ using Elpa or at
-‘/path/to/magit/../<package>’, then you have to tell ‘make’ where to
-find them. To do so create ‘/path/to/magit/config.mk’ with the
-following content before running ‘make’:
-
- LOAD_PATH = -L /path/to/magit/lisp
- LOAD_PATH += -L /path/to/dash
- LOAD_PATH += -L /path/to/with-editor
-
- Finally add this to your init file:
-
- (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp")
- (require 'magit)
-
- (with-eval-after-load 'info
- (info-initialize)
- (add-to-list 'Info-directory-list
- "~/.emacs.d/site-lisp/magit/Documentation/"))
-
- Note that you have to add the ‘lisp’ subdirectory to the ‘load-path’,
-not the top-level of the repository, and that elements of ‘load-path’
-should not end with a slash, while those of ‘Info-directory-list’
-should.
-
- Instead of requiring the feature ‘magit’, you could load just the
-autoload definitions, by loading the file ‘magit-autoloads.el’.
-
- Instead of running Magit directly from the repository by adding that
-to the ‘load-path’, you might want to instead install it in some other
-directory using ‘sudo make install’ and setting ‘load-path’ accordingly.
-
- To update Magit use:
-
- $ git pull
- $ make
-
- At times it might be necessary to run ‘make clean all’ instead.
-
- To view all available targets use ‘make help’.
-
- Now see *note Post-installation tasks: Post-installation tasks.
-
-\1f
-File: magit.info, Node: Post-installation tasks, Prev: Installing from the Git repository, Up: Installation
-
-2.4 Post-installation tasks
-===========================
-
-After installing Magit you should verify that you are indeed using the
-Magit, Git, and Emacs releases you think you are using. It’s best to
-restart Emacs before doing so, to make sure you are not using an
-outdated value for ‘load-path’.
-
- M-x magit-version RET
-
- should display something like
-
- Magit 2.4.0, Git 2.7.0, Emacs 24.5.1
-
- Then you might also want to read about options that many users likely
-want to customize. See *note Essential settings: Essential settings.
-
- To be able to follow cross references to Git manpages found in this
-manual, you might also have to manually install the ‘gitman’ info
-manual, or advice ‘Info-follow-nearest-node’ to instead open the actual
-manpage. See *note How to install the gitman info manual?: How to
-install the gitman info manual?.
-
- If you are completely new to Magit then see *note Getting started:
-Getting started.
-
- If you have used an older Magit release before, then you should have
-a look at the release notes <https://github.com/magit/magit/releases>.
-
- And last but not least please consider making a donation, to ensure
-that I can keep working on Magit. See <http://magit.vc/donations.html>
-for various donation options.
-
-\1f
-File: magit.info, Node: Getting started, Next: Interface concepts, Prev: Installation, Up: Top
-
-3 Getting started
-*****************
-
-This section describes the most essential features that many Magitians
-use on a daily basis. It only scratches the surface but should be
-enough to get you started.
-
- (You might want to create a repository just for this walk-through,
-e.g. by cloning an existing repository. If you don’t use a separate
-repository then make sure you create a snapshot as described below).
-
- To display information about the current Git repository, type ‘M-x
-magit-status’. You will be doing that so often that it is best to bind
-this command globally:
-
- (global-set-key (kbd "C-x g") 'magit-status)
-
- Most Magit commands are commonly invoked from this buffer. It should
-be considered the primary interface to interact with Git using Magit.
-There are many other Magit buffers, but they are usually created from
-this buffer.
-
- Depending on what state your repository is in, this buffer will
-contain sections titled "Staged changes", "Unstaged changes", "Unpulled
-commits", "Unpushed commits", and/or some others.
-
- If some staged and/or unstaged changes exist, you should back them up
-now. Type ‘z’ to show the stashing popup buffer featuring various stash
-variants and arguments that can be passed to these commands. Do not
-worry about those for now, just type ‘Z’ (uppercase) to create a stash
-while also keeping the index and work tree intact. The status buffer
-should now also contain a section titled "Stashes".
-
- Otherwise, if there are no uncommitted changes, you should create
-some now by editing and saving some of the tracked files. Then go back
-to the status buffer, while at the same time refreshing it, by typing
-‘C-x g’. (When the status buffer, or any Magit buffer for that matter,
-is the current buffer, then you can also use just ‘g’ to refresh it).
-
- Move between sections using ‘p’ and ‘n’. Note that the bodies of
-some sections are hidden. Type ‘TAB’ to expand or collapse the section
-at point. You can also use ‘C-tab’ to cycle the visibility of the
-current section and its children. Move to a file section inside the
-section named "Unstaged changes" and type ‘s’ to stage the changes you
-have made to that file. That file now appears under "Staged changes".
-
- Magit can stage and unstage individual hunks, not just complete
-files. Move to the file you have just staged, expand it using ‘TAB’,
-move to one of the hunks using ‘n’, and unstage just that by typing ‘u’.
-Note how the staging (‘s’) and unstaging (‘u’) commands operate on the
-change at point. Many other commands behave the same way.
-
- You can also un-/stage just part of a hunk. Inside the body of a
-hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and
-move down until some added and removed lines fall inside the region but
-not all of them. Again type ‘s’ to stage.
-
- It’s also possible to un-/stage multiple files at once. Move to a
-file section, type ‘C-SPC’, move to the next file using ‘n’, and then
-‘s’ to stage both files. Note that both the mark and point have to be
-on the headings of sibling sections for this to work. If the region
-looks like it does in other buffers, then it doesn’t select Magit
-sections that can be acted on as a unit.
-
- And then of course you want to commit your changes. Type ‘c’. This
-shows the committing popup buffer featuring various commit variants and
-arguments that can be passed to ‘git commit’. Do not worry about those
-for now. We want to create a "normal" commit, which is done by typing
-‘c’ again.
-
- Now two new buffers appear. One is for writing the commit message,
-the other shows a diff with the changes that are about to committed.
-Write a message and then type ‘C-c C-c’ to actually create the commit.
-
- You probably don’t want to push the commit you just created because
-you just committed some random changes, but if that is not the case you
-could push it by typing ‘P’ to bring up the push popup and then ‘P’
-again to push to the configured upstream. (If the upstream is not
-configured, then you would be prompted for the push target instead.)
-
- Instead we are going to undo the changes made so far. Bring up the
-log for the current branch by typing ‘l l’, move to the last commit
-created before starting with this walk through using ‘n’, and do a hard
-reset using ‘C-u x’. *WARNING*: this discards all uncommitted changes.
-If you did not follow the advice about using a separate repository for
-these experiments and did not create a snapshot of uncommitted changes
-before starting to try out Magit, then don’t do this.
-
- So far we have mentioned the commit, push, and log popups. These are
-probably among the popups you will be using the most, but many others
-exist. To show a popup with all other popups (as well as the various
-apply commands), type ‘h’. Try a few.
-
- The key bindings in that popup correspond to the bindings in Magit
-buffers, including but not limited to the status buffer. So you could
-type ‘h d’ to bring up the diff popup, but once you remember that "d"
-stands for "diff", you would usually do so by just typing ‘d’. But the
-"popup of popups" is useful even once you have memorized all the
-bindings, as it can provide easy access to Magit commands from non-Magit
-buffers. So you should bind this globally too:
-
- (global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
-
- You might also want to enable ‘global-magit-file-mode’ (see *note
-Minor mode for buffers visiting files: Minor mode for buffers visiting
-files.).
-
-\1f
-File: magit.info, Node: Interface concepts, Next: Inspecting, Prev: Getting started, Up: Top
-
-4 Interface concepts
-********************
-
-* Menu:
-
-* Modes and Buffers::
-* Sections::
-* Popup buffers and prefix commands::
-* Completion and confirmation::
-* Running Git::
-
-\1f
-File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface concepts
-
-4.1 Modes and Buffers
-=====================
-
-Magit provides several major-modes. For each of these modes there
-usually exists only one buffer per repository. Separate modes and thus
-buffers exist for commits, diffs, logs, and some other things.
-
- Besides these special purpose buffers, there also exists an overview
-buffer, called the *status buffer*. Its usually from this buffer that
-the user invokes Git commands, or creates or visits other buffers.
-
- In this manual we often speak about "Magit buffers". By that we mean
-buffers whose major-modes derive from ‘magit-mode’.
-
-‘M-x magit-toggle-buffer-lock’ (‘magit-toggle-buffer-lock’)
-
- This command locks the current buffer to its value or if the buffer
- is already locked, then it unlocks it.
-
- Locking a buffer to its value, prevents it from being reused to
- display another value. The name of a locked buffer contains its
- value, which allows telling it apart from other locked buffers and
- the unlocked buffer.
-
- Not all Magit buffers can be locked to their values, for example it
- wouldn’t make sense to lock a status buffer.
-
- There can only be a single unlocked buffer using a certain
- major-mode per repository. So when a buffer is being unlocked and
- another unlocked buffer already exists for that mode and
- repository, then the former buffer is instead deleted and the
- latter is displayed in its place.
-
-* Menu:
-
-* Switching Buffers::
-* Naming Buffers::
-* Quitting Windows::
-* Automatic Refreshing of Magit Buffers::
-* Automatic Saving of File-Visiting Buffers::
-* Automatic Reverting of File-Visiting Buffers::
-
-\1f
-File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers
-
-4.1.1 Switching Buffers
------------------------
-
- -- Function: magit-display-buffer buffer
-
- This function is a wrapper around ‘display-buffer’ and is used to
- display any Magit buffer. It displays BUFFER in some window and,
- unlike ‘display-buffer’, also selects that window, provided
- ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks
- mentioned below.
-
- -- Variable: magit-display-buffer-noselect
-
- When this is non-nil, then ‘magit-display-buffer’ only displays the
- buffer but forgoes also selecting the window. This variable should
- not be set globally, it is only intended to be let-bound, by code
- that automatically updates "the other window". This is used for
- example when the revision buffer is updated when you move inside
- the log buffer.
-
- -- User Option: magit-display-buffer-function
-
- The function specified here is called by ‘magit-display-buffer’
- with one argument, a buffer, to actually display that buffer. This
- function should call ‘display-buffer’ with that buffer as first and
- a list of display actions as second argument.
-
- Magit provides several functions, listed below, that are suitable
- values for this option. If you want to use different rules, then a
- good way of doing that is to start with a copy of one of these
- functions and then adjust it to your needs. More functions to
- choose from will likely be added in the future, and eventually the
- default will change.
-
- Instead of using a wrapper around ‘display-buffer’, that function
- itself can be used here, in which case the display actions have to
- be specified by adding them to ‘display-buffer-alist’ instead.
-
- To learn about display actions, see *note (elisp)Choosing a Window
- for Display::.
-
- -- Function: magit-display-buffer-traditional buffer
-
- This function is the current default value of the option
- ‘magit-display-buffer-function’. Before that option and this
- function were added, the behavior was hard-coded in many places all
- over the code base but now all the rules are contained in this one
- function (except for the "noselect" special case mentioned above).
-
- -- Function: magit-display-buffer-same-window-except-diff-v1
-
- This function displays most buffers in the currently selected
- window. If a buffer’s mode derives from ‘magit-diff-mode’ or
- ‘magit-process-mode’, it is displayed in another window.
-
- -- Function: magit-display-buffer-fullframe-status-v1
-
- This function fills the entire frame when displaying a status
- buffer. Otherwise, it behaves like
- ‘magit-display-buffer-traditional’.
-
- -- Function: magit-display-buffer-fullframe-status-topleft-v1
-
- This function fills the entire frame when displaying a status
- buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’
- except that it displays buffers that derive from ‘magit-diff-mode’
- or ‘magit-process-mode’ to the top or left of the current buffer
- rather than to the bottom or right. As a result, Magit buffers
- tend to pop up on the same side as they would if
- ‘magit-display-buffer-traditional’ were in use.
-
- -- Function: magit-display-buffer-fullcolumn-most-v1
-
- This function displays most buffers so that they fill the entire
- height of the frame. However, the buffer is displayed in another
- window if 1) the buffer’s mode derives from ‘magit-process-mode’,
- or 2) the buffer’s mode derives from ‘magit-diff-mode’, provided
- that the mode of the current buffer derives from ‘magit-log-mode’
- or ‘magit-cherry-mode’.
-
- -- User Option: magit-pre-display-buffer-hook
-
- This hook is run by ‘magit-display-buffer’ before displaying the
- buffer.
-
- -- Function: magit-save-window-configuration
-
- This function saves the current window configuration. Later when
- the buffer is buried, it may be restored by
- ‘magit-restore-window-configuration’.
-
- -- User Option: magit-post-display-buffer-hook
-
- This hook is run by ‘magit-display-buffer’ after displaying the
- buffer.
-
- -- Function: magit-maybe-set-dedicated
-
- This function remembers if a new window had to be created to
- display the buffer, or whether an existing window was reused. This
- information is later used by ‘magit-mode-quit-window’, to determine
- whether the window should be deleted when its last Magit buffer is
- buried.
-
-\1f
-File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers
-
-4.1.2 Naming Buffers
---------------------
-
- -- User Option: magit-generate-buffer-name-function
-
- The function used to generate the names of Magit buffers.
-
- Such a function should take the options
- ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’
- into account. If it doesn’t, then should be clearly stated in the
- doc-string. And if it supports %-sequences beyond those mentioned
- in the doc-string of the option ‘magit-buffer-name-format’, then
- its own doc-string should describe the additions.
-
- -- Function: magit-generate-buffer-name-default-function mode
-
- This function returns a buffer name suitable for a buffer whose
- major-mode is MODE and which shows information about the repository
- in which ‘default-directory’ is located.
-
- This function uses ‘magit-buffer-name-format’ and supporting all of
- the %-sequences mentioned the documentation of that option. It
- also respects the option ‘magit-uniquify-buffer-names’.
-
- -- User Option: magit-buffer-name-format
-
- The format string used to name Magit buffers.
-
- At least the following %-sequences are supported:
-
- • ‘%m’
-
- The name of the major-mode, but with the ‘-mode’ suffix
- removed.
-
- • ‘%M’
-
- Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’.
-
- • ‘%v’
-
- The value the buffer is locked to, in parentheses, or an empty
- string if the buffer is not locked to a value.
-
- • ‘%V’
-
- Like ‘%v’, but the string is prefixed with a space, unless it
- is an empty string.
-
- • ‘%t’
-
- The top-level directory of the working tree of the repository,
- or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation
- of that.
- The value should always contain either ‘%m’ or ‘%M’, ‘%v’ or ‘%V’,
- and ‘%t’. If ‘magit-uniquify-buffer-names’ is non-nil, then the
- value must end with ‘%t’.
-
- -- User Option: magit-uniquify-buffer-names
-
- This option controls whether the names of Magit buffers are
- uniquified. If the names are not being uniquified, then they
- contain the full path of the top-level of the working tree of the
- corresponding repository. If they are being uniquified, then they
- end with the basename of the top-level, or if that would conflict
- with the name used for other buffers, then the names of all these
- buffers are adjusted until they no longer conflict.
-
- This is done using the ‘uniquify’ package; customize its options to
- control how buffer names are uniquified.
-
-\1f
-File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers
-
-4.1.3 Quitting Windows
-----------------------
-
-‘q’ (‘magit-mode-bury-buffer’)
-
- This command buries the current Magit buffer. With a prefix
- argument, it instead kills the buffer.
-
- -- User Option: magit-bury-buffer-function
-
- The function used to actually bury or kill the current buffer.
-
- ‘magit-mode-bury-buffer’ calls this function with one argument. If
- the argument is non-nil, then the function has to kill the current
- buffer. Otherwise it has to bury it alive. The default value
- currently is ‘magit-restore-window-configuration’.
-
- -- Function: magit-restore-window-configuration kill-buffer
-
- Bury or kill the current buffer using ‘quit-window’, which is
- called with KILL-BUFFER as first and the selected window as second
- argument.
-
- Then restore the window configuration that existed right before the
- current buffer was displayed in the selected frame. Unfortunately
- that also means that point gets adjusted in all the buffers, which
- are being displayed in the selected frame.
-
- -- Function: magit-mode-quit-window kill-buffer
-
- Bury or kill the current buffer using ‘quit-window’, which is
- called with KILL-BUFFER as first and the selected window as second
- argument.
-
- Then, if the window was originally created to display a Magit
- buffer and the buried buffer was the last remaining Magit buffer
- that was ever displayed in the window, then that is deleted.
-
-\1f
-File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers
-
-4.1.4 Automatic Refreshing of Magit Buffers
--------------------------------------------
-
-After running a command which may change the state of the current
-repository, the current Magit buffer and the corresponding status buffer
-are refreshed. The status buffer may optionally be automatically
-refreshed whenever a buffer is saved to a file inside the respective
-repository.
-
- Automatically refreshing Magit buffers ensures that the displayed
-information is up-to-date most of the time but can lead to a noticeable
-delay in big repositories. Other Magit buffers are not refreshed to
-keep the delay to a minimum and also because doing so can sometimes be
-undesirable.
-
- Buffers can also be refreshed explicitly, which is useful in buffers
-that weren’t current during the last refresh and after changes were made
-to the repository outside of Magit.
-
-‘g’ (‘magit-refresh’)
-
- This command refreshes the current buffer if its major mode derives
- from ‘magit-mode’ as well as the corresponding status buffer.
-
- If the option ‘magit-revert-buffers’ calls for it, then it also
- reverts all unmodified buffers that visit files being tracked in
- the current repository.
-
-‘G’ (‘magit-refresh-all’)
-
- This command refreshes all Magit buffers belonging to the current
- repository and also reverts all unmodified buffers that visit files
- being tracked in the current repository.
-
- The file-visiting buffers are always reverted, even if
- ‘magit-revert-buffers’ is nil.
-
- -- User Option: magit-refresh-buffer-hook
-
- This hook is run in each Magit buffer that was refreshed during the
- current refresh - normally the current buffer and the status
- buffer.
-
- -- User Option: magit-refresh-status-buffer
-
- When this option is non-nil, then the status buffer is
- automatically refreshed after running git for side-effects, in
- addition to the current Magit buffer, which is always refreshed
- automatically.
-
- Only set this to nil after exhausting all other options to improve
- performance.
-
- -- Function: magit-after-save-refresh-status
-
- This function is intended to be added to ‘after-save-hook’. After
- doing that the corresponding status buffer is refreshed whenever a
- buffer is saved to a file inside a repository.
-
- 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.
-
-\1f
-File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers
-
-4.1.5 Automatic Saving of File-Visiting Buffers
------------------------------------------------
-
-File-visiting buffers are by default saved at certain points in time.
-This doesn’t guarantee that Magit buffers are always up-to-date, but,
-provided one only edits files by editing them in Emacs and uses only
-Magit to interact with Git, one can be fairly confident. When in doubt
-or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh
-explicitly.
-
- -- User Option: magit-save-repository-buffers
-
- This option controls whether file-visiting buffers are saved before
- certain events.
-
- If this is non-nil then all modified file-visiting buffers
- belonging to the current repository may be saved before running
- commands, before creating new Magit buffers, and before explicitly
- refreshing such buffers. If this is ‘dontask’ then this is done
- without user intervention. If it is ‘t’ then the user has to
- confirm each save.
-
-\1f
-File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers
-
-4.1.6 Automatic Reverting of File-Visiting Buffers
---------------------------------------------------
-
-By default Magit automatically reverts buffers that are visiting files
-that are being tracked in a Git repository, after they have changed on
-disk. When using Magit one often changes files on disk by running git,
-i.e. "outside Emacs", making this a rather important feature.
-
- For example, if you discard a change in the status buffer, then that
-is done by running ‘git apply --reverse ...’, and Emacs considers the
-file to have "changed on disk". If Magit did not automatically revert
-the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in
-the visiting buffer before you could continue making changes.
-
- -- User Option: magit-auto-revert-mode
-
- When this mode is enabled, then buffers that visit tracked files,
- are automatically reverted after the visited files changed on disk.
-
- -- User Option: global-auto-revert-mode
-
- When this mode is enabled, then any file-visiting buffer is
- automatically reverted after the visited file changed on disk.
-
- If you like buffers that visit tracked files to be automatically
- reverted, then you might also like any buffer to be reverted, not
- just those visiting tracked files. If that is the case, then
- enable this mode _instead of_ ‘magit-auto-revert-mode’.
-
- -- User Option: magit-auto-revert-immediately
-
- This option controls whether Magit reverts buffers immediately.
-
- If this is non-nil and either ‘global-auto-revert-mode’ or
- ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts
- buffers by explicitly calling ‘auto-revert-buffers’ after running
- git for side-effects.
-
- If ‘auto-revert-use-notify’ is non-nil (and file notifications are
- actually supported), then ‘magit-auto-revert-immediately’ does not
- have to be non-nil, because the reverts happen immediately anyway.
-
- If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are
- both ‘nil’, then reverts happen after ‘auto-revert-interval’
- seconds of user inactivity. That is not desirable.
-
- -- User Option: auto-revert-use-notify
-
- This option controls whether file notification functions should be
- used. Note that this variable unfortunately defaults to ‘t’ even
- on systems on which file notifications cannot be used.
-
- -- User Option: magit-auto-revert-tracked-only
-
- This option controls whether ‘magit-auto-revert-mode’ only reverts
- tracked files or all files that are located inside Git
- repositories, including untracked files and files located inside
- Git’s control directory.
-
- -- Command: auto-revert-mode
-
- The global mode ‘magit-auto-revert-mode’ works by turning on this
- local mode in the appropriate buffers (but
- ‘global-auto-revert-mode’ is implemented differently). You can
- also turn it on or off manually, which might be necessary if Magit
- does not notice that a previously untracked file now is being
- tracked or vice-versa.
-
- -- User Option: auto-revert-stop-on-user-input
-
- This option controls whether the arrival of user input suspends the
- automatic reverts for ‘auto-revert-interval’ seconds.
-
- -- User Option: auto-revert-interval
-
- This option controls for how many seconds Emacs waits before
- resuming suspended reverts.
-
- -- User Option: auto-revert-buffer-list-filter
-
- This option specifies an additional filter used by
- ‘auto-revert-buffers’ to determine whether a buffer should be
- reverted or not.
-
- This option is provided by ‘magit’, which also redefines
- ‘auto-revert-buffers’ to respect it. Magit users who do not turn
- on the local mode ‘auto-revert-mode’ themselves, are best served by
- setting the value to ‘magit-auto-revert-repository-buffers-p’.
-
- However the default is nil, to not disturb users who do use the
- local mode directly. If you experience delays when running Magit
- commands, then you should consider using one of the predicates
- provided by Magit - especially if you also use Tramp.
-
- Users who do turn on ‘auto-revert-mode’ in buffers in which Magit
- doesn’t do that for them, should likely not use any filter. Users
- who turn on ‘global-auto-revert-mode’, do not have to worry about
- this option, because it is disregarded if the global mode is
- enabled.
-
- -- User Option: auto-revert-verbose
-
- This option controls whether Emacs reports when a buffer has been
- reverted.
-
- The options with the ‘auto-revert-’ prefix are located in the Custom
-group named ‘auto-revert’. The other, magit-specific, options are
-located in the ‘magit’ group.
-
-* Menu:
-
-* Risk of Reverting Automatically::
-
-\1f
-File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers
-
-Risk of Reverting Automatically
-...............................
-
-For the vast majority users automatically reverting file-visiting
-buffers after they have changed on disk is harmless.
-
- If a buffer is modified (i.e. it contains changes that haven’t been
-saved yet), then Emacs would refuse to automatically revert it. If you
-save a previously modified buffer, then that results in what is seen by
-Git as an uncommitted change. Git would then refuse to carry out any
-commands that would cause these changes to be lost. In other words, if
-there is anything that could be lost, then either Git or Emacs would
-refuse to discard the changes.
-
- However if you do use file-visiting buffers as a sort of ad hoc
-"staging area", then the automatic reverts could potentially cause data
-loss. So far I have only heard from one user who uses such a workflow.
-
- An example: You visit some file in a buffer, edit it, and save the
-changes. Then, outside of Emacs (or at least not using Magit or by
-saving the buffer) you change the file on disk again. At this point the
-buffer is the only place where the intermediate version still exists.
-You have saved the changes to disk, but that has since been overwritten.
-Meanwhile Emacs considers the buffer to be unmodified (because you have
-not made any changes to it since you last saved it to the visited file)
-and therefore would not object to it being automatically reverted. At
-this point an Auto-Revert mode would kick in. It would check whether
-the buffer is modified and since that is not the case it would revert
-it. The intermediate version would be lost. (Actually you could still
-get it back using the ‘undo’ command.)
-
- If your workflow depends on Emacs preserving the intermediate version
-in the buffer, then you have to disable all Auto-Revert modes. But
-please consider that such a workflow would be dangerous even without
-using an Auto-Revert mode, and should therefore be avoided. If Emacs
-crashed or if you quit Emacs by mistake, then you would also lose the
-buffer content. There would be no autosave file still containing the
-intermediate version (because that was deleted when you saved the
-buffer) and you would not be asked whether you want to safe the buffer
-(because it isn’t modified).
-
-\1f
-File: magit.info, Node: Sections, Next: Popup buffers and prefix commands, Prev: Modes and Buffers, Up: Interface concepts
-
-4.2 Sections
-============
-
-Magit buffers are organized into nested sections, which can be collapsed
-and expanded, similar to how sections are handled in Org mode. Each
-section also has a type, and some sections also have a value. For each
-section type there can also be a local keymap, shared by all sections of
-that type.
-
- Taking advantage of the section value and type, many commands operate
-on the current section, or when the region is active and selects
-sections of the same type, all of the selected sections. Commands that
-only make sense for a particular section type (as opposed to just
-behaving differently depending on the type) are usually bound in section
-type keymaps.
-
-* Menu:
-
-* Section movement::
-* Section visibility::
-* Section hooks::
-* Section types and values::
-* Section options::
-
-\1f
-File: magit.info, Node: Section movement, Next: Section visibility, Up: Sections
-
-4.2.1 Section movement
-----------------------
-
-To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’
-etc), whose global bindings are not shadowed. To move to another
-section use the following commands.
-
-‘p’ (‘magit-section-backward’)
-
- When not at the beginning of a section, then move to the beginning
- of the current section. At the beginning of a section, instead
- move to the beginning of the previous visible section.
-
-‘n’ (‘magit-section-forward’)
-
- Move to the beginning of the next visible section.
-
-‘M-p’ (‘magit-section-backward-siblings’)
-
- Move to the beginning of the previous sibling section. If there is
- no previous sibling section, then move to the parent section
- instead.
-
-‘M-n’ (‘magit-section-forward-siblings’)
-
- Move to the beginning of the next sibling section. If there is no
- next sibling section, then move to the parent section instead.
-
-‘^’ (‘magit-section-up’)
-
- Move to the beginning of the parent of the current section.
-
- The above commands all call the hook ‘magit-section-movement-hook’.
-And, except for the second, the below functions are all members of that
-hook’s default value.
-
- -- Variable: magit-section-movement-hook
-
- This hook is run by all of the above movement commands, after
- arriving at the destination.
-
- -- Function: magit-hunk-set-window-start
-
- This hook function ensures that the beginning of the current
- section is visible, provided it is a ‘hunk’ section. Otherwise, it
- does nothing.
-
- -- Function: magit-section-set-window-start
-
- This hook function ensures that the beginning of the current
- section is visible, regardless of the section’s type. If you add
- this to ‘magit-section-movement-hook’, then you must remove the
- hunk-only variant in turn.
-
- -- Function: magit-log-maybe-show-more-commits
-
- This hook function only has an effect in log buffers, and ‘point’
- is on the "show more" section. If that is the case, then it
- doubles the number of commits that are being shown.
-
- -- Function: magit-log-maybe-update-revision-buffer
-
- When moving inside a log buffer, then this function updates the
- revision buffer, provided it is already being displayed in another
- window of the same frame.
-
- -- Function: magit-log-maybe-update-blob-buffer
-
- When moving inside a log buffer and another window of the same
- frame displays a blob buffer, then this function instead displays
- the blob buffer for the commit at point in that window.
-
- -- Function: magit-status-maybe-update-revision-buffer
-
- When moving inside a status buffer, then this function updates the
- revision buffer, provided it is already being displayed in another
- window of the same frame.
-
- -- Function: magit-status-maybe-update-blob-buffer
-
- When moving inside a status buffer and another window of the same
- frame displays a blob buffer, then this function instead displays
- the blob buffer for the commit at point in that window.
-
- -- User Option: magit-update-other-window-delay
-
- Delay before automatically updating the other window.
-
- When moving around in certain buffers certain other buffers, which
- are being displayed in another window, may optionally be updated to
- display information about the section at point.
-
- When holding down a key to move by more than just one section, then
- that would update that buffer for each section on the way. To
- prevent that, updating the revision buffer is delayed, and this
- option controls for how long. For optimal experience you might
- have to adjust this delay and/or the keyboard repeat rate and delay
- of your graphical environment or operating system.
-
-\1f
-File: magit.info, Node: Section visibility, Next: Section hooks, Prev: Section movement, Up: Sections
-
-4.2.2 Section visibility
-------------------------
-
-Magit provides many commands for changing the visibility of sections,
-but all you need to get started are the next two.
-
-‘TAB’ (‘magit-section-toggle’)
-
- Toggle the visibility of the body of the current section.
-
-‘C-<tab>’ (‘magit-section-cycle’)
-
- Cycle the visibility of current section and its children.
-
-‘M-<tab>’ (‘magit-section-cycle-diffs’)
-
- Cycle the visibility of diff-related sections in the current
- buffer.
-
-‘s-<tab>’ (‘magit-section-cycle-global’)
-
- Cycle the visibility of all sections in the current buffer.
-
- -- Command: magit-section-show-level-1
- -- Command: magit-section-show-level-2
- -- Command: magit-section-show-level-3
- -- Command: magit-section-show-level-4
-
- To show sections surrounding the current section, up to level N,
- press the respective number key (‘1’, ‘2’, ‘3’, or ‘4’).
-
- -- Command: magit-section-show-level-1-all
- -- Command: magit-section-show-level-2-all
- -- Command: magit-section-show-level-3-all
- -- Command: magit-section-show-level-4-all
-
- To show all sections up to level N, press the respective number key
- and meta (‘M-1’, ‘M-2’, ‘M-3’, or ‘M-4’).
-
- Some functions, which are used to implement the above commands, are
-also exposed as commands themselves. By default no keys are bound to
-these commands, as they are generally perceived to be much less useful.
-But your mileage may vary.
-
- -- Command: magit-section-show
-
- Show the body of the current section.
-
- -- Command: magit-section-hide
-
- Hide the body of the current section.
-
- -- Command: magit-section-show-headings
-
- Recursively show headings of children of the current section. Only
- show the headings. Previously shown text-only bodies are hidden.
-
- -- Command: magit-section-show-children
-
- Recursively show the bodies of children of the current section.
- With a prefix argument show children down to the level of the
- current section, and hide deeper children.
-
- -- Command: magit-section-hide-children
-
- Recursively hide the bodies of children of the current section.
-
- -- Command: magit-section-toggle-children
-
- Toggle visibility of bodies of children of the current section.
-
- When a buffer is first created then some sections are shown expanded
-while others are not. This is hard coded. When a buffer is refreshed
-then the previous visibility is preserved. The initial visibility of
-certain sections can also be overwritten using the hook
-‘magit-section-set-visibility-hook’.
-
- -- Variable: magit-section-set-visibility-hook
-
- This hook is run when first creating a buffer and also when
- refreshing an existing buffer, and is used to determine the
- visibility of the section currently being inserted.
-
- Each function is called with one argument, the section being
- inserted. It should return ‘hide’ or ‘show’, or to leave the
- visibility undefined ‘nil’. If no function decides on the
- visibility and the buffer is being refreshed, then the visibility
- is preserved; or if the buffer is being created, then the hard
- coded default is used.
-
- Usually this should only be used to set the initial visibility but
- not during refreshes. If ‘magit-insert-section--oldroot’ is
- non-nil, then the buffer is being refreshed and these functions
- should immediately return ‘nil’.
-
-\1f
-File: magit.info, Node: Section hooks, Next: Section types and values, Prev: Section visibility, Up: Sections
-
-4.2.3 Section hooks
--------------------
-
-Which sections are inserted into certain buffers is controlled with
-hooks. This includes the status and the refs buffers. For other
-buffers, e.g. log, diff, and revision buffers, this is not possible.
-
- For buffers whose sections can be customized by the user, a hook
-variable called ‘magit-TYPE-sections-hook’ exists. This hook should be
-changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the
-Custom interface.
-
- The various available section hook variables are described later in
-this manual along with the appropriate "section inserter functions".
-
- -- Function: magit-add-section-hook hook function &optional at append
- local
-
- Add the function FUNCTION to the value of section hook HOOK.
-
- Add FUNCTION at the beginning of the hook list unless optional
- APPEND is non-nil, in which case FUNCTION is added at the end. If
- FUNCTION already is a member then move it to the new location.
-
- If optional AT is non-nil and a member of the hook list, then add
- FUNCTION next to that instead. Add before or after AT, or replace
- AT with FUNCTION depending on APPEND. If APPEND is the symbol
- ‘replace’, then replace AT with FUNCTION. For any other non-nil
- value place FUNCTION right after AT. If nil, then place FUNCTION
- right before AT. If FUNCTION already is a member of the list but AT
- is not, then leave FUNCTION where ever it already is.
-
- If optional LOCAL is non-nil, then modify the hook’s buffer-local
- value rather than its global value. This makes the hook local by
- copying the default value. That copy is then modified.
-
- HOOK should be a symbol. If HOOK is void, it is first set to nil.
- HOOK’s value must not be a single hook function. FUNCTION should
- be a function that takes no arguments and inserts one or multiple
- sections at point, moving point forward. FUNCTION may choose not
- to insert its section(s), when doing so would not make sense. It
- should not be abused for other side-effects.
-
- To remove a function from a section hook, use ‘remove-hook’.
-
-\1f
-File: magit.info, Node: Section types and values, Next: Section options, Prev: Section hooks, Up: Sections
-
-4.2.4 Section types and values
-------------------------------
-
-Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’.
-Instances of certain section types also have a value. The value of a
-section of type ‘file’, for example, is a file name.
-
- Users usually do not have to worry about a section’s type and value,
-but knowing them can be handy at times.
-
-‘M-x magit-describe-section’ (‘magit-describe-section’)
-
- Show information about the section at point in the echo area, as
- "VALUE [TYPE PARENT-TYPE…] BEGINNING-END".
-
- Many commands behave differently depending on the type of the section
-at point and/or somehow consume the value of that section. But that is
-only one of the reasons why the same key may do something different,
-depending on what section is current.
-
- Additionally for each section type a keymap *might* be defined, named
-‘magit-TYPE-section-map’. That keymap is used as text property keymap
-of all text belonging to any section of the respective type. If such a
-map does not exist for a certain type, then you can define it yourself,
-and it will automatically be used.
-
-\1f
-File: magit.info, Node: Section options, Prev: Section types and values, Up: Sections
-
-4.2.5 Section options
----------------------
-
-This section describes options that have an effect on more than just a
-certain type of sections. As you can see there are not many of those.
-
- -- User Option: magit-section-show-child-count
-
- Whether to append the number of children to section headings. This
- only affects sections that could benefit from this information.
-
-\1f
-File: magit.info, Node: Popup buffers and prefix commands, Next: Completion and confirmation, Prev: Sections, Up: Interface concepts
-
-4.3 Popup buffers and prefix commands
-=====================================
-
-Many Magit commands are implemented using *popup buffers*. First the
-user invokes a *popup* or *prefix* command, which causes a popup buffer
-with the available *infix* arguments and *suffix* commands to be
-displayed. The user then optionally toggles/sets some arguments and
-finally invokes one of the suffix commands.
-
- This is implemented in the library ‘magit-popup’. Earlier releases
-used the library ‘magit-key-mode’. A future release will switch to a
-yet-to-be-written successor, which will likely be named ‘transient’.
-
- Because ‘magit-popup’ can also be used by other packages without
-having to depend on all of Magit, it is documented in its own manual.
-See *note (magit-popup)Top::.
-
-‘C-c C-c’ (‘magit-dispatch-popup’)
-
- This popup command shows a buffer featuring all other Magit popup
- commands as well as some other commands that are not popup commands
- themselves.
-
- This command is also, or especially, useful outside Magit buffers, so
-you should setup a global binding:
-
- (global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
-
-\1f
-File: magit.info, Node: Completion and confirmation, Next: Running Git, Prev: Popup buffers and prefix commands, Up: Interface concepts
-
-4.4 Completion and confirmation
-===============================
-
-Many commands read a value from the user. By default this is done using
-the built-in function ‘completing-read’, but Magit can instead use
-another completion framework.
-
- -- User Option: magit-completing-read-function
-
- The value of this variable is the function used to perform
- completion. Because functions _intended_ to replace
- ‘completing-read’ often are not fully compatible drop-in
- replacements, and also because Magit expects them to add the
- default choice to the prompt themselves, such functions should not
- be used directly. Instead a wrapper function has to be used.
-
- Currently only the real ‘completing-read’ and Ido
-(http://www.emacswiki.org/emacs/InteractivelyDoThings) are fully
-supported. More frameworks will be supported in the future.
-
- -- Function: magit-builtin-completing-read prompt choices &optional
- predicate require-match initial-input hist def
-
- Perform completion using ‘completion-read’.
-
- -- Function: magit-ido-completing-read prompt choices &optional
- predicate require-match initial-input hist def
-
- Perform completion using ‘ido-completing-read+’ from the package by
- the same name (which you have to explicitly install). Ido itself
- comes with a supposed drop-in replacement ‘ido-completing-read’,
- but that has too many deficits to serve our needs.
-
- By default many commands that could potentially lead to data loss
-have to be confirmed. This includes many very common commands, so this
-can become annoying quickly. Many of these actions can be undone,
-provided ‘magit-wip-before-change-mode’ is turned on (which it is not by
-default, due to performance concerns).
-
- -- User Option: magit-no-confirm
-
- The value of this option is a list of symbols, representing
- commands which do not have to be confirmed by the user before being
- carried out.
-
- When the global mode ‘magit-wip-before-change-mode’ is enabled then
- many commands can be undone. If that mode is enabled then adding
- ‘safe-with-wip’ to this list has the same effect as adding
- ‘discard’, ‘reverse’, ‘stage-all-changes’, and
- ‘unstage-all-changes’.
-
- (add-to-list 'magit-no-confirm 'safe-with-wip)
-
- For a list of all symbols that can be added to the value of this
- variable, see the doc-string.
-
- Note that there are commands that ignore this option and always
-require confirmation, or which can be told not to do so using another
-dedicated option. Also most commands, when acting on multiple sections
-at once always, require confirmation, even when they do respect this
-option when acting on a single section.
-
-\1f
-File: magit.info, Node: Running Git, Prev: Completion and confirmation, Up: Interface concepts
-
-4.5 Running Git
-===============
-
-* Menu:
-
-* Viewing Git output::
-* Running Git manually::
-* Git executable::
-* Global Git arguments::
-
-\1f
-File: magit.info, Node: Viewing Git output, Next: Running Git manually, Up: Running Git
-
-4.5.1 Viewing Git output
-------------------------
-
-Magit runs Git either for side-effects (e.g. when pushing) or to get
-some value (e.g. the name of the current branch). When Git is run for
-side-effects then the output goes into a per-repository log buffer,
-which can be consulted when things don’t go as expected.
-
-‘$’ (‘magit-process’)
-
- This commands displays the process buffer for the current
- repository.
-
- Inside that buffer, the usual key bindings for navigating and showing
-sections are available. There is one additional command.
-
-‘k’ (‘magit-process-kill’)
-
- This command kills the process represented by the section at point.
-
- -- User Option: magit-git-debug
-
- When this is non-nil then the output of all calls to git are logged
- in the process buffer. This is useful when debugging, otherwise it
- just negatively affects performance.
-
-\1f
-File: magit.info, Node: Running Git manually, Next: Git executable, Prev: Viewing Git output, Up: Running Git
-
-4.5.2 Running Git manually
---------------------------
-
-While Magit provides many Emacs commands to interact with Git, it does
-not cover everything. In those cases your existing Git knowledge will
-come in handy. Magit provides some commands for running arbitrary Git
-commands by typing them into the minibuffer, instead of having to switch
-to a shell.
-
-‘!’ (‘magit-run-popup’)
-
- Shows the popup buffer featuring the below suffix commands.
-
- These suffix commands run a Git subcommand. The user input has to
-begin with the subcommand, "git" is assumed.
-
-‘! !’ (‘magit-git-command-topdir’)
-
- This command reads a Git subcommand from the user and executes it
- in the top-level directory of the current repository.
-
-‘! p’ (‘magit-git-command’)
-
- This command reads a Git subcommand from the user and executes it
- in ‘default-directory’. With a prefix argument the command is
- executed in the top-level directory of the current repository
- instead.
-
- These suffix commands run arbitrary shell commands.
-
-‘! s’ (‘magit-shell-command-topdir’)
-
- This command reads a shell command from the user and executes it in
- the top-level directory of the current repository.
-
-‘! S’ (‘magit-shell-command’)
-
- This command reads a shell command from the user and executes it in
- ‘default-directory’. With a prefix argument the command is
- executed in the top-level directory of the current repository
- instead.
-
- These suffix commands start external gui tools.
-
-‘! k’ (‘magit-run-gitk’)
-
- This command runs ‘gitk’ in the current repository.
-
-‘! a’ (‘magit-run-gitk-all’)
-
- This command runs ‘gitk --all’ in the current repository.
-
-‘! b’ (‘magit-run-gitk-branches’)
-
- This command runs ‘gitk --branches’ in the current repository.
-
-‘! g’ (‘magit-run-git-gui’)
-
- This command runs ‘git gui’ in the current repository.
-
-\1f
-File: magit.info, Node: Git executable, Next: Global Git arguments, Prev: Running Git manually, Up: Running Git
-
-4.5.3 Git executable
---------------------
-
-Except on MS Windows, Magit defaults to running Git without specifying
-the path to the git executable. Instead the first executable found by
-Emacs on ‘exec-path’ is used (whose value in turn is set based on the
-value of the environment variable ‘$PATH’ when Emacs was started).
-
- This has the advantage that it continues to work even when using
-Tramp to connect to a remote machine on which the executable is found in
-a different place. The downside is that if you have multiple versions
-of Git installed, then you might end up using another version than the
-one you think you are using.
-
-‘M-x magit-version’ (‘magit-version’)
-
- Shows the currently used versions of Magit, Git, and Emacs in the
- echo area. Non-interactively this just returns the Magit version.
-
- When the ‘system-type’ is ‘windows-nt’, then ‘magit-git-executable’
-is set to an absolute path when Magit is first loaded. This is
-necessary because Git on that platform comes with several wrapper
-scripts for the actual git binary, which are also placed on ‘$PATH’, and
-using one of these wrappers instead of the binary would degrade
-performance horribly.
-
- If Magit doesn’t find the correct executable then you *can* work
-around that by setting ‘magit-git-executable’ to an absolute path. But
-note that doing so is a kludge. It is better to make sure the order in
-the environment variable ‘$PATH’ is correct, and that Emacs is started
-with that environment in effect. If you have to connect from Windows to
-a non-Windows machine, then you must change the value to "git".
-
- -- User Option: magit-git-executable
-
- The git executable used by Magit, either the full path to the
- executable or the string "git" to let Emacs find the executable
- itself, using the standard mechanism for doing such things.
-
-\1f
-File: magit.info, Node: Global Git arguments, Prev: Git executable, Up: Running Git
-
-4.5.4 Global Git arguments
---------------------------
-
- -- User Option: magit-git-global-arguments
-
- The arguments set here are used every time the git executable is
- run as a subprocess. They are placed right after the executable
- itself and before the git command - as in ‘git HERE... COMMAND
- REST’. For valid arguments see *note (gitman)git:: .
-
- Be careful what you add here, especially if you are using Tramp to
- connect to servers with ancient Git versions. Never remove
- anything that is part of the default value, unless you really know
- what you are doing. And think very hard before adding something;
- it will be used every time Magit runs Git for any purpose.
-
-\1f
-File: magit.info, Node: Inspecting, Next: Manipulating, Prev: Interface concepts, Up: Top
-
-5 Inspecting
-************
-
-The functionality provided by Magit can be roughly divided into three
-groups: inspecting existing data, manipulating existing data or adding
-new data, and transferring data. Of course that is a rather crude
-distinction that often falls short, but it’s more useful than no
-distinction at all. This section is concerned with inspecting data, the
-next two with manipulating and transferring it. Then follows a section
-about miscellaneous functionality, which cannot easily be fit into this
-distinction.
-
- Of course other distinctions make sense too, e.g. Git’s distinction
-between porcelain and plumbing commands, which for the most part is
-equivalent to Emacs’ distinction between interactive commands and
-non-interactive functions. All of the sections mentioned before are
-mainly concerned with the porcelain – Magit’s plumbing layer is
-described later.
-
-* Menu:
-
-* Status buffer::
-* Logging::
-* Diffing::
-* Ediffing::
-* References buffer::
-* Bisecting::
-* Visiting blobs::
-* Blaming::
-
-\1f
-File: magit.info, Node: Status buffer, Next: Logging, Up: Inspecting
-
-5.1 Status buffer
-=================
-
-While other Magit buffers contain e.g. one particular diff or one
-particular log, the status buffer contains the diffs for staged and
-unstaged changes, logs for unpushed and unpulled commits, lists of
-stashes and untracked files, and information related to the current
-branch.
-
- During certain incomplete operations – for example when a merge
-resulted in a conflict – additional information is displayed that helps
-proceeding with or aborting the operation.
-
- The command ‘magit-status’ displays the status buffer belonging to
-the current repository in another window. This command is used so often
-that it should be bound globally. We recommend using ‘C-x g’:
-
- (global-set-key (kbd "C-x g") 'magit-status)
-
-‘C-x g’ (‘magit-status’)
-
- Show the status of the current Git repository in a buffer. With a
- prefix argument prompt for a repository to be shown. With two
- prefix arguments prompt for an arbitrary directory. If that
- directory isn’t the root of an existing repository, then offer to
- initialize it as a new repository.
-
- -- User Option: magit-repository-directories
-
- Directories containing Git repositories. Magit checks these
- directories for Git repositories and offers them as choices when
- ‘magit-status’ is used with a prefix argument.
-
- -- User Option: magit-repository-directories-depth
-
- The maximum depth to look for Git repositories. When looking for a
- Git repository below the directories in
- ‘magit-repository-directories’, only descend this many levels deep.
-
- -- Command: ido-enter-magit-status
-
- From an Ido prompt used to open a file, instead drop into
- ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which,
- despite its name, usually causes a Dired buffer to be created.
-
- To make this command available, use something like:
-
- (add-hook 'ido-setup-hook
- (lambda ()
- (define-key ido-completion-map
- (kbd \"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:
-
- (define-key ido-common-completion-map
- (kbd \"C-x g\") 'ido-enter-magit-status)
-
-* Menu:
-
-* Status sections::
-* Status header sections::
-* Status options::
-
-\1f
-File: magit.info, Node: Status sections, Next: Status header sections, Up: Status buffer
-
-5.1.1 Status sections
----------------------
-
-The contents of status buffers is controlled using the hook
-‘magit-status-sections-hook’. See *note Section hooks: Section hooks.
-to learn about such hooks and how to customize them.
-
- -- User Option: magit-status-sections-hook
-
- Hook run to insert sections into a status buffer.
-
- The first function on that hook by default is
-‘magit-insert-status-headers’; it is described in the next section. By
-default the following functions are also members of that hook:
-
- -- Function: magit-insert-merge-log
-
- Insert section for the on-going merge. Display the heads that are
- being merged. If no merge is in progress, do nothing.
-
- -- Function: magit-insert-rebase-sequence
-
- Insert section for the on-going rebase sequence. If no such
- sequence is in progress, do nothing.
-
- -- Function: magit-insert-am-sequence
-
- Insert section for the on-going patch applying sequence. If no
- such sequence is in progress, do nothing.
-
- -- Function: magit-insert-sequencer-sequence
-
- Insert section for the on-going cherry-pick or revert sequence. If
- no such sequence is in progress, do nothing.
-
- -- Function: magit-insert-bisect-output
-
- While bisecting, insert section with output from ‘git bisect’.
-
- -- Function: magit-insert-bisect-rest
-
- While bisecting, insert section visualizing the bisect state.
-
- -- Function: magit-insert-bisect-log
-
- While bisecting, insert section logging bisect progress.
-
- -- Function: magit-insert-untracked-files
-
- Maybe insert a list or tree of untracked files. Do so depending on
- the value of ‘status.showUntrackedFiles’.
-
- -- Function: magit-insert-unstaged-changes
-
- Insert section showing unstaged changes.
-
- -- Function: magit-insert-staged-changes
-
- Insert section showing staged changes.
-
- -- Function: magit-insert-stashes &optional ref heading
-
- Insert the ‘stashes’ section showing reflog for "refs/stash". If
- optional REF is non-nil show reflog for that instead. If optional
- HEADING is non-nil use that as section heading instead of
- "Stashes:".
-
- -- Function: magit-insert-unpulled-from-upstream
-
- Insert section showing commits that haven’t been pulled from the
- upstream branch yet.
-
- -- Function: magit-insert-unpulled-from-pushremote
-
- Insert section showing commits that haven’t been pulled from the
- push-remote branch yet.
-
- -- Function: magit-insert-unpushed-to-upstream
-
- Insert section showing commits that haven’t been pushed to the
- upstream yet.
-
- -- Function: magit-insert-unpushed-to-pushremote
-
- Insert section showing commits that haven’t been pushed to the
- push-remote yet.
-
- The following functions can also be added to the above hook:
-
- -- Function: magit-insert-tracked-files
-
- Insert a tree of tracked files.
-
- -- Function: magit-insert-unpulled-or-recent-commits
-
- Insert section showing unpulled or recent commits. If an upstream
- is configured for the current branch and it is ahead of the current
- branch, then show the missing commits. Otherwise, show the last
- ‘magit-log-section-commit-count’ commits.
-
- -- Function: magit-insert-recent-commits
-
- Insert section showing the last ‘magit-log-section-commit-count’
- commits.
-
- -- User Option: magit-log-section-commit-count
-
- How many recent commits ‘magit-insert-recent-commits’ and
- ‘magit-insert-unpulled-or-recent-commits’ (provided there are no
- unpulled commits) show.
-
- -- Function: magit-insert-modules-unpulled-from-upstream
-
- Insert sections for modules that haven’t been pulled from the
- upstream yet. These sections can be expanded to show the
- respective commits.
-
- -- Function: magit-insert-modules-unpulled-from-pushremote
-
- Insert sections for modules that haven’t been pulled from the
- push-remote yet. These sections can be expanded to show the
- respective commits.
-
- -- Function: magit-insert-modules-unpushed-to-upstream
-
- Insert sections for modules that haven’t been pushed to the
- upstream yet. These sections can be expanded to show the
- respective commits.
-
- -- Function: magit-insert-modules-unpushed-to-pushremote
-
- Insert sections for modules that haven’t been pushed to the
- push-remote yet. These sections can be expanded to show the
- respective commits.
-
- -- Function: magit-insert-submodules
-
- Insert sections for all modules. For each section insert the path
- and the output of ‘git describe --tags’.
-
- -- Function: magit-insert-unpulled-cherries
-
- Insert section showing unpulled commits. Like
- ‘magit-insert-unpulled-commits’ but prefix each commit that has not
- been applied yet (i.e. a commit with a patch-id not shared with
- any local commit) with "+", and all others with "-".
-
- -- Function: magit-insert-unpushed-cherries
-
- Insert section showing unpushed commits. Like
- ‘magit-insert-unpushed-commits’ but prefix each commit which has
- not been applied to upstream yet (i.e. a commit with a patch-id
- not shared with any upstream commit) with "+" and all others with
- "-".
-
- See *note References buffer: References buffer. for some more section
-inserters, which could be used here.
-
-\1f
-File: magit.info, Node: Status header sections, Next: Status options, Prev: Status sections, Up: Status buffer
-
-5.1.2 Status header sections
-----------------------------
-
-The contents of status buffers is controlled using the hook
-‘magit-status-sections-hook’, as described in the previous section. By
-default ‘magit-insert-status-headers’ is the first member of that hook
-variable.
-
- -- Function: magit-insert-status-headers
-
- Insert headers sections appropriate for ‘magit-status-mode’
- buffers. The sections are inserted by running the functions on the
- hook ‘magit-status-headers-hook’.
-
- -- User Option: magit-status-headers-hook
-
- Hook run to insert headers sections into the status buffer.
-
- This hook is run by ‘magit-insert-status-headers’, which in turn
- has to be a member of ‘magit-status-sections-hook’ to be used at
- all.
-
- By default the following functions are members of the above hook:
-
- -- Function: magit-insert-error-header
-
- Insert a header line showing the message about the Git error that
- just occurred.
-
- This function is only aware of the last error that occur when Git
- was run for side-effects. If, for example, an error occurs while
- generating a diff, then that error won’t be inserted. Refreshing
- the status buffer causes this section to disappear again.
-
- -- Function: magit-insert-diff-filter-header
-
- Insert a header line showing the effective diff filters.
-
- -- Function: magit-insert-head-branch-header
-
- Insert a header line about the current branch or detached ‘HEAD’.
-
- -- Function: magit-insert-upstream-branch-header
-
- Insert a header line about the branch that is usually pulled into
- the current branch.
-
- -- Function: magit-insert-push-branch-header
-
- Insert a header line about the branch that the current branch is
- usually pushed to.
-
- -- Function: magit-insert-tags-header
-
- Insert a header line about the current and/or next tag.
-
- The following functions can also be added to the above hook:
-
- -- Function: magit-insert-repo-header
-
- Insert a header line showing the path to the repository top-level.
-
- -- Function: magit-insert-remote-header
-
- Insert a header line about the remote of the current branch.
-
- If no remote is configured for the current branch, then fall back
- showing the "origin" remote, or if that does not exist the first
- remote in alphabetic order.
-
- -- Function: magit-insert-user-header
-
- Insert a header line about the current user.
-
-\1f
-File: magit.info, Node: Status options, Prev: Status header sections, Up: Status buffer
-
-5.1.3 Status options
---------------------
-
- -- User Option: magit-status-refresh-hook
-
- Hook run after a status buffer has been refreshed.
-
- -- User Option: magit-log-section-args
-
- Additional Git arguments used when creating log sections. Only
- ‘--graph’, ‘--decorate’, and ‘--show-signature’ are supported.
- This option is only a temporary kludge and will be removed.
-
- Note that due to an issue in Git the use of ‘--graph’ is very slow
- with long histories, so you probably don’t want to add this here.
-
- Also see the proceeding section for more options concerning status
-buffers.
-
-\1f
-File: magit.info, Node: Logging, Next: Diffing, Prev: Status buffer, Up: Inspecting
-
-5.2 Logging
-===========
-
-The status buffer contains logs for the unpushed and unpulled commits,
-but that obviously isn’t enough. The prefix command ‘magit-log-popup’,
-on ‘l’, features several suffix commands, which show a specific log in a
-separate log buffer.
-
- Like other popups, the log popup also features several arguments that
-can be changed before invoking one of the suffix commands. However in
-case of the log popup these arguments correspond to those currently in
-use in the current repository’s log buffer. When the log popup is
-invoked while no log buffer exists for the current repository yet, then
-the default value of ‘magit-log-arguments’ is used instead.
-
- For information about the various arguments, see *note
-(gitman)git-log:: . The switch ‘++order=VALUE’ is converted to one of
-‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being
-passed to ‘git log’.
-
- The log popup also features several reflog commands. See *note
-Reflog: Reflog.
-
-‘l’ (‘magit-log-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘l l’ (‘magit-log-current’)
-
- Show log for the current branch. When ‘HEAD’ is detached or with a
- prefix argument, show log for one or more revs read from the
- minibuffer.
-
-‘l o’ (‘magit-log’)
-
- Show log for one or more revs read from the minibuffer. The user
- can input any revision or revisions separated by a space, or even
- ranges, but only branches, tags, and a representation of the commit
- at point are available as completion candidates.
-
-‘l h’ (‘magit-log-head’)
-
- Show log for ‘HEAD’.
-
-‘l L’ (‘magit-log-branches’)
-
- Show log for all local branches and ‘HEAD’.
-
-‘l b’ (‘magit-log-all-branches’)
-
- Show log for all local and remote branches and ‘HEAD’.
-
-‘l a’ (‘magit-log-all’)
-
- Show log for all references and ‘HEAD’.
-
- The following related commands are not available from the popup.
-
-‘Y’ (‘magit-cherry’)
-
- Show commits in a branch that are not merged in the upstream
- branch.
-
-‘M-x magit-log-buffer-file’ (‘magit-log-buffer-file’)
-
- Show log for the file visited in the current buffer.
-
- Two additional commands that show the log for the file or blob that
-is being visited in the current buffer exists, see *note Minor mode for
-buffers visiting files: Minor mode for buffers visiting files.
-
-* Menu:
-
-* Refreshing logs::
-* Log Buffer::
-* Select from log::
-* Reflog::
-
-\1f
-File: magit.info, Node: Refreshing logs, Next: Log Buffer, Up: Logging
-
-5.2.1 Refreshing logs
----------------------
-
-The prefix command ‘magit-log-refresh-popup’, on ‘L’, can be used to
-change the log arguments used in the current buffer, without changing
-which log is shown. This works in dedicated log buffers, but also in
-the status buffer.
-
-‘L’ (‘magit-log-refresh-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘L g’ (‘magit-log-refresh’)
-
- This suffix command sets the local log arguments for the current
- buffer.
-
-‘L s’ (‘magit-log-set-default-arguments’)
-
- This suffix command sets the default log arguments for buffers of
- the same type as that of the current buffer. Other existing
- buffers of the same type are not affected because their local
- values have already been initialized.
-
-‘L w’ (‘magit-log-save-default-arguments’)
-
- This suffix command sets the default log arguments for buffers of
- the same type as that of the current buffer, and saves the value
- for future sessions. Other existing buffers of the same type are
- not affected because their local values have already been
- initialized.
-
-‘L t’ (‘magit-toggle-margin’)
-
- Show or hide the margin.
-
-\1f
-File: magit.info, Node: Log Buffer, Next: Select from log, Prev: Refreshing logs, Up: Logging
-
-5.2.2 Log Buffer
-----------------
-
-‘L’ (‘magit-log-refresh-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer. See *note
- Refreshing logs: Refreshing logs.
-
-‘q’ (‘magit-log-bury-buffer’)
-
- Bury the current buffer or the revision buffer in the same frame.
- Like ‘magit-mode-bury-buffer’ (which see) but with a negative
- prefix argument instead bury the revision buffer, provided it is
- displayed in the current frame.
-
-‘C-c C-b’ (‘magit-go-backward’)
-
- Move backward in current buffer’s history.
-
-‘C-c C-f’ (‘magit-go-forward’)
-
- Move forward in current buffer’s history.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer up. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer down. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘=’ (‘magit-log-toggle-commit-limit’)
-
- Toggle the number of commits the current log buffer is limited to.
- If the number of commits is currently limited, then remove that
- limit. Otherwise set it to 256.
-
-‘+’ (‘magit-log-double-commit-limit’)
-
- Double the number of commits the current log buffer is limited to.
-
-‘=’ (‘magit-log-half-commit-limit’)
-
- Half the number of commits the current log buffer is limited to.
-
- -- User Option: magit-log-auto-more
-
- Insert more log entries automatically when moving past the last
- entry. Only considered when moving past the last entry with
- ‘magit-goto-*-section’ commands.
-
- -- User Option: magit-log-show-margin
-
- Whether to initially show the margin in log buffers.
-
- When non-nil the author name and date are initially displayed in
- the margin of log buffers. The margin can be shown or hidden in
- the current buffer using the command ‘magit-toggle-margin’.
-
- When a log buffer contains a verbose log, then the margin is never
- displayed. In status buffers this option is ignored, but it is
- possible to show the margin using the mentioned command.
-
- -- User Option: magit-log-show-refname-after-summary
-
- Whether to show the refnames after the commit summaries. This is
- useful if you use really long branch names.
-
-\1f
-File: magit.info, Node: Select from log, Next: Reflog, Prev: Log Buffer, Up: Logging
-
-5.2.3 Select from log
----------------------
-
-When the user has to select a recent commit that is reachable from
-‘HEAD’, using regular completion would be inconvenient (because most
-humans cannot remember hashes or "HEAD~5", at least not without double
-checking). Instead a log buffer is used to select the commit, which has
-the advantage that commits are presented in order and with the commit
-message. The following additional key bindings are available when a log
-is used for selection:
-
-‘C-c C-c’ (‘magit-log-select-pick’)
-
- Select the commit at point and act on it. Call
- ‘magit-log-select-pick-function’ with the selected commit as
- argument.
-
-‘C-c C-k’ (‘magit-log-select-quit’)
-
- Abort selecting a commit, don’t act on any commit.
-
- This feature is used by rebase and squash commands.
-
-\1f
-File: magit.info, Node: Reflog, Prev: Select from log, Up: Logging
-
-5.2.4 Reflog
-------------
-
-Also see *note (gitman)git-reflog:: .
-
- These reflog commands are available from the log popup. See *note
-Logging: Logging.
-
-‘l r’ (‘magit-reflog-current’)
-
- Display the reflog of the current branch.
-
-‘l O’ (‘magit-reflog-other’)
-
- Display the reflog of a branch.
-
-‘l H’ (‘magit-reflog-head’)
-
- Display the ‘HEAD’ reflog.
-
-\1f
-File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting
-
-5.3 Diffing
-===========
-
-The status buffer contains diffs for the staged and unstaged commits,
-but that obviously isn’t enough. The prefix command ‘magit-diff-popup’,
-on ‘d’, features several suffix commands, which show a specific diff in
-a separate diff buffer.
-
- Like other popups, the diff popup also features several arguments
-that can be changed before invoking one of the suffix commands. However
-in case of the diff popup these arguments correspond to those currently
-in use in the current repository’s diff buffer. When the diff popup is
-invoked while no diff buffer exists for the current repository yet, then
-the default value of ‘magit-diff-arguments’ is used instead.
-
- Also see *note (gitman)git-diff:: .
-
-‘d’ (‘magit-diff-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘d d’ (‘magit-diff-dwim’)
-
- Show changes for the thing at point.
-
-‘d r’ (‘magit-diff’)
-
- Show differences between two commits.
-
- RANGE should be a range (A..B or A…B) but can also be a single
- commit. If one side of the range is omitted, then it defaults to
- HEAD. If just a commit is given, then changes in the working tree
- relative to that commit are shown.
-
- If the region is active, use the revisions on the first and last
- line of the region. With a prefix argument, instead of diffing the
- revisions, choose a revision to view changes along, starting at the
- common ancestor of both revisions (i.e., use a "…" range).
-
-‘d w’ (‘magit-diff-worktree’)
-
- Show changes between the current working tree and the ‘HEAD’
- commit. With a prefix argument show changes between the working
- tree and a commit read from the minibuffer.
-
-‘d s’ (‘magit-diff-staged’)
-
- Show changes between the index and the ‘HEAD’ commit. With a
- prefix argument show changes between the index and a commit read
- from the minibuffer.
-
-‘d u’ (‘magit-diff-unstaged’)
-
- Show changes between the working tree and the index.
-
-‘d p’ (‘magit-diff-paths’)
-
- Show changes between any two files on disk.
-
- All of the above suffix commands update the repository’s diff buffer.
-The diff popup also features two commands which show differences in
-another buffer:
-
-‘d c’ (‘magit-show-commit’)
-
- Show the commit at point. If there is no commit at point or with a
- prefix argument, prompt for a commit.
-
-‘d t’ (‘magit-stash-show’)
-
- Show all diffs of a stash in a buffer.
-
- Two additional commands that show the diff for the file or blob that
-is being visited in the current buffer exists, see *note Minor mode for
-buffers visiting files: Minor mode for buffers visiting files.
-
-* Menu:
-
-* Refreshing diffs::
-* Diff buffer::
-* Diff options::
-* Revision buffer::
-
-\1f
-File: magit.info, Node: Refreshing diffs, Next: Diff buffer, Up: Diffing
-
-5.3.1 Refreshing diffs
-----------------------
-
-The prefix command ‘magit-diff-refresh-popup’, on ‘D’, can be used to
-change the diff arguments used in the current buffer, without changing
-which diff is shown. This works in dedicated diff buffers, but also in
-the status buffer.
-
-‘D’ (‘magit-diff-refresh-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘D g’ (‘magit-diff-refresh’)
-
- This suffix command sets the local diff arguments for the current
- buffer.
-
-‘D s’ (‘magit-diff-set-default-arguments’)
-
- This suffix command sets the default diff arguments for buffers of
- the same type as that of the current buffer. Other existing
- buffers of the same type are not affected because their local
- values have already been initialized.
-
-‘D w’ (‘magit-diff-save-default-arguments’)
-
- This suffix command sets the default diff arguments for buffers of
- the same type as that of the current buffer, and saves the value
- for future sessions. Other existing buffers of the same type are
- not affected because their local values have already been
- initialized.
-
-‘D t’ (‘magit-diff-toggle-refine-hunk’)
-
- This command toggles hunk refinement on or off.
-
-‘D r’ (‘magit-diff-switch-range-type’)
-
- This command converts the diff range type from "revA..revB" to
- "revB…revA", or vice versa.
-
-‘D f’ (‘magit-diff-flip-revs’)
-
- This command swaps revisions in the diff range from "revA..revB" to
- "revB..revA", or vice versa.
-
- In addition to the above popup, which allows changing any of the
-supported arguments, there also exist some commands which change a
-particular argument.
-
-‘-’ (‘magit-diff-less-context’)
-
- This command decreases the context for diff hunks by COUNT lines.
-
-‘+’ (‘magit-diff-more-context’)
-
- This command increases the context for diff hunks by COUNT lines.
-
-‘0’ (‘magit-diff-default-context’)
-
- This command resets the context for diff hunks to the default
- height.
-
- The following commands quickly change what diff is being displayed
-without having to using one of the diff popups.
-
-‘C-c C-d’ (‘magit-diff-while-committing’)
-
- While committing, this command shows the changes that are about to
- be committed. While amending, invoking the command again toggles
- between showing just the new changes or all the changes that will
- be committed.
-
- This binding is available in the diff buffer as well as the commit
- message buffer.
-
-‘C-c C-b’ (‘magit-go-backward’)
-
- This command moves backward in current buffer’s history.
-
-‘C-c C-f’ (‘magit-go-forward’)
-
- This command moves forward in current buffer’s history.
-
-\1f
-File: magit.info, Node: Diff buffer, Next: Diff options, Prev: Refreshing diffs, Up: Diffing
-
-5.3.2 Diff buffer
------------------
-
-‘RET’ (‘magit-diff-visit-file’)
-
- From a diff, visit the corresponding file at the appropriate
- position.
-
- When the file is already being displayed in another window of the
- same frame, then just select that window and adjust point. With a
- prefix argument also display in another window.
-
- If the diff shows changes in the worktree, the index, or ‘HEAD’,
- then visit the actual file. Otherwise when the diff is about an
- older commit, then visit the respective blob using
- ‘magit-find-file’. Also see ‘magit-diff-visit-file-worktree’,
- which, as the name suggests, always visits the actual file.
-
-‘C-<return>’ (‘magit-diff-visit-file-worktree’)
-
- From a diff, visit the corresponding file at the appropriate
- position.
-
- When the file is already being displayed in another window of the
- same frame, then just select that window and adjust point. With a
- prefix argument also display in another window.
-
- The actual file in the worktree is visited. The positions in the
- hunk headers get less useful the "older" the changes are, and as a
- result, jumping to the appropriate position gets less reliable.
-
- Also see ‘magit-diff-visit-file-worktree’, which visits the
- respective blob, unless the diff shows changes in the worktree, the
- index, or ‘HEAD’.
-
-‘j’ (‘magit-jump-to-diffstat-or-diff’)
-
- Jump to the diffstat or diff. When point is on a file inside the
- diffstat section, then jump to the respective diff section.
- Otherwise, jump to the diffstat section or a child thereof.
-
-‘SPC’ (‘scroll-up’)
-
- Scroll text upward.
-
-‘DEL’ (‘scroll-down’)
-
- Scroll text downward.
-
-\1f
-File: magit.info, Node: Diff options, Next: Revision buffer, Prev: Diff buffer, Up: Diffing
-
-5.3.3 Diff options
-------------------
-
- -- User Option: magit-diff-refine-hunk
-
- Whether to show word-granularity differences within diff hunks.
-
- • ‘nil’ never show fine differences.
-
- • ‘t’ show fine differences for the current diff hunk only.
-
- • ‘all’ show fine differences for all displayed diff hunks.
-
- -- User Option: magit-diff-paint-whitespace
-
- Specify where to highlight whitespace errors.
-
- See ‘magit-highlight-trailing-whitespace’,
- ‘magit-highlight-indentation’. The symbol ‘t’ means in all diffs,
- ‘status’ means only in the status buffer, and nil means nowhere.
-
- -- User Option: magit-diff-highlight-trailing
-
- Whether to highlight whitespace at the end of a line in diffs.
- Used only when ‘magit-diff-paint-whitespace’ is non-nil.
-
- -- User Option: magit-diff-highlight-indentation
-
- Highlight the "wrong" indentation style. Used only when
- ‘magit-diff-paint-whitespace’ is non-nil.
-
- The value is a list of cons cells. The car is a regular
- expression, and the cdr is the value that applies to repositories
- whose directory matches the regular expression. If more than one
- element matches, then the *last* element in the list applies. The
- default value should therefore come first in the list.
-
- If the value is ‘tabs’, highlight indentation with tabs. If the
- value is an integer, highlight indentation with at least that many
- spaces. Otherwise, highlight neither.
-
- -- User Option: magit-diff-hide-trailing-cr-characters
-
- Whether to hide ^M characters at the end of a line in diffs.
-
-\1f
-File: magit.info, Node: Revision buffer, Prev: Diff options, Up: Diffing
-
-5.3.4 Revision buffer
----------------------
-
- -- User Option: magit-revision-insert-related-refs
-
- Whether to show related refs in revision buffers.
-
- -- User Option: magit-revision-show-gravatar
-
- Whether to show gravatar images in revision buffers.
-
- If non-nil, then the value has to be a cons-cell which specifies
- where the gravatar images for the author and/or the committer are
- inserted inside the text that was previously inserted according to
- ‘magit-revision-header-format’.
-
- Both cells are regular expressions. The car specifies where to
- insert the author gravatar image. The top halve of the image is
- inserted right after the matched text, the bottom halve on the next
- line at the same offset. The cdr specifies where to insert the
- committer image, accordingly. Either the car or the cdr may be
- nil.
-
-\1f
-File: magit.info, Node: Ediffing, Next: References buffer, Prev: Diffing, Up: Inspecting
-
-5.4 Ediffing
-============
-
-This section describes how to enter Ediff from Magit buffers. For
-information on how to use Ediff itself, see *note (ediff)Top::.
-
-‘e’ (‘magit-ediff-dwim’)
-
- Compare, stage, or resolve using Ediff.
-
- This command tries to guess what file, and what commit or range the
- user wants to compare, stage, or resolve using Ediff. It might
- only be able to guess either the file, or range/commit, in which
- case the user is asked about the other. It might not always guess
- right, in which case the appropriate ‘magit-ediff-*’ command has to
- be used explicitly. If it cannot read the user’s mind at all, then
- it asks the user for a command to run.
-
-‘E’ (‘magit-ediff-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer.
-
-‘E r’ (‘magit-ediff-compare’)
-
- Compare two revisions of a file using Ediff.
-
- If the region is active, use the revisions on the first and last
- line of the region. With a prefix argument, instead of diffing the
- revisions, choose a revision to view changes along, starting at the
- common ancestor of both revisions (i.e., use a "…" range).
-
-‘E m’ (‘magit-ediff-resolve’)
-
- Resolve outstanding conflicts in a file using Ediff, defaulting to
- the file at point.
-
- Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you
- can view the file’s merge-base revision using ‘/’ in the Ediff
- control buffer.
-
- In the rare event that you want to manually resolve all conflicts,
- including those already resolved by Git, use
- ‘ediff-merge-revisions-with-ancestor’.
-
-‘E s’ (‘magit-ediff-stage’)
-
- Stage and unstage changes to a file using Ediff, defaulting to the
- file at point.
-
-‘E u’ (‘magit-ediff-show-unstaged’)
-
- Show unstaged changes to a file using Ediff.
-
-‘E i’ (‘magit-ediff-show-staged’)
-
- Show staged changes to a file using Ediff.
-
-‘E w’ (‘magit-ediff-show-working-tree’)
-
- Show changes in a file between HEAD and working tree using Ediff.
-
-‘E c’ (‘magit-ediff-show-commit’)
-
- Show changes to a file introduced by a commit using Ediff.
-
-‘E z’ (‘magit-ediff-show-stash’)
-
- Show changes to a file introduced by a stash using Ediff.
-
- -- User Option: magit-ediff-dwim-show-on-hunks
-
- This option controls what command ‘magit-ediff-dwim’ calls when
- point is on uncommitted hunks. When nil, always run
- ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and
- ‘magit-ediff-show-unstaged’ to show staged and unstaged changes,
- respectively.
-
- -- User Option: magit-ediff-show-stash-with-index
-
- This option controls whether ‘magit-ediff-show-stash’ includes a
- buffer containing the file’s state in the index at the time the
- stash was created. This makes it possible to tell which changes in
- the stash were staged.
-
- -- User Option: magit-ediff-quit-hook
-
- This hook is run after quitting an Ediff session that was created
- using a Magit command. The hook functions are run inside the Ediff
- control buffer, and should not change the current buffer.
-
- This is similar to ‘ediff-quit-hook’ but takes the needs of Magit
- into account. The regular ‘ediff-quit-hook’ is ignored by Ediff
- sessions that were created using a Magit command.
-
-\1f
-File: magit.info, Node: References buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting
-
-5.5 References buffer
-=====================
-
-‘y’ (‘magit-show-refs-popup’)
-
- List and compare references in a dedicated buffer. By default all
- refs are compared with ‘HEAD’, but with a prefix argument this
- command instead acts as a prefix command and shows the following
- suffix commands along with the appropriate infix arguments in a
- popup buffer.
-
-‘y y’ (‘magit-show-refs-head’)
-
- List and compare references in a dedicated buffer. Refs are
- compared with ‘HEAD’.
-
-‘y c’ (‘magit-show-refs-current’)
-
- List and compare references in a dedicated buffer. Refs are
- compared with the current branch or ‘HEAD’ if it is detached.
-
-‘y o’ (‘magit-show-refs’)
-
- List and compare references in a dedicated buffer. Refs are
- compared with a branch read from the user.
-
- -- User Option: magit-refs-show-commit-count
-
- Whether to show commit counts in Magit-Refs mode buffers.
-
- • ‘all’ Show counts for branches and tags.
-
- • ‘branch’ Show counts for branches only.
-
- • ‘nil’ Never show counts.
- The default is ‘nil’ because anything else can be very expensive.
-
- -- User Option: magit-refs-show-margin
-
- Whether to initially show the margin in refs buffers.
-
- When non-nil the committer name and date are initially displayed in
- the margin of refs buffers. The margin can be shown or hidden in
- the current buffer using the command ‘magit-toggle-margin’.
-
- The following variables control how individual refs are displayed.
-If you change one of these variables (especially the "%c" part), then
-you should also change the others to keep things aligned. The following
-%-sequences are supported:
-
- • ‘%a’ Number of commits this ref has over the one we compare to.
-
- • ‘%b’ Number of commits the ref we compare to has over this one.
-
- • ‘%c’ Number of commits this ref has over the one we compare to.
- For the ref which all other refs are compared this is instead "@",
- if it is the current branch, or "#" otherwise.
-
- • ‘%C’ For the ref which all other refs are compared this is "@", if
- it is the current branch, or "#" otherwise. For all other refs "
- ".
-
- • ‘%h’ Hash of this ref’s tip.
-
- • ‘%m’ Commit summary of the tip of this ref.
-
- • ‘%n’ Name of this ref.
-
- • ‘%u’ Upstream of this local branch and additional local vs.
- upstream information.
-
- • ‘%U’ Upstream of this local branch.
-
- -- Variable: magit-refs-local-branch-format
-
- Format used for local branches in refs buffers.
-
- -- Variable: magit-refs-remote-branch-format
-
- Format used for remote branches in refs buffers.
-
- -- Variable: magit-refs-tags-format
-
- Format used for tags in refs buffers.
-
- -- Variable: magit-refs-indent-cherry-lines
-
- Indentation of cherries in refs buffers. This should be N-1 where
- N is taken from "%Nc" in the above format strings.
-
- Everywhere in Magit ‘RET’ visits the thing represented by the section
-at point. In almost all cases visiting is done by showing some
-information in another buffer and *not* doing anything else. In refs
-buffers ‘RET’ behaves differently, and because many users have grown
-accustomed to that inconsistency we are keeping it that way.
-
-‘RET’ (‘magit-visit-ref’)
-
- Everywhere except in refs buffers this command behaves exactly like
- ‘magit-show-commit’; it shows the commit at point in another
- buffer.
-
- In refs buffers, when there is a local branch at point, then this
- command instead checks out that branch. When there is a remote
- branch or a tag at point then the respective commit is checked out
- causing ‘HEAD’ to be detached.
-
- When a prefix argument it used, then this command only *focuses* on
- the reference at point, i.e. the commit counts and cherries are
- updated to be relative to that reference, but nothing is checked
- out.
-
- -- User Option: magit-visit-ref-create
-
- When this is non-nil and ‘magit-visit-ref’ is called inside a refs
- buffer, then it "visits" the remote branch at point by creating a
- new local branch which tracks that remote branch and then checking
- out the newly created branch.
-
- This is not enabled by default because one has to use an extremely
- loose definition of the verb "to visit" to be able to argue that
- creating and then checking out a new local branch is a form of
- visiting a remote branch.
-
-* Menu:
-
-* References sections::
-
-\1f
-File: magit.info, Node: References sections, Up: References buffer
-
-5.5.1 References sections
--------------------------
-
-The contents of references buffers is controlled using the hook
-‘magit-refs-sections-hook’. See *note Section hooks: Section hooks. to
-learn about such hooks and how to customize them. All of the below
-functions are members of the default value. Note that it makes much
-less sense to customize this hook than it does for the respective hook
-used for the status buffer.
-
- -- User Option: magit-refs-sections-hook
-
- Hook run to insert sections into a references buffer.
-
- -- Function: magit-insert-local-branches
-
- Insert sections showing all local branches.
-
- -- Function: magit-insert-remote-branches
-
- Insert sections showing all remote-tracking branches.
-
- -- Function: magit-insert-tags
-
- Insert sections showing all tags.
-
-\1f
-File: magit.info, Node: Bisecting, Next: Visiting blobs, Prev: References buffer, Up: Inspecting
-
-5.6 Bisecting
-=============
-
-Also see *note (gitman)git-bisect:: .
-
-‘B’ (‘magit-bisect-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer.
-
- When bisecting is not in progress, then the popup buffer features the
-following commands.
-
-‘B s’ (‘magit-bisect-start’)
-
- Start a bisect session.
-
- Bisecting a bug means to find the commit that introduced it. This
- command starts such a bisect session by asking for a known good and
- a bad commit.
-
-‘B u’ (‘magit-bisect-run’)
-
- Bisect automatically by running commands after each step.
-
- When bisecting is in progress, then the popup buffer features these
-commands instead.
-
-‘B b’ (‘magit-bisect-bad’)
-
- Mark the current commit as bad. Use this after you have asserted
- that the commit does contain the bug in question.
-
-‘B g’ (‘magit-bisect-good’)
-
- Mark the current commit as good. Use this after you have asserted
- that the commit does not contain the bug in question.
-
-‘B k’ (‘magit-bisect-skip’)
-
- Skip the current commit. Use this if for some reason the current
- commit is not a good one to test. This command lets Git choose a
- different one.
-
-‘B r’ (‘magit-bisect-reset’)
-
- After bisecting, cleanup bisection state and return to original
- ‘HEAD’.
-
-\1f
-File: magit.info, Node: Visiting blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting
-
-5.7 Visiting blobs
-==================
-
-‘M-x magit-find-file’ (‘magit-find-file’)
-
- View FILE from REV. Switch to a buffer visiting blob REV:FILE,
- creating one if none already exists.
-
-‘M-x magit-find-file-other-window’ (‘magit-find-file-other-window’)
-
- View FILE from REV, in another window. Like ‘magit-find-file’, but
- create a new window or reuse an existing one.
-
-\1f
-File: magit.info, Node: Blaming, Prev: Visiting blobs, Up: Inspecting
-
-5.8 Blaming
-===========
-
-Also see *note (gitman)git-blame:: .
-
-‘M-x magit-blame’ (‘magit-blame’)
-
- Display edit history of FILE up to REVISION.
-
- Interactively blame the file being visited in the current buffer.
- If the buffer visits a revision of that file, then blame up to that
- revision. Otherwise, blame the file’s full history, including
- uncommitted changes.
-
- If Magit-Blame mode is already turned on then blame recursively, by
- visiting REVISION:FILE (using ‘magit-find-file’), where revision is
- the revision before the revision that added the lines at point.
-
- ARGS is a list of additional arguments to pass to ‘git blame’; only
- arguments available from ‘magit-blame-popup’ should be used.
-
-‘M-x magit-blame-popup’ (‘magit-blame-popup’)
-
- This prefix command shows the above suffix command along with the
- appropriate infix arguments in a popup buffer.
-
-‘RET’ (‘magit-show-commit’)
-
- Show the commit at point. If there is no commit at point or with a
- prefix argument, prompt for a commit.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer up. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer down. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘n’ (‘magit-blame-next-chunk’)
-
- Move to the next chunk.
-
-‘N’ (‘magit-blame-next-chunk-same-commit’)
-
- Move to the next chunk from the same commit.
-
-‘p’ (‘magit-blame-previous-chunk’)
-
- Move to the previous chunk.
-
-‘P’ (‘magit-blame-previous-chunk-same-commit’)
-
- Move to the previous chunk from the same commit.
-
-‘q’ (‘magit-blame-quit’)
-
- Turn off Magit-Blame mode. If the buffer was created during a
- recursive blame, then also kill the buffer.
-
-‘M-w’ (‘magit-blame-copy-hash’)
-
- Save the hash of the current chunk’s commit to the kill ring.
-
-‘t’ (‘magit-blame-toggle-headings’)
-
- Show or hide blame chunk headings.
-
- -- User Option: magit-blame-heading-format
-
- Format string used for blame headings.
-
- -- User Option: magit-blame-time-format
-
- Format string used for time strings in blame headings.
-
- -- User Option: magit-blame-show-headings
-
- Whether to initially show blame block headings. The headings can
- also be toggled locally using command
- ‘magit-blame-toggle-headings’.
-
- -- User Option: magit-blame-goto-chunk-hook
-
- Hook run by ‘magit-blame-next-chunk’ and
- ‘magit-blame-previous-chunk’.
-
-\1f
-File: magit.info, Node: Manipulating, Next: Transferring, Prev: Inspecting, Up: Top
-
-6 Manipulating
-**************
-
-* Menu:
-
-* Repository setup::
-* Staging and unstaging::
-* Applying::
-* Committing::
-* Branching::
-* Merging::
-* Resolving conflicts::
-* Rebasing::
-* Cherry picking::
-* Resetting::
-* Stashing::
-
-\1f
-File: magit.info, Node: Repository setup, Next: Staging and unstaging, Up: Manipulating
-
-6.1 Repository setup
-====================
-
-‘M-x magit-init’ (‘magit-init’)
-
- This command initializes a repository and then shows the status
- buffer for the new repository.
-
- If the directory is below an existing repository, then the user has
- to confirm that a new one should be created inside. If the
- directory is the root of the existing repository, then the user has
- to confirm that it should be reinitialized.
-
-‘M-x magit-clone’ (‘magit-clone’)
-
- This command clones a repository and then shows the status buffer
- for the new repository.
-
- The user is queried for a remote url and a local directory.
-
- -- User Option: magit-clone-set-remote.pushDefault
-
- Whether to set the value of ‘remote.pushDefault’ after cloning.
-
- If ‘t’, then set without asking. If ‘nil’, then don’t set. If
- ‘ask’, then ask the user every time she clones a repository.
-
-\1f
-File: magit.info, Node: Staging and unstaging, Next: Applying, Prev: Repository setup, Up: Manipulating
-
-6.2 Staging and unstaging
-=========================
-
-Like Git, Magit can of course stage and unstage complete files. Unlike
-Git, it also allows users to gracefully un-/stage individual hunks and
-even just part of a hunk. To stage individual hunks and parts of hunks
-using Git directly, one has to use the very modal and rather clumsy
-interface of a ‘git add --interactive’ session.
-
- With Magit, on the other hand, one can un-/stage individual hunks by
-just moving point into the respective section inside a diff displayed in
-the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To
-operate on just parts of a hunk, mark the changes that should be
-un-/staged using the region and then press the same key that would be
-used to un-/stage. To stage multiple files or hunks at once use a
-region that starts inside the heading of such a section and ends inside
-the heading of a sibling section of the same type.
-
- Besides staging and unstaging, Magit also provides several other
-"apply variants" that can also operate on a file, multiple files at
-once, a hunk, multiple hunks at once, and on parts of a hunk. These
-apply variants are described in the next section.
-
- You can also use Ediff to stage and unstage. See *note Ediffing:
-Ediffing.
-
-‘s’ (‘magit-stage’)
-
- Add the change at point to the staging area.
-
- With a prefix argument and an untracked file (or files) at point,
- stage the file but not its content. This makes it possible to
- stage only a subset of the new file’s changes.
-
-‘S’ (‘magit-stage-modified’)
-
- Stage all changes to files modified in the worktree. Stage all new
- content of tracked files and remove tracked files that no longer
- exist in the working tree from the index also. With a prefix
- argument also stage previously untracked (but not ignored) files.
-
-‘u’ (‘magit-unstage’)
-
- Remove the change at point from the staging area.
-
- Only staged changes can be unstaged. But by default this command
- performs an action that is somewhat similar to unstaging, when it
- is called on a committed change: it reverses the change in the
- index but not in the working tree.
-
-‘U’ (‘magit-unstage-all’)
-
- Remove all changes from the staging area.
-
- -- User Option: magit-unstage-committed
-
- This option controls whether ‘magit-unstage’ "unstages" committed
- changes by reversing them in the index but not the working tree.
- The alternative is to raise an error.
-
-‘M-x magit-reverse-in-index’ (‘magit-reverse-in-index’)
-
- This command reverses the committed change at point in the index
- but not the working tree. By default no key is bound directly to
- this command, but it is indirectly called when ‘u’
- (‘magit-unstage’) is pressed on a committed change.
-
- This allows extracting a change from ‘HEAD’, while leaving it in
- the working tree, so that it can later be committed using a
- separate commit. A typical workflow would be:
-
- • Optionally make sure that there are no uncommitted changes.
-
- • Visit the ‘HEAD’ commit and navigate to the change that should
- not have been included in that commit.
-
- • Type ‘u’ (‘magit-unstage’) to reverse it in the index. This
- assumes that ‘magit-unstage-committed-changes’ is non-nil.
-
- • Type ‘c e’ to extend ‘HEAD’ with the staged changes, including
- those that were already staged before.
-
- • Optionally stage the remaining changes using ‘s’ or ‘S’ and
- then type ‘c c’ to create a new commit.
-
-‘M-x magit-reset-index’ (‘magit-reset-index’)
-
- Reset the index to some commit. The commit is read from the user
- and defaults to the commit at point. If there is no commit at
- point, then it defaults to ‘HEAD’.
-
-* Menu:
-
-* Staging from file-visiting buffers::
-
-\1f
-File: magit.info, Node: Staging from file-visiting buffers, Up: Staging and unstaging
-
-6.2.1 Staging from file-visiting buffers
-----------------------------------------
-
-Fine-grained un-/staging has to be done from the status or a diff
-buffer, but it’s also possible to un-/stage all changes made to the file
-visited in the current buffer right from inside that buffer.
-
-‘M-x magit-stage-file’ (‘magit-stage-file’)
-
- When invoked inside a file-visiting buffer, then stage all changes
- to that file. In a Magit buffer, stage the file at point if any.
- Otherwise prompt for a file to be staged. With a prefix argument
- always prompt the user for a file, even in a file-visiting buffer
- or when there is a file section at point.
-
-‘M-x magit-unstage-file’ (‘magit-unstage-file’)
-
- When invoked inside a file-visiting buffer, then unstage all
- changes to that file. In a Magit buffer, unstage the file at point
- if any. Otherwise prompt for a file to be unstaged. With a prefix
- argument always prompt the user for a file, even in a file-visiting
- buffer or when there is a file section at point.
-
-\1f
-File: magit.info, Node: Applying, Next: Committing, Prev: Staging and unstaging, Up: Manipulating
-
-6.3 Applying
-============
-
-Magit provides several "apply variants": stage, unstage, discard,
-reverse, and "regular apply". At least when operating on a hunk they
-are all implemented using ‘git apply’, which is why they are called
-"apply variants".
-
- • Stage. Apply a change from the working tree to the index. The
- change also remains in the working tree.
-
- • Unstage. Remove a change from the index. The change remains in
- the working tree.
-
- • Discard. On a staged change, remove it from the working tree and
- the index. On an unstaged change, remove it from the working tree
- only.
-
- • Reverse. Reverse a change in the working tree. Both committed and
- staged changes can be reversed. Unstaged changes cannot be
- reversed. Discard them instead.
-
- • Apply. Apply a change to the working tree. Both committed and
- staged changes can be applied. Unstaged changes cannot be applied
- - as they already have been applied.
-
- The previous section described the staging and unstaging commands.
-What follows are the commands which implement the remaining apply
-variants.
-
-‘a’ (‘magit-apply’)
-
- Apply the change at point to the working tree.
-
- With a prefix argument fallback to a 3-way merge. Doing so causes
- the change to be applied to the index as well.
-
-‘k’ (‘magit-discard’)
-
- Remove the change at point from the working tree.
-
-‘v’ (‘magit-reverse’)
-
- Reverse the change at point in the working tree.
-
- With a prefix argument fallback to a 3-way merge. Doing so causes
- the change to be applied to the index as well.
-
- With a prefix argument all apply variants attempt a 3-way merge when
-appropriate (i.e. when ‘git apply’ is used internally).
-
-\1f
-File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating
-
-6.4 Committing
-==============
-
-When the user initiates a commit, Magit calls ‘git commit’ without any
-arguments, so Git has to get it from the user. It creates the file
-‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit
-arranges for that editor to be the Emacsclient. Once the user finishes
-the editing session, the Emacsclient exits and Git creates the commit
-using the file’s content as message.
-
-* Menu:
-
-* Initiating a commit::
-* Editing commit messages::
-
-\1f
-File: magit.info, Node: Initiating a commit, Next: Editing commit messages, Up: Committing
-
-6.4.1 Initiating a commit
--------------------------
-
-Also see *note (gitman)git-commit:: .
-
-‘c’ (‘magit-commit-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘c c’ (‘magit-commit’)
-
- Create a new commit on ‘HEAD’. With a prefix argument amend to the
- commit at ‘HEAD’ instead.
-
-‘c a’ (‘magit-commit-amend’)
-
- Amend the last commit.
-
-‘c e’ (‘magit-commit-extend’)
-
- Amend the last commit, without editing the 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.
-
- Non-interactively respect the optional OVERRIDE-DATE argument and
- ignore the option.
-
-‘c w’ (‘magit-commit-reword’)
-
- Reword the last commit, ignoring staged changes. 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.
-
-‘c f’ (‘magit-commit-fixup’)
-
- Create a fixup commit.
-
- 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’.
-
-‘c F’ (‘magit-commit-instant-fixup’)
-
- Create a fixup commit and instantly rebase.
-
-‘c s’ (‘magit-commit-squash’)
-
- Create a squash commit, without editing the squash 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’.
-
-‘c S’ (‘magit-commit-instant-squash’)
-
- Create a squash commit and instantly rebase.
-
-‘c A’ (‘magit-commit-augment’)
-
- Create a squash commit, editing the squash 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’.
-
- -- User Option: magit-commit-ask-to-stage
-
- Whether to ask to stage everything when committing and nothing is
- staged.
-
- -- User Option: magit-commit-extend-override-date
-
- Whether using ‘magit-commit-extend’ changes the committer date.
-
- -- User Option: magit-commit-reword-override-date
-
- Whether using ‘magit-commit-reword’ changes the committer date.
-
- -- User Option: magit-commit-squash-confirm
-
- Whether the commit targeted by squash and fixup has to be
- confirmed. When non-nil then the commit at point (if any) is used
- as default choice. Otherwise it has to be confirmed. This option
- only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The
- "instant" variants always require confirmation because making an
- error while using those is harder to recover from.
-
-\1f
-File: magit.info, Node: Editing commit messages, Prev: Initiating a commit, Up: Committing
-
-6.4.2 Editing commit messages
------------------------------
-
-After initiating a commit as described in the previous section, two new
-buffers appear. One shows the changes that are about to committed,
-while the other is used to write the message. All regular editing
-commands are available in the commit message buffer. This section only
-describes the additional commands.
-
- Commit messages are edited in an edit session - in the background Git
-is waiting for the editor, in our case the Emacsclient, to save the
-commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then
-return. If the Emacsclient returns with a non-zero exit status then Git
-does not create the commit. So the most important commands are those
-for finishing and aborting the commit.
-
-‘C-c C-c’ (‘with-editor-finish’)
-
- Finish the current editing session by returning with exit code 0.
- Git then creates the commit using the message it finds in the file.
-
-‘C-c C-k’ (‘with-editor-cancel’)
-
- Cancel the current editing session by returning with exit code 1.
- Git then cancels the commit, but leaves the file untouched.
-
- In addition to being used by Git, these messages may also be stored
-in a ring that persists until Emacs is closed. By default the message
-is stored at the beginning and the end of an edit session (regardless of
-whether the session is finished successfully or was canceled). It is
-sometimes useful to bring back messages from that ring.
-
-‘C-s M-s’ (‘git-commit-save-message’)
-
- Save the current buffer content to the commit message ring.
-
-‘M-p’ (‘git-commit-prev-message’)
-
- Cycle backward through the commit message ring, after saving the
- current message to the ring. With a numeric prefix ARG, go back
- ARG comments.
-
-‘M-n’ (‘git-commit-next-message’)
-
- Cycle forward through the commit message ring, after saving the
- current message to the ring. With a numeric prefix ARG, go back
- ARG comments.
-
- By default the diff for the changes that are about to be committed
-are automatically shown when invoking the commit. When amending to an
-existing commit it may be useful to show either the changes that are
-about to be added to that commit or to show those changes together with
-those that are already committed.
-
-‘C-c C-d’ (‘magit-diff-while-committing’)
-
- While committing, show the changes that are about to be committed.
- While amending, invoking the command again toggles between showing
- just the new changes or all the changes that will be committed.
-
-‘C-c C-w’ (‘magit-pop-revision-stack’)
-
- This command inserts a representation of a revision into the
- current buffer. It can be used inside buffers used to write commit
- messages but also in other buffers such as buffers used to edit
- emails or ChangeLog files.
-
- By default this command pops the revision which was last added to
- the ‘magit-revision-stack’ and inserts it into the current buffer
- according to ‘magit-pop-revision-stack-format’. Revisions can be
- put on the stack using ‘magit-copy-section-value’ and
- ‘magit-copy-buffer-revision’.
-
- If the stack is empty or with a prefix argument it instead reads a
- revision in the minibuffer. By using the minibuffer history this
- allows selecting an item which was popped earlier or to insert an
- arbitrary reference or revision without first pushing it onto the
- stack.
-
- When reading the revision from the minibuffer, then it might not be
- possible to guess the correct repository. When this command is
- called inside a repository (e.g. while composing a commit
- message), then that repository is used. Otherwise (e.g. while
- composing an email) then the repository recorded for the top
- element of the stack is used (even though we insert another
- revision). If not called inside a repository and with an empty
- stack, or with two prefix arguments, then read the repository in
- the minibuffer too.
-
- -- User Option: magit-pop-revision-stack-format
-
- This option controls how the command ‘magit-pop-revision-stack’
- inserts a revision into the current buffer.
-
- The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this
- option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all
- of which may be nil or a string (though either one of EOB-FORMAT or
- POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil,
- then the two formats should be too).
-
- First INDEX-REGEXP is used to find the previously inserted entry,
- by searching backward from point. The first submatch must match
- the index number. That number is incremented by one, and becomes
- the index number of the entry to be inserted. If you don’t want to
- number the inserted revisions, then use nil for INDEX-REGEXP.
-
- If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
- should contain \"%N\", which is replaced with the number that was
- determined in the previous step.
-
- Both formats, if non-nil and after removing %N, are then expanded
- using ‘git show –format=FORMAT …’ inside TOPLEVEL.
-
- The expansion of POINT-FORMAT is inserted at point, and the
- expansion of EOB-FORMAT is inserted at the end of the buffer (if
- the buffer ends with a comment, then it is inserted right before
- that).
-
- Some projects use pseudo headers in commit messages. Magit colorizes
-such headers and provides some commands to insert such headers.
-
- -- User Option: git-commit-known-pseudo-headers
-
- A list of Git pseudo headers to be highlighted.
-
-‘C-c C-a’ (‘git-commit-ack’)
-
- Insert a header acknowledging that you have looked at the commit.
-
-‘C-c C-r’ (‘git-commit-review’)
-
- Insert a header acknowledging that you have reviewed the commit.
-
-‘C-c C-s’ (‘git-commit-signoff’)
-
- Insert a header to sign off the commit.
-
-‘C-c C-t’ (‘git-commit-test’)
-
- Insert a header acknowledging that you have tested the commit.
-
-‘C-c C-o’ (‘git-commit-cc’)
-
- Insert a header mentioning someone who might be interested.
-
-‘C-c C-p’ (‘git-commit-reported’)
-
- Insert a header mentioning the person who reported the issue being
- fixed by the commit.
-
-‘C-c C-i’ (‘git-commit-suggested’)
-
- Insert a header mentioning the person who suggested the change.
-
- ‘git-commit-mode’ is a minor mode that is only used to establish the
-above key bindings. This allows using an arbitrary major mode when
-editing the commit message. It’s even possible to use a different major
-mode in different repositories, which is useful when different projects
-impose different commit message conventions.
-
- -- User Option: git-commit-major-mode
-
- The value of this option is the major mode used to edit Git commit
- messages.
-
- Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook
-to setup the buffer, except for the key bindings. All other setup
-happens in the function ‘git-commit-setup’, which among other things
-runs the hook ‘git-commit-setup-hook’. The following functions are
-suitable for that hook.
-
- -- User Option: git-commit-setup-hook
-
- Hook run at the end of ‘git-commit-setup’.
-
- -- Function: magit-revert-buffers &optional force
-
- Revert unmodified file-visiting buffers of the current repository.
-
- If either ‘magit-revert-buffers’ is non-nil and
- ‘inhibit-magit-revert’ is nil, or if optional FORCE is non-nil,
- then revert all unmodified buffers that visit files being tracked
- in the current repository.
-
- -- Function: git-commit-save-message
-
- Save the current buffer content to the commit message ring.
-
- -- Function: git-commit-setup-changelog-support
-
- After this function is called, ChangeLog entries are treated as
- paragraphs.
-
- -- Function: git-commit-turn-on-auto-fill
-
- Turn on ‘auto-fill-mode’ and set ‘fill-column’ to the value of
- ‘git-commit-fill-column’.
-
- -- Function: git-commit-turn-on-flyspell
-
- Turn on Flyspell mode. Also prevent comments from being checked
- and finally check current non-comment text.
-
- -- Function: git-commit-propertize-diff
-
- Propertize the diff shown inside the commit message buffer. Git
- inserts such diffs into the commit message template when the
- ‘--verbose’ argument is used. Magit’s commit popup by default does
- not offer that argument because the diff that is shown in a
- separate buffer is more useful. But some users disagree, which is
- why this function exists.
-
- -- Function: with-editor-usage-message
-
- Show usage information in the echo area.
-
- Magit also helps with writing *good* commit messages by complaining
-when certain rules are violated.
-
- -- User Option: git-commit-summary-max-length
-
- The intended maximal length of the summary line of commit messages.
- Characters beyond this column are colorized to indicate that this
- preference has been violated.
-
- -- User Option: git-commit-fill-column
-
- Column beyond which automatic line-wrapping should happen in commit
- message buffers.
-
- -- User Option: git-commit-finish-query-functions
-
- List of functions called to query before performing commit.
-
- The commit message buffer is current while the functions are
- called. If any of them returns nil, then the commit is not
- performed and the buffer is not killed. The user should then fix
- the issue and try again.
-
- The functions are called with one argument. If it is non-nil then
- that indicates that the user used a prefix argument to force
- finishing the session despite issues. Functions should usually
- honor this wish and return non-nil.
-
- -- Function: git-commit-check-style-conventions
-
- Check for violations of certain basic style conventions. For each
- violation ask the user if she wants to proceed anyway. This makes
- sure the summary line isn’t too long and that the second line is
- empty.
-
- To show no diff while committing remove ‘magit-commit-diff’ from
-‘server-switch-hook’.
-
-\1f
-File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating
-
-6.5 Branching
-=============
-
-* Menu:
-
-* The two remotes::
-* The branch popup::
-* The branch config popup::
-
-\1f
-File: magit.info, Node: The two remotes, Next: The branch popup, Up: Branching
-
-6.5.1 The two remotes
----------------------
-
-The upstream branch of some local branch is the branch into which the
-commits on that local branch should eventually be merged, usually
-something like ‘origin/master’. For the ‘master’ branch itself the
-upstream branch and the branch it is being pushed to, are usually the
-same remote branch. But for a feature branch the upstream branch and
-the branch it is being pushed to should differ.
-
- Feature branches too should _eventually_ end up in a remote branch
-such as ‘origin/master’ or ‘origin/maint’. Such a branch should
-therefore be used as the upstream. But feature branches shouldn’t be
-pushed directly to such branches. Instead a feature branch ‘my-feature’
-is usually pushed to ‘my-fork/my-feature’ or ‘origin/my-feature’. After
-the new feature has been reviewed, the maintainer merges the feature
-into ‘master’. And finally ‘master’ (not ‘my-feature’ itself) is pushed
-to ‘origin/master’.
-
- But new features seldom are perfect on the first try, and so feature
-branches usually have to be improved and re-pushed many times. Pushing
-should therefore be easy to do, and for that reason some users have
-concluded that the remote branch to which a feature branch is being
-pushed should be set as the upstream. Luckily Git has long ago gained
-support for a push-remote which can be configured separately from the
-upstream branch, using the variables ‘branch.<name>.pushRemote’ and
-‘remote.pushDefault’, so we no longer have to choose which of the two
-remotes should be used as "the remote".
-
- Each of the fetching, pulling, and pushing popups features three
-commands which act on the current branch and some other branch. Of
-these, ‘p’ is bound to a command which acts on the push-remote, ‘u’ is
-bound to a command which acts on the upstream, and ‘e’ is bound to a
-command which acts on any other branch. The status buffer shows
-unpushed and unpulled for both the push-remote and the upstream.
-
- It’s fairly simple to configure these two remotes. The values of all
-the variables that are related to fetching, pulling, and pushing (as
-well as some other branch-related variables) can be inspected and
-changed using the popup ‘magit-branch-config-popup’, which is a
-sub-popup of many popups that deal with branches. It is also possible
-to set the push-remote and/or upstream while pushing (see *note Pushing:
-Pushing.).
-
-\1f
-File: magit.info, Node: The branch popup, Next: The branch config popup, Prev: The two remotes, Up: Branching
-
-6.5.2 The branch popup
-----------------------
-
-The popup ‘magit-branch-popup’ is used to create and checkout branches,
-and to make changes to existing branches. It is not used to fetch,
-pull, merge, rebase, or push branches, i.e. this popup deals with
-branches themselves, not with the commits reachable from them. Those
-features are available from separate popups.
-
-‘b’ (‘magit-branch-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer.
-
- By default it also displays the values of some branch-related Git
- variables and allows changing their values, just like the
- specialized ‘magit-branch-config-popup’ does.
-
- -- User Option: magit-branch-popup-show-variables
-
- Whether the ‘magit-branch-popup’ shows Git variables. This
- defaults to t to avoid changing key bindings. When set to nil, no
- variables are displayed directly in this popup, and the sub-popup
- ‘magit-branch-config-popup’ has to be used indead to view and
- change branch related variables.
-
-‘b b’ (‘magit-checkout’)
-
- Checkout a revision read in the minibuffer and defaulting to the
- branch or arbitrary revision at point. If the revision is a local
- branch then that becomes the current branch. If it is something
- else then ‘HEAD’ becomes detached. Checkout fails if the working
- tree or the staging area contain changes.
-
-‘b n’ (‘magit-branch’)
-
- Create a new branch. The user is asked for a branch or arbitrary
- revision to use as the starting point of the new branch. When a
- branch name is provided, then that becomes the upstream branch of
- the new branch. The name of the new branch is also read in the
- minibuffer.
-
- Also see option ‘magit-branch-prefer-remote-upstream’.
-
-‘b c’ (‘magit-branch-and-checkout’)
-
- This command creates a new branch like ‘magit-branch’, but then
- also checks it out.
-
- Also see option ‘magit-branch-prefer-remote-upstream’.
-
-‘b s’ (‘magit-branch-spinoff’)
-
- This command creates and checks out a new branch starting at and
- tracking the current branch. That branch in turn is reset to the
- last commit it shares with its upstream. If the current branch has
- no upstream or no unpushed commits, then the new branch is created
- anyway and the previously current branch is not touched.
-
- This is useful to create a feature branch after work has already
- began on the old branch (likely but not necessarily "master").
-
- If the current branch is a member of the value of option
- ‘magit-branch-prefer-remote-upstream’ (which see), then the current
- branch will be used as the starting point as usual, but the
- upstream of the starting-point may be used as the upstream of the
- new branch, instead of the starting-point itself.
-
-‘b x’ (‘magit-branch-reset’)
-
- This command resets a branch, defaulting to the branch at point, to
- the tip of another branch or any other commit.
-
- When the branch being reset is the current branch, then a hard
- reset is performed. If there are any uncommitted changes, then the
- user has to confirming the reset because those changes would be
- lost.
-
- This is useful when you have started work on a feature branch but
- realize it’s all crap and want to start over.
-
- When resetting to another branch and a prefix argument is used,
- then the target branch is set as the upstream of the branch that is
- being reset.
-
-‘b k’ (‘magit-branch-delete’)
-
- Delete one or multiple branches. If the region marks multiple
- branches, then offer to delete those. Otherwise, prompt for a
- single branch to be deleted, defaulting to the branch at point.
-
-‘b r’ (‘magit-branch-rename’)
-
- Rename a branch. The branch and the new name are read in the
- minibuffer. With prefix argument the branch is renamed even if
- that name conflicts with an existing branch.
-
- -- User Option: magit-branch-read-upstream-first
-
- When creating a branch, whether to read the upstream branch before
- the name of the branch that is to be created. The default is
- ‘nil’, and I recommend you leave it at that.
-
- -- User Option: magit-branch-prefer-remote-upstream
-
- This option specifies whether remote upstreams are favored over
- local upstreams when creating new branches.
-
- When a new branch is created, Magit offers the branch, commit, or
- stash as the default starting point of the new branch. If there is
- no such thing at point, then it falls back to offer the current
- branch as starting-point. The user may then accept that default or
- pick something else.
-
- If the chosen starting-point is a branch, then it may also be set
- as the upstream of the new branch, depending on the value of the
- Git variable ‘branch.autoSetupMerge’. By default this is done for
- remote branches, but not for local branches.
-
- You might prefer to always use some remote branch as upstream. If
- the chosen starting-point is (1) a local branch, (2) whose name is
- a member of the value of this option, (3) the upstream of that
- local branch is a remote branch with the same name, and (4) that
- remote branch can be fast-forwarded to the local branch, then the
- chosen branch is used as starting-point, but its own upstream is
- used as the upstream of the new branch.
-
- Assuming the chosen branch matches these conditions you would end
- up with with e.g.:
-
- feature --upstream--> origin/master
-
- instead of
-
- feature --upstream--> master --upstream--> origin/master
-
- Which you prefer is a matter of personal preference. If you do
- prefer the former, then you should add branches such as ‘master’,
- ‘next’, and ‘maint’ to the value of this options.
-
-\1f
-File: magit.info, Node: The branch config popup, Prev: The branch popup, Up: Branching
-
-6.5.3 The branch config popup
------------------------------
-
- -- Command: magit-branch-popup
-
- This prefix command shows the following branch-related Git
- variables in a popup buffer. The values can be changed from that
- buffer.
-
- This popup is a sub-popup of several popups that deal with
- branches, including ‘magit-branch-popup’, ‘magit-pull-popup’,
- ‘magit-fetch-popup’, ‘magit-pull-and-fetch-popup’, and
- ‘magit-push-popup’. In all of these popups "C" is bound to this
- popup.
-
- The following variables are used to configure a specific branch. The
-values are being displayed for the current branch (if any). To change
-the value for another branch invoke ‘magit-branch-config-popup’ with a
-prefix argument.
-
- -- Variable: branch.NAME.merge
-
- Together with ‘branch.NAME.remote’ this variable defines the
- upstream branch of the local branch named NAME. The value of this
- variable is the full reference of the upstream _branch_.
-
- -- Variable: branch.NAME.remote
-
- Together with ‘branch.NAME.merge’ this variable defines the
- upstream branch of the local branch named NAME. The value of this
- variable is the name of the upstream _remote_.
-
- -- Variable: branch.NAME.rebase
-
- This variable controls whether pulling into the branch named NAME
- is done by rebasing or by merging the fetched branch.
-
- • When ‘true’ then pulling is done by rebasing.
-
- • When ‘false’ then pulling is done by merging.
-
- • When undefined then the value of ‘pull.rebase’ is used. The
- default of that variable is ‘false’.
-
- -- Variable: branch.NAME.pushRemote
-
- This variable specifies the remote that the branch named NAME is
- usually pushed to. The value has to be the name of an existing
- remote.
-
- It is not possible to specify the name of _branch_ to push the
- local branch to. The name of the remote branch is always the same
- as the name of the local branch.
-
- If this variable is undefined but ‘remote.pushDefault’ is defined,
- then the value of the latter is used. By default
- ‘remote.pushDefault’ is undefined.
-
- -- Variable: branch.NAME.description
-
- This variable can be used to describe the branch named NAME. That
- description is used e.g. when turning the branch into a series of
- patches.
-
- The following variables specify defaults which are used if the above
-branch-specific variables are not set.
-
- -- Variable: pull.rebase
-
- This variable specifies whether pulling is done by rebasing or by
- merging. It can be overwritten using ‘branch.NAME.rebase’.
-
- • When ‘true’ then pulling is done by rebasing.
-
- • When ‘false’ (the default) then pulling is done by merging.
- Since it is never a good idea to merge the upstream branch into a
- feature or hotfix branch and most branches are such branches, you
- should consider setting this to ‘true’, and ‘branch.master.rebase’
- to ‘false’.
-
- -- Variable: remote.pushDefault
-
- This variable specifies what remote the local branches are usually
- pushed to. This can be overwritten per branch using
- ‘branch.NAME.pushRemote’.
-
- The following variables are used during the creation of a branch and
-control whether the various branch-specific variables are automatically
-set at this time.
-
- -- Variable: branch.autoSetupMerge
-
- This variable specifies under what circumstances creating a branch
- NAME should result in the variables ‘branch.NAME.merge’ and
- ‘branch.NAME.remote’ being set according to the starting point used
- to create the branch. If the starting point isn’t a branch, then
- these variables are never set.
-
- • When ‘always’ then the variables are set regardless of whether
- the starting point is a local or a remote branch.
-
- • When ‘true’ (the default) then the variables are set when the
- starting point is a remote branch, but not when it is a local
- branch.
-
- • When ‘false’ then the variables are never set.
-
- -- Variable: branch.autoSetupRebase
-
- This variable specifies whether creating a branch NAME should
- result in the variable ‘branch.NAME.rebase’ being set to ‘true’.
-
- • When ‘always’ then the variable is set regardless of whether
- the starting point is a local or a remote branch.
-
- • When ‘local’ then the variable are set when the starting point
- is a local branch, but not when it is a remote branch.
-
- • When ‘remote’ then the variable are set when the starting
- point is a remote branch, but not when it is a local branch.
-
- • When ‘never’ (the default) then the variable is never set.
-
- Note that the respective commands always change the repository-local
-values. If you want to change the global value, which is used when the
-local value is undefined, then you have to do so on the command line,
-e.g.:
-
- git config --global remote.autoSetupMerge always
-
- For more information about these variables you should also see
-
- *note (gitman)git-config:: . Also see *note (gitman)git-branch:: ,
-
- *note (gitman)git-checkout:: , and *note Pushing: Pushing.
-
- -- User Option: magit-prefer-remote-upstream
-
- This option controls whether commands that read a branch from the
- user and then set it as the upstream branch, offer a local or a
- remote branch as default completion candidate, when they have the
- choice.
-
- This affects all commands that use ‘magit-read-upstream-branch’ or
- ‘magit-read-starting-point’, which includes all commands that
- change the upstream and many which create new branches.
-
-\1f
-File: magit.info, Node: Merging, Next: Resolving conflicts, Prev: Branching, Up: Manipulating
-
-6.6 Merging
-===========
-
-Also see *note (gitman)git-merge:: . For information on how to resolve
-merge conflicts see the next section.
-
-‘m’ (‘magit-merge-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no merge is in progress, then the popup buffer features the
-following commands.
-
-‘m m’ (‘magit-merge’)
-
- Merge another branch or an arbitrary revision into the current
- branch. The branch or revision to be merged is read in the
- minibuffer and defaults to the one at point.
-
- Unless there are conflicts or a prefix argument is used, the
- resulting merge commit uses a generic commit message, and the user
- does not get a chance to inspect or change it before the commit is
- created. With a prefix argument this does not actually create the
- merge commit, which makes it possible to inspect how conflicts were
- resolved and to adjust the commit message.
-
-‘m e’ (‘magit-merge-editmsg’)
-
- Merge another branch or an arbitrary revision into the current
- branch and open a commit message buffer, so that the user can make
- adjustments. The commit is not actually created until the user
- finishes with ‘C-c C-c’.
-
-‘m n’ (‘magit-merge-nocommit’)
-
- Merge another branch or an arbitrary revision into the current
- branch, but do not actually create the commit. The user can then
- further adjust the merge, even when automatic conflict resolution
- succeeded and/or adjust the commit message.
-
-‘m p’ (‘magit-merge-preview’)
-
- Preview result of merging another branch or an arbitrary revision
- into the current branch.
-
- When a merge is in progress, then the popup buffer features these
-commands instead.
-
-‘m m’ (‘magit-merge’)
-
- After resolving conflicts, proceed with the merge. If there are
- still conflicts, then this fails.
-
-‘m a’ (‘magit-merge-abort’)
-
- Abort the current merge operation.
-
-\1f
-File: magit.info, Node: Resolving conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating
-
-6.7 Resolving conflicts
-=======================
-
-When merging branches (or otherwise combining or changing history)
-conflicts can occur. If you edited two completely different parts of
-the same file in two branches and then merge one of these branches into
-the other, then Git can resolve that on its own, but if you edit the
-same area of a file, then a human is required to decide how the two
-versions, or "sides of the conflict", are to be combined into one.
-
- Here we can only provide a brief introduction to the subject and
-point you toward some tools that can help. If you are new to this, then
-please also consult Git’s own documentation as well as other resources.
-
- If a file has conflicts and Git cannot resolve them by itself, then
-it puts both versions into the affected file along with special markers
-whose purpose is to denote the boundaries of the unresolved part of the
-file and between the different versions. These boundary lines begin
-with the strings "<<<<", "|||||||", "=======", and ">>>>" and are
-followed by information about the source of the respective versions,
-e.g.:
-
- <<<<<<< HEAD
- Take the blue pill.
- =======
- Take the red pill.
- >>>>>>> feature
-
- In this case you have chosen to take the red pill on one bracnh and
-on another you picked the blue pill. Now that you are merging these two
-diverging branches, Git cannot possibly know which pill you want to
-take.
-
- To resolve that conflict you have to create a version of the affected
-area of the file by keeping only one of the sides, possibly by editing
-it in order to bring in the changes from the other side, remove the
-other versions as well as the markers, and then stage the result. A
-possible resolution might be:
-
- Take both pills.
-
- Often it is useful to see not only the two sides of the conflict but
-also the "original" version from before the same area of the file was
-modified twice on different branches. Instruct Git to insert that
-version as well by running this command once:
-
- git config --global merge.conflictStyle diff3
-
- The above conflict might then have looked like this:
-
- <<<<<<< HEAD
- Take the blue pill.
- ||||||| merged common ancestors
- Take either the blue or the red pill, but not both.
- =======
- Take the red pill.
- >>>>>>> feature
-
- If that were the case, then the above conflict resolution would not
-have been correct, which demonstrates why seeing the original version
-alongside the conflicting versions can be useful.
-
- You can perform the conflict resolution completely by hand, but Emacs
-also provides some packages that help in the process: Smerge, Ediff
-(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does
-not provide its own tools for conflict resolution, but it does make
-using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so
-you probably don’t want to use the latter anyway.)
-
- In the Magit status buffer, files with unresolved conflicts are
-listed in the "Unstaged changes" and/or "Staged changes" sections. They
-are prefixed with the word "unmerged", which in this context essentially
-is a synonym for "unresolved".
-
- Pressing ‘RET’ while point is on such a file section shows a buffer
-visiting that file, turns on ‘smerge-mode’ in that buffer, and places
-point inside the first area with conflicts. You should then resolve
-that conflict using regular edit commands and/or Smerge commands.
-
- Unfortunately Smerge does not have a manual, but you can get a list
-of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a
-command name to read its documentation.
-
- Normally you would edit one version and then tell Smerge to keep only
-that version. Use ‘C-c ^ m’ (‘smerge-keep-mine)’ to keep the "HEAD"
-version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that
-follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting
-area in the same file. Once you are done resolving conflicts, return to
-the Magit status buffer. The file should now be shown as "modified", no
-longer as "unmerged", because Smerge automatically stages the file when
-you save the buffer after resolving the last conflict.
-
- Alternatively you could use Ediff, which uses separate buffers for
-the different versions of the file. To resolve conflicts in a file
-using Ediff press ‘e’ while point is on such a file in the status
-buffer.
-
- Ediff can be used for other purposes as well. For more information
-on how to enter Ediff from Magit, see *note Ediffing: Ediffing.
-Explaining how to use Ediff is beyond the scope of this manual, instead
-see *note (ediff)Top::.
-
- If you are unsure whether you should Smerge or Ediff, then use the
-former. It is much easier to understand and use, and except for truely
-complex conflicts, the latter is usually overkill.
-
-\1f
-File: magit.info, Node: Rebasing, Next: Cherry picking, Prev: Resolving conflicts, Up: Manipulating
-
-6.8 Rebasing
-============
-
-Also see *note (gitman)git-rebase:: . For information on how to resolve
-conflicts that occur during rebases see the preceding section.
-
-‘r’ (‘magit-rebase-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no rebase is in progress, then the popup buffer features the
-following commands.
-
- Using one of these commands _starts_ a rebase sequence. Git might
-then stop somewhere along the way, either because you told it to do so,
-or because applying a commit failed due to a conflict. When that
-happens, then the status buffer shows information about the rebase
-sequence which is in progress in a section similar to a log section.
-See *note Information about in-progress rebase: Information about
-in-progress rebase.
-
-‘r p’ (‘magit-rebase-onto-pushremote’)
-
- Rebase the current branch onto ‘branch.<name>.pushRemote’. If that
- variable is unset, then rebase onto ‘remote.pushDefault’.
-
-‘r u’ (‘magit-rebase-onto-upstream’)
-
- Rebase the current branch onto its upstream branch.
-
-‘r e’ (‘magit-rebase’)
-
- Rebase the current branch onto a branch read in the minibuffer.
- All commits that are reachable from head but not from the selected
- branch TARGET are being rebased."
-
-‘r o’ (‘magit-rebase-subset’)
-
- Start a non-interactive rebase sequence with commits from START to
- ‘HEAD’ onto NEWBASE. START has to be selected from a list of recent
- commits.
-
- Note that the popup also features the infix argument ‘--interactive’.
-This can be used to turn one of the above non-interactive rebase
-variants into an interactive rebase.
-
- For example if you want to clean up a feature branch and at the same
-time rebase it onto ‘master’, then you could use ‘r-iu’. But we
-recommend that you instead do that in two steps. First use ‘ri’ to
-cleanup the feature branch, and then in a second step ‘ru’ to rebase it
-onto ‘master’. That way if things turn out to be more complicated than
-you thought and/or you make a mistake and have to start over, then you
-only have to redo half the work.
-
- Explicitly enabling ‘--interactive’ won’t have an effect on the
-following commands as they always use that argument anyway, even if it
-is not enabled in the popup.
-
-‘r i’ (‘magit-rebase-interactive’)
-
- Start an interactive rebase sequence.
-
-‘r f’ (‘magit-rebase-autosquash’)
-
- Combine squash and fixup commits with their intended targets.
-
-‘r m’ (‘magit-rebase-edit-commit’)
-
- Edit a single older commit using rebase.
-
-‘r w’ (‘magit-rebase-reword-commit’)
-
- Reword a single older commit using rebase.
-
- When a rebase is in progress, then the popup buffer features these
-commands instead.
-
-‘r r’ (‘magit-rebase-continue’)
-
- Restart the current rebasing operation.
-
- In some cases this pops up a commit message buffer for you do edit.
- With a prefix argument the old message is reused as-is.
-
-‘r s’ (‘magit-rebase-skip’)
-
- Skip the current commit and restart the current rebase operation.
-
-‘r e’ (‘magit-rebase-edit’)
-
- Edit the todo list of the current rebase operation.
-
-‘r a’ (‘magit-rebase-abort’)
-
- Abort the current rebase operation, restoring the original branch.
-
-* Menu:
-
-* Editing rebase sequences::
-* Information about in-progress rebase::
-
-\1f
-File: magit.info, Node: Editing rebase sequences, Next: Information about in-progress rebase, Up: Rebasing
-
-6.8.1 Editing rebase sequences
-------------------------------
-
-‘C-c C-c’ (‘with-editor-finish’)
-
- Finish the current editing session by returning with exit code 0.
- Git then uses the rebase instructions it finds in the file.
-
-‘C-c C-k’ (‘with-editor-cancel’)
-
- Cancel the current editing session by returning with exit code 1.
- Git then forgoes starting the rebase sequence.
-
-‘RET’ (‘git-rebase-show-commit’)
-
- Show the commit on the current line in another buffer and select
- that buffer.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- Show the commit on the current line in another buffer without
- selecting that buffer. If the revision buffer is already visible
- in another window of the current frame, then instead scroll that
- window up.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- Show the commit on the current line in another buffer without
- selecting that buffer. If the revision buffer is already visible
- in another window of the current frame, then instead scroll that
- window down.
-
-‘p’ (‘git-rebase-backward-line’)
-
- Move to previous line.
-
-‘n’ (‘forward-line’)
-
- Move to next line.
-
-‘M-p’ (‘git-rebase-move-line-up’)
-
- Move the current commit (or command) up.
-
-‘M-n’ (‘git-rebase-move-line-down’)
-
- Move the current commit (or command) down.
-
-‘r’ (‘git-rebase-reword’)
-
- Edit message of commit on current line.
-
-‘e’ (‘git-rebase-edit’)
-
- Stop at the commit on the current line.
-
-‘s’ (‘git-rebase-squash’)
-
- Meld commit on current line into previous commit, and edit message.
-
-‘f’ (‘git-rebase-fixup’)
-
- Meld commit on current line into previous commit, discarding the
- current commit’s message.
-
-‘k’ (‘git-rebase-kill-line’)
-
- Kill the current action line.
-
-‘c’ (‘git-rebase-pick’)
-
- Use commit on current line.
-
-‘x’ (‘git-rebase-exec’)
-
- Insert a shell command to be run after the proceeding commit.
-
- If there already is such a command on the current line, then edit
- that instead. With a prefix argument insert a new command even
- when there already is one on the current line. With empty input
- remove the command on the current line, if any.
-
-‘y’ (‘git-rebase-insert’)
-
- Read an arbitrary commit and insert it below current line.
-
-‘C-x u’ (‘git-rebase-undo’)
-
- Undo some previous changes. Like ‘undo’ but works in read-only
- buffers.
-
- -- User Option: git-rebase-auto-advance
-
- Whether to move to next line after changing a line.
-
- -- User Option: git-rebase-show-instructions
-
- Whether to show usage instructions inside the rebase buffer.
-
- -- User Option: git-rebase-confirm-cancel
-
- Whether confirmation is required to cancel.
-
-\1f
-File: magit.info, Node: Information about in-progress rebase, Prev: Editing rebase sequences, Up: Rebasing
-
-6.8.2 Information about in-progress rebase
-------------------------------------------
-
-While a rebase sequence is in progress, the status buffer features a
-section which lists the commits that have already been applied as well
-as the commits that still have to be applied.
-
- The commits are split in two halves. When rebase stops at a commit,
-either because the user has to deal with a conflict or explicitly
-requested that rebase stops at that commit, then point is placed on the
-commit that separates the two groups, i.e. on ‘HEAD’. The commits
-above it have not been applied yet, while it and the commits below it
-have already been applied. In between these two groups of applied and
-yet-to-be applied commits, there sometimes is a commit which has been
-dropped.
-
- Each commit is prefixed with a word and these words are additionally
-shown in different colors to indicate the status of the commits.
-
- The following colors are used:
-
- • Yellow commits have not been applied yet.
-
- • Gray commits have already been applied.
-
- • The blue commit is the ‘HEAD’ commit.
-
- • The green commit is the commit the rebase sequence stopped at. If
- this is the same commit as ‘HEAD’ (e.g. because you haven’t done
- anything yet after rebase stopped at the commit, then this commit
- is shown in blue, not green. There can only be a green and a blue
- commit at the same time, if you create one or more new commits
- after rebase stops at a commit.
-
- • Red commits have been dropped. They are shown for reference only,
- e.g. to make it easier to diff.
-
- Of course these colors are subject to the color-theme in use.
-
- The following words are used:
-
- • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and
- ‘fixup’ have not been applied yet. These words have the same
- meaning here as they do in the buffer used to edit the rebase
- sequence. See *note Editing rebase sequences: Editing rebase
- sequences.
-
- • The commit prefixed with ‘onto’ is the commit on top of which all
- the other commits are being re-applied. Like the commits that have
- already been re-applied, it is reachable from ‘HEAD’, but unlike
- those it has not actually been re-applied during the current
- session - it wasn’t touched at all.
-
- • Commits prefixed with ‘done’ have already been re-applied. Not all
- commits that have already been applied are prefixed with this word,
- though.
-
- • When a commit is prefixed with ‘void’, then that indicates that
- Magit knows for sure that all the changes in that commit have been
- applied using several new commits. This commit is no longer
- reachable from ‘HEAD’, and it also isn’t one of the commits that
- will be applied when resuming the session.
-
- • When a commit is prefixed with ‘join’, then that indicates that the
- rebase sequence stopped at that commit due to a conflict - you now
- have to join (merge) the changes with what has already been
- applied. In a sense this is the commit rebase stopped at, but
- while its effect is already in the index and in the worktree (with
- conflict markers), the commit itself has not actually been applied
- yet (it isn’t the ‘HEAD’). So it is shown in yellow, like the
- other commits that still have to be applied.
-
- • When a commit is prefixed with ‘goal’, ‘same’, or ‘work’, then that
- indicates that you reset to an earlier commit (and that this commit
- therefore is no longer reachable from ‘HEAD’), but that it might
- still be possible to create a new commit with the exact same tree
- or at least the same patch-id (1), without manually editing any
- file. Or at the very least that there are some uncommitted
- remaining, which may or may not originate from that commit.
-
- • When a commit is prefixed with ‘goal’, then that indicates
- that it is still possible to create a commit with the exact
- same tree (the "goal") without manually editing a file, by
- simply committing the index (or, provided nothing is already
- staged, by staging all unstaged changes and then committing
- that). This is the case when the original tree exists in the
- index or worktree in untainted form.
-
- • When a commit is prefixed with ‘same’, then that indicates
- that it is no longer possible to create a commit with the
- exact same tree, but that it is still possible to create a
- commit with the same patch-id. This would be the case if you
- created a new commit with other changes, but the changes from
- the original commit still exist in the index and/or working
- tree in untainted form.
-
- • When a commit is prefixed with ‘work’, then that indicates
- that you are working with the changes from that commit after
- resetting to an earlier commit. There are changes in the
- index and/or working tree and some of them likely originate
- from that commit.
-
- • When a commit is prefixed with ‘poof’ or ‘gone’, then that
- indicates that you reset to an earlier commit (and that this commit
- therefore is no longer reachable from ‘HEAD’), and that there are
- no uncommitted changes remaining which might allow you to create a
- new commit with the same tree or at least the same patch-id.
-
- • When a commit is prefixed with ‘poof’, then that indicates
- that it is no longer reachable from ‘HEAD’, but that it has
- been replaced with one or more commits, which together have
- the exact same effect.
-
- • When a commit is prefixed with ‘gone’, then that indicates
- that it is no longer reachable from ‘HEAD’ and that we also
- cannot determine whether its changes are still in effect in
- one or more new commits. They might be, but if so, then there
- must also be other changes which makes it impossible to know
- for sure.
-
- Do not worry if you do not fully understand the above. That’s okay,
-you will acquire a good enough understanding through practice.
-
- For other sequence operations such as cherry-picking, a similar
-section is displayed, but they lack some of the features described
-above, due to limitations in the git commands used to implement them.
-Most importantly these sequences only support "picking" a commit but not
-other actions such as "rewording", and they do not keep track of the
-commits which have already been applied.
-
- ---------- Footnotes ----------
-
- (1) The patch-id is a hash of the _changes_ introduced by commit. It
-differs from hash of the commit itself, which is a hash of the result of
-applying that change (i.e. the resulting trees and blobs) as well as
-author and committer information, the commit message, and the hashes of
-the parents of the commit. The patch-id hash on the other hand is
-created only from the added and removed lines, even line numbers and
-whitespace are created when calculating the hash. The patch-ids of two
-commits can be used to answer the question "Do these two commits make
-the same change?".
-
-\1f
-File: magit.info, Node: Cherry picking, Next: Resetting, Prev: Rebasing, Up: Manipulating
-
-6.9 Cherry picking
-==================
-
-Also see *note (gitman)git-cherry-pick:: .
-
-‘A’ (‘magit-cherry-pick-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no cherry-pick or revert is in progress, then the popup buffer
-features the following commands.
-
-‘A A’ (‘magit-cherry-pick’)
-
- Cherry-pick a commit. Prompt for a commit, defaulting to the
- commit at point. If the region selects multiple commits, then pick
- all of them, without prompting.
-
-‘A a’ (‘magit-cherry-apply’)
-
- Apply the changes in a commit to the working tree, but do not
- commit them. Prompt for a commit, defaulting to the commit at
- point. If the region selects multiple commits, then apply all of
- them, without prompting.
-
- This command also has a top-level binding, which can be invoked
- without using the popup by typing ‘a’ at the top-level.
-
- When a cherry-pick or revert is in progress, then the popup buffer
-features these commands instead.
-
-‘A A’ (‘magit-sequence-continue’)
-
- Resume the current cherry-pick or revert sequence.
-
-‘A s’ (‘magit-sequence-skip’)
-
- Skip the stopped at commit during a cherry-pick or revert sequence.
-
-‘A a’ (‘magit-sequence-abort’)
-
- Abort the current cherry-pick or revert sequence. This discards
- all changes made since the sequence started.
-
-* Menu:
-
-* Reverting::
-
-\1f
-File: magit.info, Node: Reverting, Up: Cherry picking
-
-6.9.1 Reverting
----------------
-
-‘V’ (‘magit-revert-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- When no cherry-pick or revert is in progress, then the popup buffer
-features the following commands.
-
-‘V V’ (‘magit-revert’)
-
- Revert a commit by creating a new commit. Prompt for a commit,
- defaulting to the commit at point. If the region selects multiple
- commits, then revert all of them, without prompting.
-
-‘V v’ (‘magit-revert-no-commit’)
-
- Revert a commit by applying it in reverse to the working tree.
- Prompt for a commit, defaulting to the commit at point. If the
- region selects multiple commits, then revert all of them, without
- prompting.
-
- When a cherry-pick or revert is in progress, then the popup buffer
-features these commands instead.
-
-‘V A’ (‘magit-sequence-continue’)
-
- Resume the current cherry-pick or revert sequence.
-
-‘V s’ (‘magit-sequence-skip’)
-
- Skip the stopped at commit during a cherry-pick or revert sequence.
-
-‘V a’ (‘magit-sequence-abort’)
-
- Abort the current cherry-pick or revert sequence. This discards
- all changes made since the sequence started.
-
-\1f
-File: magit.info, Node: Resetting, Next: Stashing, Prev: Cherry picking, Up: Manipulating
-
-6.10 Resetting
-==============
-
-Also see *note (gitman)git-reset:: .
-
-‘x’ (‘magit-reset’)
-
- Reset the head and index to some commit read from the user and
- defaulting to the commit at point. The working tree is kept as-is.
- With a prefix argument also reset the working tree.
-
-‘M-x magit-reset-index’ (‘magit-reset-index’)
-
- Reset the index to some commit read from the user and defaulting to
- the commit at point. Keep the ‘HEAD’ and working tree as-is, so if
- the commit refers to the ‘HEAD’, then this effectively unstages all
- changes.
-
-‘M-x magit-reset-head’ (‘magit-reset-head’)
-
- Reset the ‘HEAD’ and index to some commit read from the user and
- defaulting to the commit at point. The working tree is kept as-is.
-
-‘M-x magit-reset-soft’ (‘magit-reset-soft’)
-
- Reset the ‘HEAD’ to some commit read from the user and defaulting
- to the commit at point. The index and the working tree are kept
- as-is.
-
-‘M-x magit-reset-hard’ (‘magit-reset-hard’)
-
- Reset the ‘HEAD’, index, and working tree to some commit read from
- the user and defaulting to the commit at point.
-
-‘M-x magit-checkout-file’ (‘magit-checkout-file’)
-
- Update file in the working tree and index to the contents from a
- revision.
-
- Both the revision and file are read from the user.
-
-\1f
-File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating
-
-6.11 Stashing
-=============
-
-Also see *note (gitman)git-stash:: .
-
-‘z’ (‘magit-stash-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘z z’ (‘magit-stash’)
-
- Create a stash of the index and working tree. Untracked files are
- included according to popup arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’.
-
-‘z i’ (‘magit-stash-index’)
-
- Create a stash of the index only. Unstaged and untracked changes
- are not stashed.
-
-‘z w’ (‘magit-stash-worktree’)
-
- Create a stash of unstaged changes in the working tree. Untracked
- files are included according to popup arguments. One prefix
- argument is equivalent to ‘--include-untracked’ while two prefix
- arguments are equivalent to ‘--all’.
-
-‘z x’ (‘magit-stash-keep-index’)
-
- Create a stash of the index and working tree, keeping index intact.
- Untracked files are included according to popup arguments. One
- prefix argument is equivalent to ‘--include-untracked’ while two
- prefix arguments are equivalent to ‘--all’.
-
-‘z Z’ (‘magit-snapshot’)
-
- Create a snapshot of the index and working tree. Untracked files
- are included according to popup arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’.
-
-‘z I’ (‘magit-snapshot-index’)
-
- Create a snapshot of the index only. Unstaged and untracked
- changes are not stashed.
-
-‘z W’ (‘magit-snapshot-worktree’)
-
- Create a snapshot of unstaged changes in the working tree.
- Untracked files are included according to popup arguments. One
- prefix argument is equivalent to ‘--include-untracked’ while two
- prefix arguments are equivalent to ‘--all’-.
-
-‘z a’ (‘magit-stash-apply’)
-
- Apply a stash to the working tree. Try to preserve the stash
- index. If that fails because there are staged changes, apply
- without preserving the stash index.
-
-‘z p’ (‘magit-stash-pop’)
-
- Apply a stash to the working tree and remove it from stash list.
- Try to preserve the stash index. If that fails because there are
- staged changes, apply without preserving the stash index and forgo
- removing the stash.
-
-‘z d’ (‘magit-stash-drop’)
-
- Remove a stash from the stash list. When the region is active,
- offer to drop all contained stashes.
-
-‘z l’ (‘magit-stash-list’)
-
- List all stashes in a buffer.
-
-‘z v’ (‘magit-stash-show’)
-
- Show all diffs of a stash in a buffer.
-
-‘z b’ (‘magit-stash-branch’)
-
- Create and checkout a new BRANCH from STASH.
-
-‘z f’ (‘magit-stash-format-patch’)
-
- Create a patch from STASH.
-
-‘k’ (‘magit-stash-clear’)
-
- Remove all stashes saved in REF’s reflog by deleting REF.
-
-\1f
-File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top
-
-7 Transferring
-**************
-
-* Menu:
-
-* Remotes::
-* Fetching::
-* Pulling::
-* Pushing::
-* Creating and sending patches::
-* Applying patches::
-
-\1f
-File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring
-
-7.1 Remotes
-===========
-
-Also see *note (gitman)git-remote:: .
-
-‘M’ (‘magit-remote-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘M a’ (‘magit-remote-add’)
-
- Add a remote and fetch it. The remote name and url are read in the
- minibuffer.
-
-‘M r’ (‘magit-remote-rename’)
-
- Rename a remote. Both the old and the new names are read in the
- minibuffer.
-
-‘M u’ (‘magit-remote-set-url’)
-
- Change the url of a remote. Both the remote and the new url are
- read in the minibuffer.
-
-‘M k’ (‘magit-remote-remove’)
-
- Delete a remote, read from the minibuffer.
-
- -- User Option: magit-remote-add-set-remote.pushDefault
-
- Whether to set the value of ‘remote.pushDefault’ after adding a
- remote.
-
- If ‘ask’, then always ask. If ‘ask-if-unset’, then ask, but only
- if the variable isn’t set already. If ‘nil’, then don’t ever set.
- If the value is a string, then set without asking, provided the
- name of the name of the added remote is equal to that string and
- the variable isn’t already set.
-
-\1f
-File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring
-
-7.2 Fetching
-============
-
-For information about the differences between the _upstream_ and the
-_push-remote_, see *note Branching: Branching.
-
- Also see *note (gitman)git-fetch:: .
-
-‘f’ (‘magit-fetch-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘f p’ (‘magit-fetch-from-pushremote’)
-
- Fetch from the push-remote of the current branch.
-
-‘f u’ (‘magit-fetch-from-upstream’)
-
- Fetch from the upstream of the current branch.
-
-‘f e’ (‘magit-fetch’)
-
- Fetch from another repository.
-
-‘f o’ (‘magit-fetch-branch’)
-
- Fetch a branch from a remote, both of which are read from the
- minibuffer.
-
-‘f r’ (‘magit-fetch-refspec’)
-
- Fetch from a remote using an explicit refspec, both of which are
- read from the minibuffer.
-
-‘f a’ (‘magit-fetch-all’)
-
- Fetch from all remotes.
-
-‘f m’ (‘magit-submodule-fetch’)
-
- Fetch all submodules. With a prefix argument fetch all remotes of
- all submodules.
-
- Instead of using one popup for fetching and another for pulling, you
-could also use ‘magit-pull-and-fetch-popup’. See its doc-string for
-more information.
-
-\1f
-File: magit.info, Node: Pulling, Next: Pushing, Prev: Fetching, Up: Transferring
-
-7.3 Pulling
-===========
-
-For information about the differences between the _upstream_ and the
-_push-remote_, see *note Branching: Branching.
-
- Also see *note (gitman)git-pull:: .
-
-‘F’ (‘magit-pull-popup’)
-
- This prefix command shows the following suffix commands in a popup
- buffer.
-
-‘F p’ (‘magit-pull-from-pushremote’)
-
- Pull from the push-remote of the current branch.
-
-‘F u’ (‘magit-pull-from-upstream’)
-
- Pull from the upstream of the current branch.
-
-‘F e’ (‘magit-pull’)
-
- Pull from a branch read in the minibuffer.
-
- Instead of using one popup for fetching and another for pulling, you
-could also use ‘magit-pull-and-fetch-popup’. See its doc-string for
-more information.
-
-\1f
-File: magit.info, Node: Pushing, Next: Creating and sending patches, Prev: Pulling, Up: Transferring
-
-7.4 Pushing
-===========
-
-For information about the differences between the _upstream_ and the
-_push-remote_, see *note Branching: Branching.
-
- Also see *note (gitman)git-push:: .
-
-‘P’ (‘magit-push-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘P p’ (‘magit-push-current-to-pushremote’)
-
- Push the current branch to ‘branch.<name>.pushRemote’ or if that is
- unset to ‘remote.pushDefault’.
-
- When ‘magit-push-current-set-remote-if-missing’ is non-nil and the
- push-remote is not configured, then read the push-remote from the
- user, set it, and then push to it. With a prefix argument the
- push-remote can be changed before pushed to it.
-
-‘P u’ (‘magit-push-current-to-upstream’)
-
- Push the current branch to its upstream branch.
-
- When ‘magit-push-current-set-remote-if-missing’ is non-nil and the
- push-remote is not configured, then read the upstram from the user,
- set it, and then push to it. With a prefix argument the
- push-remote can be changed before pushed to it.
-
-‘P e’ (‘magit-push-current’)
-
- Push the current branch to a branch read in the minibuffer.
-
-‘P o’ (‘magit-push’)
-
- Push an arbitrary branch or commit somewhere. Both the source and
- the target are read in the minibuffer.
-
-‘P r’ (‘magit-push-refspecs’)
-
- Push one or multiple refspecs to a remote, both of which are read
- in the minibuffer.
-
- To use multiple refspecs, separate them with commas. Completion is
- only available for the part before the colon, or when no colon is
- used.
-
-‘P m’ (‘magit-push-matching’)
-
- Push all matching branches to another repository. If multiple
- remotes exit, then read one from the user. If just one exists, use
- that without requiring confirmation.
-
-‘P t’ (‘magit-push-tags’)
-
- Push all tags to another repository. If only one remote exists,
- then push to that. Otherwise prompt for a remote, offering the
- remote configured for the current branch as default.
-
-‘P T’ (‘magit-push-tag’)
-
- Push a tag to another repository.
-
- Two more push commands exist, which by default are not available from
-the push popup. See their doc-strings for instructions on how to add
-them to the popup.
-
- -- Command: magit-push-implicitly args
-
- Push somewhere without using an explicit refspec.
-
- This command simply runs ‘git push -v [ARGS]’. ARGS are the
- arguments specified in the popup buffer. No explicit refspec
- arguments are used. Instead the behavior depends on at least these
- Git variables: ‘push.default’, ‘remote.pushDefault’,
- ‘branch.<branch>.pushRemote’, ‘branch.<branch>.remote’,
- ‘branch.<branch>.merge’, and ‘remote.<remote>.push’.
-
- -- Command: magit-push-to-remote remote args
-
- Push to the remote REMOTE without using an explicit refspec. The
- remote is read in the minibuffer.
-
- This command simply runs ‘git push -v [ARGS] REMOTE’. ARGS are the
- arguments specified in the popup buffer. No refspec arguments are
- used. Instead the behavior depends on at least these Git
- variables: ‘push.default’, ‘remote.pushDefault’,
- ‘branch.<branch>.pushRemote’, ‘branch.<branch>.remote’,
- ‘branch.<branch>.merge’, and ‘remote.<remote>.push’.
-
- -- User Option: magit-push-current-set-remote-if-missing
-
- This option controls whether missing remotes are configured before
- pushing.
-
- When ‘nil’, then the command ‘magit-push-current-to-pushremote’ and
- ‘magit-push-current-to-upstream’ do not appear in the push popup if
- the push-remote resp. upstream is not configured. If the user
- invokes one of these commands anyway, then it raises an error.
-
- When ‘non-nil’, then these commands always appear in the push
- popup. But if the required configuration is missing, then they do
- appear in a way that indicates that this is the case. If the user
- invokes one of them, then it asks for the necessary configuration,
- stores the configuration, and then uses it to push a first time.
-
- This option also affects whether the argument ‘--set-upstream’ is
- available in the popup. If the value is ‘non-nil’, then that
- argument is redundant. But note that changing the value of this
- option does not take affect immediately, the argument will only be
- added or removed after restarting Emacs.
-
-\1f
-File: magit.info, Node: Creating and sending patches, Next: Applying patches, Prev: Pushing, Up: Transferring
-
-7.5 Creating and sending patches
-================================
-
-‘W’ (‘magit-patch-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘W p’ (‘magit-format-patch’)
-
- Create patches for a set commits. If the region marks commits,
- then create patches for those. Otherwise prompt for a range or a
- single commit, defaulting to the commit at point.
-
-‘W r’ (‘magit-request-pull’)
-
- Request that upstream pulls from your public repository.
-
-\1f
-File: magit.info, Node: Applying patches, Prev: Creating and sending patches, Up: Transferring
-
-7.6 Applying patches
-====================
-
-Also see *note (gitman)git-am:: .
-
-‘w’ (‘magit-am-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘w w’ (‘magit-am-apply-patches’)
-
- Apply one or more patches. If the region marks files, then apply
- those patches. Otherwise read a file name in the minibuffer
- defaulting to the file at point.
-
-‘w m’ (‘magit-am-apply-maildir’)
-
- Apply the patches from a maildir.
-
-‘w w’ (‘magit-am-continue’)
-
- Resume the current patch applying sequence.
-
-‘w s’ (‘magit-am-skip’)
-
- Skip the stopped at patch during a patch applying sequence.
-
-‘w a’ (‘magit-am-abort’)
-
- Abort the current patch applying sequence. This discards all
- changes made since the sequence started.
-
-\1f
-File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top
-
-8 Miscellaneous
-***************
-
-* Menu:
-
-* Tagging::
-* Notes::
-* Submodules::
-* Subtree::
-* Common commands::
-* Wip modes::
-* Minor mode for buffers visiting files::
-* Minor mode for buffers visiting blobs::
-
-\1f
-File: magit.info, Node: Tagging, Next: Notes, Up: Miscellaneous
-
-8.1 Tagging
-===========
-
-Also see *note (gitman)git-tag:: .
-
-‘t’ (‘magit-tag-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘t t’ (‘magit-tag’)
-
- Create a new tag with the given NAME at REV. With a prefix argument
- annotate the tag.
-
-‘t k’ (‘magit-tag-delete’)
-
- Delete one or more tags. If the region marks multiple tags (and
- nothing else), then offer to delete those. Otherwise, prompt for a
- single tag to be deleted, defaulting to the tag at point.
-
-‘t p’ (‘magit-tag-prune’)
-
- Offer to delete tags missing locally from REMOTE, and vice versa.
-
-\1f
-File: magit.info, Node: Notes, Next: Submodules, Prev: Tagging, Up: Miscellaneous
-
-8.2 Notes
-=========
-
-Also see *note (gitman)git-notes:: .
-
-‘T’ (‘magit-notes-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘T T’ (‘magit-notes-edit’)
-
- Edit the note attached to a commit, defaulting to the commit at
- point.
-
- By default use the value of Git variable ‘core.notesRef’ or
- "refs/notes/commits" if that is undefined.
-
-‘T r’ (‘magit-notes-remove’)
-
- Remove the note attached to a commit, defaulting to the commit at
- point.
-
- By default use the value of Git variable ‘core.notesRef’ or
- "refs/notes/commits" if that is undefined.
-
-‘T p’ (‘magit-notes-prune’)
-
- Remove notes about unreachable commits.
-
-‘T s’ (‘magit-notes-set-ref’)
-
- Set the current notes ref to a the value read from the user. The
- ref is made current by setting the value of the Git variable
- ‘core.notesRef’. With a prefix argument change the global value
- instead of the value in the current repository. When this is
- undefined, then "refs/notes/commit" is used.
-
- Other ‘magit-notes-*’ commands, as well as the sub-commands of
- Git’s ‘note’ command, default to operate on that ref.
-
-‘T S’ (‘magit-notes-set-display-refs’)
-
- Set notes refs to be display in addition to "core.notesRef". This
- reads a colon separated list of notes refs from the user. The
- values are stored in the Git variable ‘notes.displayRef’. With a
- prefix argument GLOBAL change the global values instead of the
- values in the current repository.
-
- It is possible to merge one note ref into another. That may result
-in conflicts which have to resolved in the temporary worktree
-".git/NOTES_MERGE_WORKTREE".
-
-‘T m’ (‘magit-notes-merge’)
-
- Merge the notes of a ref read from the user into the current notes
- ref. The current notes ref is the value of Git variable
- ‘core.notesRef’ or "refs/notes/commits" if that is undefined.
-
- When a notes merge is in progress then the popup features the
-following suffix commands, instead of those listed above.
-
-‘T c’ (‘magit-notes-merge-commit’)
-
- Commit the current notes ref merge, after manually resolving
- conflicts.
-
-‘T a’ (‘magit-notes-merge-abort’)
-
- Abort the current notes ref merge.
-
-\1f
-File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous
-
-8.3 Submodules
-==============
-
-Also see *note (gitman)git-submodule:: .
-
-‘o’ (‘magit-submodule-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
-‘o a’ (‘magit-submodule-add’)
-
- Add the repository at URL as a submodule. Optional PATH is the
- path to the submodule relative to the root of the super-project.
- If it is nil then the path is determined based on URL.
-
-‘o b’ (‘magit-submodule-setup’)
-
- Clone and register missing submodules and checkout appropriate
- commits.
-
-‘o i’ (‘magit-submodule-init’)
-
- Register submodules listed in ".gitmodules" into ".git/config".
-
-‘o u’ (‘magit-submodule-update’)
-
- Clone missing submodules and checkout appropriate commits. With a
- prefix argument also register submodules in ".git/config".
-
-‘o s’ (‘magit-submodule-sync’)
-
- Update each submodule’s remote URL according to ".gitmodules".
-
-‘o f’ (‘magit-submodule-fetch’)
-
- Fetch submodule. With a prefix argument fetch all remotes.
-
-‘o i’ (‘magit-submodule-init’)
-
- Unregister the submodule at PATH.
-
-\1f
-File: magit.info, Node: Subtree, Next: Common commands, Prev: Submodules, Up: Miscellaneous
-
-8.4 Subtree
-===========
-
-Also see *note (gitman)git-subtree:: .
-
-‘O’ (‘magit-tree-popup’)
-
- This prefix command shows the following suffix commands along with
- the appropriate infix arguments in a popup buffer.
-
- Most infix arguments only apply to some of the ‘git subtree’
-subcommands. When an argument that does not apply to the invoked
-command is set, then it is silently ignored.
-
- When the ‘--prefix’ argument is set in the popup buffer, then that is
-used. Otherwise the prefix is read in the minibuffer.
-
-‘O a’ (‘magit-subtree-add’)
-
- Add COMMIT from REPOSITORY as a new subtree at PREFIX.
-
-‘O c’ (‘magit-subtree-add-commit’)
-
- Add COMMIT as a new subtree at PREFIX.
-
-‘O m’ (‘magit-subtree-merge’)
-
- Merge COMMIT into the PREFIX subtree.
-
-‘O f’ (‘magit-subtree-pull’)
-
- Pull COMMIT from REPOSITORY into the PREFIX subtree.
-
-‘O p’ (‘magit-subtree-push’)
-
- Extract the history of the subtree PREFIX and push it to REF on
- REPOSITORY.
-
-‘O s’ (‘magit-subtree-split’)
-
- Extract the history of the subtree PREFIX.
-
-\1f
-File: magit.info, Node: Common commands, Next: Wip modes, Prev: Subtree, Up: Miscellaneous
-
-8.5 Common commands
-===================
-
-These are some of the commands that can be used in all buffers whose
-major-modes derive from ‘magit-mode’. There are other common commands
-beside the ones below, but these didn’t fit well anywhere else.
-
-‘M-w’ (‘magit-copy-section-value’)
-
- This command saves the value of the current section to the
- ‘kill-ring’, and, provided that the current section is a commit,
- branch, or tag section, it also pushes the (referenced) revision to
- the ‘magit-revision-stack’.
-
- When the current section is a branch or a tag, and a prefix
- argument is used, then it saves the revision at its tip to the
- ‘kill-ring’ instead of the reference name.
-
-‘C-w’ (‘magit-copy-buffer-revision’)
-
- This command save the revision being displayed in the current
- buffer to the ‘kill-ring’ and also pushes it to the
- ‘magit-revision-stack’. It is mainly intended for use in
- ‘magit-revision-mode’ buffers, the only buffers where it is always
- unambiguous exactly which revision should be saved.
-
- Most other Magit buffers usually show more than one revision, in
- some way or another, so this command has to select one of them, and
- that choice might not always be the one you think would have been
- the best pick.
-
- Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to
-‘kill-ring-save’ and ‘kill-region’, and these commands would also be
-useful in Magit buffers. Therefore when the region is active, then both
-of these commands behave like ‘kill-ring-save’ instead of as described
-above.
-
-\1f
-File: magit.info, Node: Wip modes, Next: Minor mode for buffers visiting files, Prev: Common commands, Up: Miscellaneous
-
-8.6 Wip modes
-=============
-
-Git keeps *committed* changes around long enough for users to recover
-changes they have accidentally deleted. It does so by not garbage
-collecting any committed but no longer referenced objects for a certain
-period of time, by default 30 days.
-
- But Git does *not* keep track of *uncommitted* changes in the working
-tree and not even the index (the staging area). Because Magit makes it
-so convenient to modify uncommitted changes, it also makes it easy to
-shoot yourself in the foot in the process.
-
- For that reason Magit provides three global modes that save *tracked*
-files to work-in-progress references after or before certain actions.
-(Untracked files are never saved and these modes also only work after
-the first commit has been created).
-
- Two separate work-in-progress references are used to track the state
-of the index and of the working tree: "refs/wip/index/<branchref>" and
-"refs/wip/wtree/<branchref>", where ‘<branchref>’ is the full ref of the
-current branch, e.g. "refs/heads/master". When the ‘HEAD’ is detached
-then "HEAD" is in place of ‘<branchref>’.
-
- Checking out another branch (or detaching ‘HEAD’) causes the use of
-different wip refs for subsequent changes, but the old refs are not
-deleted.
-
- Creating a commit and then making a change causes the wip refs to be
-recreated to fork from the new commit. But the old commits on the wip
-refs are not lost. They are still available from the reflog. To make
-it easier to see when the fork point of a wip ref was changed, an
-additional commit with the message "restart autosaving" is created on it
-(‘xxO’ commits below are such boundary commits).
-
- Starting with
-
- BI0---BI1 refs/wip/index/refs/heads/master
- /
-A---B refs/heads/master
- \
- BW0---BW1 refs/wip/wtree/refs/heads/master
-
- and committing the staged changes and editing and saving a file would
-result in
-
- BI0---BI1 refs/wip/index/refs/heads/master
- /
-A---B---C refs/heads/master
- \ \
- \ CW0---CW1 refs/wip/wtree/refs/heads/master
- \
- BW0---BW1 refs/wip/wtree/refs/heads/master@{2}
-
- The fork-point of the index wip ref is not changed until some change
-is being staged. Likewise just checking out a branch or creating a
-commit does not change the fork-point of the working tree wip ref. The
-fork-points are not adjusted until there actually is a change that
-should be committed to the respective wip ref.
-
- To view the log for the a branch and its wip refs use the commands
-‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’
-when using these commands. Alternatively you can use the reflog to show
-all commits that ever existed on a wip ref. You can then recover lost
-changes from the commits shown in the log or reflog.
-
- -- Command: magit-wip-log
-
- This command shows the log for a branch and its wip refs.
-
- With a negative prefix argument only the worktree wip ref is shown.
- The absolute numeric value of the prefix argument controls how many
- "branches" of each wip ref are shown.
-
- -- Command: magit-wip-log-current
-
- This command shows the log for the current branch and its wip refs.
-
- With a negative prefix argument only the worktree wip ref is shown.
- The absolute numeric value of the prefix argument controls how many
- "branches" of each wip ref are shown.
-
- There exists a total of three global modes that save to the wip refs,
-which might seem excessive, but allows fine tuning of when exactly
-changes are being committed to the wip refs. Enabling all modes makes
-it less likely that a change slips through the cracks.
-
- Setting the below variable directly does not take effect; either
-customize them or call the respective mode function.
-
- -- User Option: magit-wip-after-save-mode
-
- When this mode is enabled, then saving a buffer that visits a file
- tracked in a Git repository causes its current state to be
- committed to the working tree wip ref for the current branch.
-
- -- User Option: magit-wip-after-apply-mode
-
- When this mode is enabled, then applying (i.e. staging, unstaging,
- discarding, reversing, and regularly applying) a change to a file
- tracked in a Git repository causes its current state to be
- committed to the index and/or working tree wip refs for the current
- branch.
-
- If you only ever edit files using Emacs and only ever interact with
-Git using Magit, then the above two modes should be enough to protect
-each and every change from accidental loss. In practice nobody does
-that. So an additional mode exists that does commit to the wip refs
-before making changes that could cause the loss of earlier changes.
-
- -- User Option: magit-wip-before-change-mode
-
- When this mode is enabled, then certain commands commit the
- existing changes to the files they are about to make changes to.
-
- Note that even if you enable all three modes this won’t give you
-perfect protection. The most likely scenario for losing changes despite
-the use of these modes is making a change outside Emacs and then
-destroying it also outside Emacs. In such a scenario, Magit, being an
-Emacs package, didn’t get the opportunity to keep you from shooting
-yourself in the foot.
-
- When you are unsure whether Magit did commit a change to the wip
-refs, then you can explicitly request that all changes to all tracked
-files are being committed.
-
-‘M-x magit-wip-commit’ (‘magit-wip-commit’)
-
- This command commits all changes to all tracked files to the index
- and working tree work-in-progress refs. Like the modes described
- above, it does not commit untracked files, but it does check all
- tracked files for changes. Use this command when you suspect that
- the modes might have overlooked a change made outside Emacs/Magit.
-
- -- User Option: magit-wip-after-save-local-mode-lighter
-
- Mode-line lighter for ‘magit-wip-after-save-local-mode’.
-
- -- User Option: magit-wip-after-apply-mode-lighter
-
- Mode-line lighter for ‘magit-wip-after-apply-mode’.
-
- -- User Option: magit-wip-before-change-mode-lighter
-
- Mode-line lighter for ‘magit-wip-before-change-mode’.
-
- -- User Option: magit-wip-namespace
-
- The namespace used for work-in-progress refs. It has to end with a
- slash. The wip refs are named "<namespace>index/<branchref>" and
- "<namespace>wtree/<branchref>". When snapshots are created while
- the ‘HEAD’ is detached then "HEAD" is used in place of
- ‘<branchref>’.
-
-\1f
-File: magit.info, Node: Minor mode for buffers visiting files, Next: Minor mode for buffers visiting blobs, Prev: Wip modes, Up: Miscellaneous
-
-8.7 Minor mode for buffers visiting files
-=========================================
-
-The ‘magit-file-mode’ enables certain Magit features in file-visiting
-buffers belonging to a Git repository. It should be enabled globally
-using ‘global-magit-file-mode’. Currently this mode only establishes a
-few key bindings, but this might be extended in the future.
-
- -- User Option: magit-file-mode
-
- Whether to establish certain Magit key bindings in all
- file-visiting buffers belonging to a Git repository. This
- establishes the bindings suggested in *note Getting started:
- Getting started. (but only for file-visiting buffers), and
- additionally binds ‘C-c M-g’ to ‘magit-file-popup’.
-
-‘C-c M-g’ (‘magit-file-popup’)
-
- This prefix command shows a popup buffer featuring suffix commands
- that operate on the file being visited in the current buffer.
-
-‘C-c M-g s’ (‘magit-stage-file’)
-
- Stage all changes to the file being visited in the current buffer.
-
-‘C-c M-g u’ (‘magit-unstage-file’)
-
- Unstage all changes to the file being visited in the current
- buffer.
-
-‘C-c M-g c’ (‘magit-commit-popup’)
-
- This prefix command shows suffix commands along with the
- appropriate infix arguments in a popup buffer. See *note
- Initiating a commit: Initiating a commit.
-
-‘C-c M-g D’ (‘magit-diff-buffer-file-popup’)
-
- This prefix command shows the same suffix commands and infix
- arguments in a popup buffer as ‘magit-diff-popup’. But this
- variant has to be called from a file-visiting buffer and the
- visited file is automatically used in the popup to limit the diff
- to that file.
-
-‘C-c M-g d’ (‘magit-diff-buffer-file’)
-
- This command shows the diff for the file of blob that the current
- buffer visits. Renames are followed when a prefix argument is used
- or when ‘--follow’ is part of ‘magit-diff-arguments’.
-
- -- User Option: magit-diff-buffer-file-locked
-
- This option controls whether ‘magit-diff-buffer-file’ uses a
- decicated buffer. See *note Modes and Buffers: Modes and Buffers.
-
-‘C-c M-g L’ (‘magit-log-buffer-file-popup’)
-
- This prefix command shows the same suffix commands and infix
- arguments in a popup buffer as ‘magit-log-popup’. But this variant
- has to be called from a file-visiting buffer and the visited file
- is automatically used in the popup to limit the log to that file.
-
-‘C-c M-g l’ (‘magit-log-buffer-file’)
-
- This command shows the log for the file of blob that the current
- buffer visits. Renames are followed when a prefix argument is used
- or when ‘--follow’ is part of ‘magit-log-arguments’.
-
- -- User Option: magit-log-buffer-file-locked
-
- This option controls whether ‘magit-log-buffer-file’ uses a
- decicated buffer. See *note Modes and Buffers: Modes and Buffers.
-
-‘C-c M-g b’ (‘magit-blame-popup’)
-
- This prefix command shows the ‘magit-blame’ suffix command along
- with the appropriate infix arguments in a popup buffer. See *note
- Initiating a commit: Initiating a commit.
-
-‘C-c M-g p’ (‘magit-blob-previous’)
-
- Visit the previous blob which modified the current file.
-
-\1f
-File: magit.info, Node: Minor mode for buffers visiting blobs, Prev: Minor mode for buffers visiting files, Up: Miscellaneous
-
-8.8 Minor mode for buffers visiting blobs
-=========================================
-
-The ‘magit-blob-mode’ enables certain Magit features in blob-visiting
-buffers. Such buffers can be created using ‘magit-find-file’ and some
-of the commands mentioned below, which also take care of turning on this
-minor mode. Currently this mode only establishes a few key bindings,
-but this might be e
-
-‘p’ (‘magit-blob-previous’)
-
- Visit the previous blob which modified the current file.
-
-‘n’ (‘magit-blob-next’)
-
- Visit the next blob which modified the current file.
-
-‘q’ (‘magit-kill-this-buffer’)
-
- Kill the current buffer.
-
-\1f
-File: magit.info, Node: Customizing, Next: Plumbing, Prev: Miscellaneous, Up: Top
-
-9 Customizing
-*************
-
-Both Git and Emacs are highly customizable. Magit is both a Git
-porcelain as well as an Emacs package, so it makes sense to customize it
-using both Git variables as well as Emacs options. However this
-flexibility doesn’t come without problems, including but not limited to
-the following.
-
- • Some Git variables automatically have an effect in Magit without
- requiring any explicit support. Sometimes that is desirable - in
- other cases, it breaks Magit.
-
- When a certain Git setting breaks Magit but you want to keep using
- that setting on the command line, then that can be accomplished by
- overriding the value for Magit only by appending something like
- ‘("-c" "some.variable=compatible-value")’ to
- ‘magit-git-global-arguments’.
-
- • Certain settings like ‘fetch.prune=true’ are respected by Magit
- commands (because they simply call the respective Git command) but
- their value is not reflected in the respective popup buffers. In
- this case the ‘--prune’ argument in ‘magit-fetch-popup’ might be
- active or inactive depending on the value of
- ‘magit-fetch-arguments’ only, but that doesn’t keep the Git
- variable from being honored by the suffix commands anyway. So
- pruning might happen despite the the ‘--prune’ arguments being
- displayed in a way that seems to indicate that no pruning will
- happen.
-
- I intend to address these and similar issues in a future release.
-
-* Menu:
-
-* Per-repository configuration::
-* Essential settings::
-
-\1f
-File: magit.info, Node: Per-repository configuration, Next: Essential settings, Up: Customizing
-
-9.1 Per-repository configuration
-================================
-
-Magit can be configured on a per-repository level using both Git
-variables as well as Emacs options.
-
- To set a Git variable for one repository only, simply set it in
-‘/path/to/repo/.git/config’ instead of ‘$HOME/.gitconfig’ or
-‘/etc/gitconfig’. See *note (gitman)git-config:: .
-
- Similarly, Emacs options can be set for one repository only by
-editing ‘/path/to/repo/.dir-locals.el’. See *note (emacs)Directory
-Variables::. For example to disable automatic refreshes of
-file-visiting buffers in just one huge repository use this:
-
- • ‘/path/to/huge/repo/.dir-locals.el’
-
- ((nil . ((magit-refresh-buffers . nil))
-
- If you want to apply the same settings to several, but not all,
-repositories then keeping the repository-local config files in sync
-would quickly become annoying. To avoid that you can create config
-files for certain classes of repositories (e.g. "huge repositories")
-and then include those files in the per-repository config files. For
-example:
-
- • ‘/path/to/huge/repo/.git/config’
-
- [include]
- path = /path/to/huge-gitconfig
-
- • ‘/path/to/huge-gitconfig’
-
- [status]
- showUntrackedFiles = no
-
- • ‘$HOME/.emacs.d/init.el’
-
- (dir-locals-set-class-variables 'huge-git-repository
- '((nil . ((magit-refresh-buffers . nil)))))
-
- (dir-locals-set-directory-class
- "/path/to/huge/repo/" 'huge-git-repository)
-
-\1f
-File: magit.info, Node: Essential settings, Prev: Per-repository configuration, Up: Customizing
-
-9.2 Essential settings
-======================
-
-The next two sections list and discuss several variables that many users
-might want to customize, for safety and/or performance reasons.
-
-* Menu:
-
-* Safety::
-* Performance::
-
-\1f
-File: magit.info, Node: Safety, Next: Performance, Up: Essential settings
-
-9.2.1 Safety
-------------
-
-This section discusses various variables that you might want to change
-(or *not* change) for safety reasons.
-
- Git keeps *committed* changes around long enough for users to recover
-changes they have accidentally been deleted. It does not do the same
-for *uncommitted* changes in the working tree and not even the index
-(the staging area). Because Magit makes it so easy to modify
-uncommitted changes, it also makes it easy to shoot yourself in the foot
-in the process. For that reason Magit provides three global modes that
-save *tracked* files to work-in-progress references after or before
-certain actions. See *note Wip modes: Wip modes.
-
- These modes are not enabled by default because of performance
-concerns. Instead a lot of potentially destructive commands require
-confirmation every time they are used. In many cases this can be
-disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion
-and confirmation: Completion and confirmation.). If you enable the
-various wip modes then you should add ‘safe-with-wip’ to this list.
-
- Similarly it isn’t necessary to require confirmation before moving a
-file to the system trash - if you trashed a file by mistake then you can
-recover it from the there. Option ‘magit-delete-by-moving-to-trash’
-controls whether the system trash is used, which is the case by default.
-Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might
-want to change that.
-
- By default buffers visiting files are automatically reverted when the
-visited file changes on disk. This isn’t as risky as it might seem, but
-to make an informed decision you should see *note Risk of Reverting
-Automatically: Risk of Reverting Automatically.
-
-\1f
-File: magit.info, Node: Performance, Prev: Safety, Up: Essential settings
-
-9.2.2 Performance
------------------
-
-After Magit has run ‘git’ for side-effects, it also refreshes the
-current Magit buffer and the respective status buffer. This is
-necessary because otherwise outdated information might be displayed
-without the user noticing. Magit buffers are updated by recreating
-their content from scratch, which makes updating simpler and less
-error-prone, but also more costly. Keeping it simple and just
-re-creating everything from scratch is an old design decision and
-departing from that will require major refactoring.
-
- I plan to do that in time for the next major release. I also intend
-to create logs and diffs asynchronously, which should also help a lot
-but also requires major refactoring.
-
- Meanwhile you can tell Magit to only automatically refresh the
-current Magit buffer, but not the status buffer. If you do that, then
-the status buffer is only refreshed automatically if it itself is the
-current buffer.
-
- (setq magit-refresh-status-buffer nil)
-
- You should also check whether any third-party packages have added
-anything to ‘magit-refresh-buffer-hook’, ‘magit-status-refresh-hook’,
-‘magit-pre-refresh-hook’, and ‘magit-post-refresh-hook’. If so, then
-check whether those additions impacts performance significantly.
-Setting ‘magit-refresh-verbose’ and then inspecting the output in the
-‘*Messages*’ buffer, should help doing so.
-
- Magit also reverts buffers which visit files located inside the
-current repository, when the visited file changes on disk. That is
-implemented on top of ‘auto-revert-mode’ from the built-in library
-‘autorevert’. To figure out whether that impacts performance, check
-whether performance is significantly worse, when many buffers exist
-and/or when some buffers visit files using Tramp. If so, then this
-should help.
-
- (setq auto-revert-buffer-list-filter
- 'magit-auto-revert-repository-buffers-p)
-
- For alternative approaches see *note Automatic Reverting of
-File-Visiting Buffers: Automatic Reverting of File-Visiting Buffers.
-
- If you have enabled any features that are disabled by default, then
-you should check whether they impact performance significantly. It’s
-likely that they were not enabled by default because it is known that
-they reduce performance at least in large repositories.
-
- If performance is only slow inside certain unusually large
-repositories, then you might want to disable certain features on a
-per-repository or per-repository-class basis only. See *note
-Per-repository configuration: Per-repository configuration.
-
-Microsoft Windows Performance
-.............................
-
-In order to update the status buffer, ‘git’ has to be run a few dozen
-times. That is only problematic on Microsoft Windows, because that
-operating system is exceptionally slow at starting processes. Sadly
-this is an issue that can only be fixed by Microsoft itself, and they
-don’t appear to particularly interested in doing so.
-
- Beside the subprocess issue, there also exist other Window-specific
-performance issues, some of which can be worked around. The maintainers
-of "Git for Windows" try to reduce their effect, and in order to benefit
-from the latest performance tweaks, should always use the latest
-release. Magit too tries to work around some Windows-specific issues.
-
- According to some sources setting the following Git variables can
-also help.
-
- git config --global core.preloadindex true # default since v2.1
- git config --global core.fscache true # default since v2.8
- git config --global gc.auto 256
-
- You should also check whether an anti-virus program is slowing things
-down.
-
-Log Performance
-...............
-
-When showing logs, Magit limits the number of commits initially shown in
-the hope that this avoids unnecessary work. When using ‘--graph’ is
-used, then this unfortunately does not have the desired effect for large
-histories. Junio, Git’s maintainer, said on the git mailing list
-(<http://www.spinics.net/lists/git/msg232230.html>): "‘--graph’ wants to
-compute the whole history and the max-count only affects the output
-phase after ‘--graph’ does its computation".
-
- In other words, it’s not that Git is slow at outputting the
-differences, or that Magit is slow at parsing the output - the problem
-is that Git first goes outside and has a smoke.
-
- We actually work around this issue by limiting the number of commits
-not only by using ‘-<N>’ but by also using a range. But unfortunately
-that’s not always possible.
-
- In repositories with more than a few thousand commits ‘--graph’
-should never be a member of ‘magit-log-section-arguments’. That
-variable is used in the status buffer which is refreshed every time you
-run any Magit command.
-
- Using ‘--color --graph’ is even slower. Magit uses code that is part
-of Emacs to turn control characters into faces. That code is pretty
-slow and this is quite noticeable when showing a log with many branches
-and merges. For that reason ‘--color’ is not enabled by default
-anymore. Consider leaving it at that.
-
-Diff Performance
-................
-
-If diffs are slow, then consider turning off some optional diff features
-by setting all or some of the following variables to ‘nil’:
-‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’,
-‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and
-‘magit-diff-refine-hunk’.
-
- When showing a commit instead of some arbitrary diff, then some
-additional information is displayed. Calculating this information can
-be quite expensive given certain circumstances. If looking at a commit
-using ‘magit-revision-mode’ takes considerably more time than looking at
-the same commit in ‘magit-diff-mode’, then consider setting
-‘magit-revision-insert-related-refs’ to ‘nil’.
-
-Refs Buffer Performance
-.......................
-
-When refreshing the "references buffer" is slow, then that’s usually
-because several hundred refs are being displayed. The best way to
-address that is to display fewer refs, obviously.
-
- If you are not, or only mildly, interested in seeing the list of
-tags, then start by not displaying them:
-
- (remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
-
- Then you should also make sure that the listed remote branches
-actually all exist. You can do so by pruning branches which no longer
-exist using ‘f-pa’.
-
-Committing Performance
-......................
-
-When you initiate a commit, then Magit by default automatically shows a
-diff of the changes you are about to commit. For large commits this can
-take a long time, which is especially distracting when you are
-committing large amounts of generated data which you don’t actually
-intend to inspect before committing. This behavior can be turned off
-using:
-
- (remove-hook 'server-switch-hook 'magit-commit-diff)
-
- Then you can type ‘C-c C-d’ to show the diff when you actually want
-to see it, but only then. Alternatively you can leave the hook alone
-and just type ‘C-g’ in those cases when it takes to long to generate the
-diff. If you do that, then you will end up with a broken diff buffer,
-but doing it this way has the advantage that you usually get to see the
-diff, which is useful because it increases the odds that you spot
-potential issues.
-
-The built-in VC Package
-.......................
-
-Emacs comes with a version control interface called "VC", see *note
-(emacs)Version Control::. It is enabled be default and if you don’t use
-it in addition to Magit, then you should disable it to keep it from
-performing unnecessary work:
-
- (setq vc-handled-backends nil)
-
- You can also disable its use only for Git but keep using it when
-using another version control system:
-
- (setq vc-handled-backends (delq 'Git vc-handled-backends))
-
-\1f
-File: magit.info, Node: Plumbing, Next: FAQ, Prev: Customizing, Up: Top
-
-10 Plumbing
-***********
-
-The following sections describe how to use several of Magit’s core
-abstractions to extend Magit itself or implement a separate extension.
-
- A few of the low-level features used by Magit have been factored out
-into separate libraries/packages, so that they can be used by other
-packages, without having to depend on Magit. These libraries are
-described in separate manuals, see *note (with-editor)Top:: and *note
-(magit-popup)Top::.
-
-* Menu:
-
-* Calling Git::
-* Section plumbing::
-* Refreshing buffers::
-* Conventions::
-
-\1f
-File: magit.info, Node: Calling Git, Next: Section plumbing, Up: Plumbing
-
-10.1 Calling Git
-================
-
-Magit provides many specialized functions for calling Git. All of these
-functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and
-have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or
-‘magit-git-’ (which is also used for other things).
-
- All of these functions accept an indefinite number of arguments,
-which are strings that specify command line arguments for git (or in
-some cases an arbitrary executable). These arguments are flattened
-before being passed on to the executable; so instead of strings they can
-also be lists of strings and arguments that are ‘nil’ are silently
-dropped. Some of these functions also require a single mandatory
-argument before these command line arguments.
-
- Roughly speaking these functions run Git either to get some value or
-for side-effect. The functions that return a value are useful to
-collect the information necessary to populate a Magit buffer, while the
-others are used to implement Magit commands.
-
- The functions in the value-only group always run synchronously, and
-they never trigger a refresh. The function in the side-effect group can
-be further divided into subgroups depending on whether they run Git
-synchronously or asynchronously, and depending on whether they trigger a
-refresh when the executable has finished.
-
-* Menu:
-
-* Getting a value from Git::
-* Calling Git for effect::
-
-\1f
-File: magit.info, Node: Getting a value from Git, Next: Calling Git for effect, Up: Calling Git
-
-10.1.1 Getting a value from Git
--------------------------------
-
-These functions run Git in order to get a value, either its exit status
-or its output. Of course you could also use them to run Git commands
-that have side-effects, but that should be avoided.
-
- -- Function: magit-git-exit-code &rest args
-
- Executes git with ARGS and returns its exit code.
-
- -- Function: magit-git-success &rest args
-
- Executes git with ARGS and returns ‘t’ if the exit code is ‘0’,
- ‘nil’ otherwise.
-
- -- Function: magit-git-failure &rest args
-
- Executes git with ARGS and returns ‘t’ if the exit code is ‘1’,
- ‘nil’ otherwise.
-
- -- Function: magit-git-true &rest args
-
- Executes git with ARGS and returns ‘t’ if the first line printed by
- git is the string "true", ‘nil’ otherwise.
-
- -- Function: magit-git-false &rest args
-
- Executes git with ARGS and returns ‘t’ if the first line printed by
- git is the string "false", ‘nil’ otherwise.
-
- -- Function: magit-git-insert &rest args
-
- Executes git with ARGS and inserts its output at point.
-
- -- Function: magit-git-string &rest args
-
- Executes git with ARGS and returns the first line of its output.
- If there is no output or if it begins with a newline character,
- then this returns ‘nil’.
-
- -- Function: magit-git-lines &rest args
-
- Executes git with ARGS and returns its output as a list of lines.
- Empty lines anywhere in the output are omitted.
-
- -- Function: magit-git-items &rest args
-
- Executes git with ARGS and returns its null-separated output as a
- list. Empty items anywhere in the output are omitted.
-
- If the value of option ‘magit-git-debug’ is non-nil and git exits
- with a non-zero exit status, then warn about that in the echo area
- and add a section containing git’s standard error in the current
- repository’s process buffer.
-
- When an error occurs when using one of the above functions, then that
-is usually due to a bug, i.e. the use of an argument which is not
-actually supported. Such errors are usually not reported, but when they
-occur we need to be able to debug them.
-
- -- User Option: magit-git-debug
-
- Whether to report errors that occur when using ‘magit-git-insert’,
- ‘magit-git-string’, ‘magit-git-lines’, or ‘magit-git-items’. This
- does not actually raise an error. Instead a message is shown in
- the echo area, and git’s standard error is insert into a new
- section in the current repository’s process buffer.
-
- -- Function: magit-git-str &rest args
-
- This is a variant of ‘magit-git-string’ that ignores the option
- ‘magit-git-debug’. It is mainly intended to be used while handling
- errors in functions that do respect that option. Using such a
- function while handing an error could cause yet another error and
- therefore lead to an infinite recursion. You probably won’t ever
- need to use this function.
-
-\1f
-File: magit.info, Node: Calling Git for effect, Prev: Getting a value from Git, Up: Calling Git
-
-10.1.2 Calling Git for effect
------------------------------
-
-These functions are used to run git to produce some effect. Most Magit
-commands that actually run git do so by using such a function.
-
- Because we do not need to consume git’s output when using these
-functions, their output is instead logged into a per-repository buffer,
-which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’
-elsewhere.
-
- These functions can have an effect in two distinct ways. Firstly,
-running git may change something, i.e. create or push a new commit.
-Secondly, that change may require that Magit buffers are refreshed to
-reflect the changed state of the repository. But refreshing isn’t
-always desirable, so only some of these functions do perform such a
-refresh after git has returned.
-
- Sometimes it is useful to run git asynchronously. For example, when
-the user has just initiated a push, then there is no reason to make her
-wait until that has completed. In other cases it makes sense to wait
-for git to complete before letting the user do something else. For
-example after staging a change it is useful to wait until after the
-refresh because that also automatically moves to the next change.
-
- -- Function: magit-call-git &rest args
-
- Calls git synchronously with ARGS.
-
- -- Function: magit-call-process program &rest args
-
- Calls PROGRAM synchronously with ARGS.
-
- -- Function: magit-run-git &rest args
-
- Calls git synchronously with ARGS and then refreshes.
-
- -- Function: magit-run-git-with-input input &rest args
-
- Calls git synchronously with ARGS and sends it INPUT on standard
- input.
-
- INPUT should be a buffer or the name of an existing buffer. The
- content of that buffer is used as the process’ standard input.
- After the process returns a refresh is performed.
-
- As a special case, INPUT may also be nil. In that case the content
- of the current buffer is used as standard input and *no* refresh is
- performed.
-
- This function actually runs git asynchronously. But then it waits
- for the process to return, so the function itself is synchronous.
-
- -- Function: magit-run-git-with-logfile file &rest args
-
- Calls git synchronously with ARGS. The process’ output is saved in
- FILE. This is rarely useful and so this function might be removed
- in the future.
-
- This function actually runs git asynchronously. But then it waits
- for the process to return, so the function itself is synchronous.
-
- -- Function: magit-git &rest args
-
- Calls git synchronously with ARGS for side-effects only. This
- function does not refresh the buffer.
-
- -- Function: magit-git-wash washer &rest args
-
- Execute Git with ARGS, inserting washed output at point. Actually
- first insert the raw output at point. If there is no output call
- ‘magit-cancel-section’. Otherwise temporarily narrow the buffer to
- the inserted text, move to its beginning, and then call function
- WASHER with no argument.
-
- And now for the asynchronous variants.
-
- -- Function: magit-run-git-async &rest args
-
- Start Git, prepare for refresh, and return the process object.
- ARGS is flattened and then used as arguments to Git.
-
- Display the command line arguments in the echo area.
-
- After Git returns some buffers are refreshed: the buffer that was
- current when this function was called (if it is a Magit buffer and
- still alive), as well as the respective Magit status buffer.
- Unmodified buffers visiting files that are tracked in the current
- repository are reverted if ‘magit-revert-buffers’ is non-nil.
-
- -- Function: magit-run-git-with-editor &rest args
-
- Export GIT_EDITOR and start Git. Also prepare for refresh and
- return the process object. ARGS is flattened and then used as
- arguments to Git.
-
- Display the command line arguments in the echo area.
-
- After Git returns some buffers are refreshed: the buffer that was
- current when this function was called (if it is a Magit buffer and
- still alive), as well as the respective Magit status buffer.
-
- -- Function: magit-start-git &rest args
-
- Start Git, prepare for refresh, and return the process object.
-
- If INPUT is non-nil, it has to be a buffer or the name of an
- existing buffer. The buffer content becomes the processes standard
- input.
-
- Option ‘magit-git-executable’ specifies the Git executable and
- option ‘magit-git-global-arguments’ specifies constant arguments.
- The remaining arguments ARGS specify arguments to Git. They are
- flattened before use.
-
- After Git returns, some buffers are refreshed: the buffer that was
- current when this function was called (if it is a Magit buffer and
- still alive), as well as the respective Magit status buffer.
- Unmodified buffers visiting files that are tracked in the current
- repository are reverted if ‘magit-revert-buffers’ is non-nil.
-
- -- Function: magit-start-process &rest args
-
- Start PROGRAM, prepare for refresh, and return the process object.
-
- If optional argument INPUT is non-nil, it has to be a buffer or the
- name of an existing buffer. The buffer content becomes the
- processes standard input.
-
- The process is started using ‘start-file-process’ and then setup to
- use the sentinel ‘magit-process-sentinel’ and the filter
- ‘magit-process-filter’. Information required by these functions is
- stored in the process object. When this function returns the
- process has not started to run yet so it is possible to override
- the sentinel and filter.
-
- After the process returns, ‘magit-process-sentinel’ refreshes the
- buffer that was current when ‘magit-start-process’ was called (if
- it is a Magit buffer and still alive), as well as the respective
- Magit status buffer. Unmodified buffers visiting files that are
- tracked in the current repository are reverted if
- ‘magit-revert-buffers’ is non-nil.
-
- -- Variable: magit-this-process
-
- The child process which is about to start. This can be used to
- change the filter and sentinel.
-
- -- Variable: magit-process-raise-error
-
- When this is non-nil, then ‘magit-process-sentinel’ raises an error
- if git exits with a non-zero exit status. For debugging purposes.
-
-\1f
-File: magit.info, Node: Section plumbing, Next: Refreshing buffers, Prev: Calling Git, Up: Plumbing
-
-10.2 Section plumbing
-=====================
-
-* Menu:
-
-* Creating sections::
-* Section selection::
-* Matching sections::
-
-\1f
-File: magit.info, Node: Creating sections, Next: Section selection, Up: Section plumbing
-
-10.2.1 Creating sections
-------------------------
-
- -- Macro: magit-insert-section &rest args
-
- Insert a section at point.
-
- TYPE is the section type, a symbol. Many commands that act on the
- current section behave differently depending on that type. Also if
- a variable ‘magit-TYPE-section-map’ exists, then use that as the
- text-property ‘keymap’ of all text belonging to the section (but
- this may be overwritten in subsections). TYPE can also have the
- form ‘(eval FORM)’ in which case FORM is evaluated at runtime.
-
- Optional VALUE is the value of the section, usually a string that
- is required when acting on the section.
-
- When optional HIDE is non-nil collapse the section body by default,
- i.e. when first creating the section, but not when refreshing the
- buffer. Otherwise, expand it by default. This can be overwritten
- using ‘magit-section-set-visibility-hook’. When a section is
- recreated during a refresh, then the visibility of predecessor is
- inherited and HIDE is ignored (but the hook is still honored).
-
- BODY is any number of forms that actually insert the section’s
- heading and body. Optional NAME, if specified, has to be a symbol,
- which is then bound to the struct of the section being inserted.
-
- Before BODY is evaluated the ‘start’ of the section object is set
- to the value of ‘point’ and after BODY was evaluated its ‘end’ is
- set to the new value of ‘point’; BODY is responsible for moving
- ‘point’ forward.
-
- If it turns out inside BODY that the section is empty, then
- ‘magit-cancel-section’ can be used to abort and remove all traces
- of the partially inserted section. This can happen when creating a
- section by washing Git’s output and Git didn’t actually output
- anything this time around.
-
- -- Function: magit-insert-heading &rest args
-
- Insert the heading for the section currently being inserted.
-
- This function should only be used inside ‘magit-insert-section’.
-
- When called without any arguments, then just set the ‘content’ slot
- of the object representing the section being inserted to a marker
- at ‘point’. The section should only contain a single line when
- this function is used like this.
-
- When called with arguments ARGS, which have to be strings, then
- insert those strings at point. The section should not contain any
- text before this happens and afterwards it should again only
- contain a single line. If the ‘face’ property is set anywhere
- inside any of these strings, then insert all of them unchanged.
- Otherwise use the ‘magit-section-heading’ face for all inserted
- text.
-
- The ‘content’ property of the section struct is the end of the
- heading (which lasts from ‘start’ to ‘content’) and the beginning
- of the body (which lasts from ‘content’ to ‘end’). If the value of
- ‘content’ is nil, then the section has no heading and its body
- cannot be collapsed. If a section does have a heading then its
- height must be exactly one line, including a trailing newline
- character. This isn’t enforced; you are responsible for getting it
- right. The only exception is that this function does insert a
- newline character if necessary.
-
- -- Function: magit-cancel-section
-
- Cancel the section currently being inserted. This exits the
- innermost call to ‘magit-insert-section’ and removes all traces of
- what has already happened inside that call.
-
- -- Function: magit-define-section-jumper sym title &optional value
-
- Define an interactive function to go to section SYM. TITLE is the
- displayed title of the section.
-
-\1f
-File: magit.info, Node: Section selection, Next: Matching sections, Prev: Creating sections, Up: Section plumbing
-
-10.2.2 Section selection
-------------------------
-
- -- Function: magit-current-section
-
- Return the section at point.
-
- -- Function: magit-region-sections
-
- Return a list of the selected sections.
-
- When the region is active and constitutes a valid section
- selection, then return a list of all selected sections. This is
- the case when the region begins in the heading of a section and
- ends in the heading of a sibling of that first section. When the
- selection is not valid then return nil. Most commands that can act
- on the selected sections, then instead just act on the current
- section, the one point is in.
-
- When the region looks like it would in any other buffer then the
- selection is invalid. When the selection is valid then the region
- uses the ‘magit-section-highlight’. This does not apply to diffs
- where things get a bit more complicated, but even here if the
- region looks like it usually does, then that’s not a valid
- selection as far as this function is concerned.
-
- -- Function: magit-region-values &rest types
-
- Return a list of the values of the selected sections.
-
- Also see ‘magit-region-sections’ whose doc-string explains when a
- region is a valid section selection. If the region is not active
- or is not a valid section selection, then return nil. If optional
- TYPES is non-nil then the selection not only has to be valid; the
- types of all selected sections additionally have to match one of
- TYPES, or nil is returned.
-
-\1f
-File: magit.info, Node: Matching sections, Prev: Section selection, Up: Section plumbing
-
-10.2.3 Matching sections
-------------------------
-
-‘M-x magit-describe-section’ (‘magit-describe-section’)
-
- Show information about the section at point. This command is
- intended for debugging purposes.
-
- -- Function: magit-section-ident
-
- Return an unique identifier for SECTION. The return value has the
- form ‘((TYPE . VALUE)...)’.
-
- -- Function: magit-get-section
-
- Return the section identified by IDENT. IDENT has to be a list as
- returned by ‘magit-section-ident’.
-
- -- Function: magit-section-match condition &optional section
-
- Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the
- section at point.
-
- Conditions can take the following forms:
- • ‘(CONDITION...)’
-
- matches if any of the CONDITIONs matches.
-
- • ‘[TYPE...]’
-
- matches if the first TYPE matches the type of the section at
- point, the second matches that of its parent, and so on.
-
- • ‘[* TYPE...]’
-
- matches sections that match [TYPE…] and also recursively all
- their child sections.
-
- • ‘TYPE’
-
- matches TYPE regardless of its parents.
- Each TYPE is a symbol. Note that is not necessary to specify all
- TYPEs up to the root section as printed by ‘magit-describe-type’,
- unless of course your want to be that precise.
-
- -- Function: magit-section-when condition &rest body
-
- If the section at point matches CONDITION evaluate BODY.
-
- If the section matches evaluate BODY forms sequentially and return
- the value of the last one, or if there are no BODY forms return the
- value of the section. If the section does not match return nil.
-
- See ‘magit-section-match’ for the forms CONDITION can take.
-
- -- Function: magit-section-case &rest clauses
-
- Choose among clauses on the type of the section at point.
-
- Each clause looks like (CONDITION BODY…). The type of the section
- is compared against each CONDITION; the BODY forms of the first
- match are evaluated sequentially and the value of the last form is
- returned. Inside BODY the symbol ‘it’ is bound to the section at
- point. If no clause succeeds or if there is no section at point
- return nil.
-
- See ‘magit-section-match’ for the forms CONDITION can take.
- Additionally a CONDITION of t is allowed in the final clause and
- matches if no other CONDITION match, even if there is no section at
- point.
-
- -- Variable: magit-root-section
-
- The root section in the current buffer. All other sections are
- descendants of this section. The value of this variable is set by
- ‘magit-insert-section’ and you should never modify it.
-
- For diff related sections a few additional tools exist.
-
- -- Function: magit-diff-type &optional section
-
- Return the diff type of SECTION.
-
- The returned type is one of the symbols ‘staged’, ‘unstaged’,
- ‘committed’, or ‘undefined’. This type serves a similar purpose as
- the general type common to all sections (which is stored in the
- ‘type’ slot of the corresponding ‘magit-section’ struct) but takes
- additional information into account. When the SECTION isn’t
- related to diffs and the buffer containing it also isn’t a
- diff-only buffer, then return nil.
-
- Currently the type can also be one of ‘tracked’ and ‘untracked’,
- but these values are not handled explicitly in every place they
- should be. A possible fix could be to just return nil here.
-
- The section has to be a ‘diff’ or ‘hunk’ section, or a section
- whose children are of type ‘diff’. If optional SECTION is nil,
- return the diff type for the current section. In buffers whose
- major mode is ‘magit-diff-mode’ SECTION is ignored and the type is
- determined using other means. In ‘magit-revision-mode’ buffers the
- type is always ‘committed’.
-
- -- Function: magit-diff-scope &optional section strict
-
- Return the diff scope of SECTION or the selected section(s).
-
- A diff’s "scope" describes what part of a diff is selected, it is a
- symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or
- ‘list’. Do not confuse this with the diff "type", as returned by
- ‘magit-diff-type’.
-
- If optional SECTION is non-nil, then return the scope of that,
- ignoring the sections selected by the region. Otherwise return the
- scope of the current section, or if the region is active and
- selects a valid group of diff related sections, the type of these
- sections, i.e. ‘hunks’ or ‘files’. If SECTION (or if the current
- section that is nil) is a ‘hunk’ section and the region starts and
- ends inside the body of a that section, then the type is ‘region’.
-
- If optional STRICT is non-nil then return nil if the diff type of
- the section at point is ‘untracked’ or the section at point is not
- actually a ‘diff’ but a ‘diffstat’ section.
-
-\1f
-File: magit.info, Node: Refreshing buffers, Next: Conventions, Prev: Section plumbing, Up: Plumbing
-
-10.3 Refreshing buffers
-=======================
-
-All commands that create a new Magit buffer or change what is being
-displayed in an existing buffer do so by calling ‘magit-mode-setup’.
-Among other things, that function sets the buffer local values of
-‘default-directory’ (to the top-level of the repository),
-‘magit-refresh-function’, and ‘magit-refresh-args’.
-
- Buffers are refreshed by calling the function that is the local value
-of ‘magit-refresh-function’ (a function named ‘magit-*-refresh-buffer’,
-where ‘*’ may be something like ‘diff’) with the value of
-‘magit-refresh-args’ as arguments.
-
- -- Macro: magit-mode-setup buffer switch-func mode refresh-func
- &optional refresh-args
-
- This function displays and selects BUFFER, turns on MODE, and
- refreshes a first time.
-
- This function displays and optionally selects BUFFER by calling
- ‘magit-mode-display-buffer’ with BUFFER, MODE and SWITCH-FUNC as
- arguments. Then it sets the local value of
- ‘magit-refresh-function’ to REFRESH-FUNC and that of
- ‘magit-refresh-args’ to REFRESH-ARGS. Finally it creates the buffer
- content by calling REFRESH-FUNC with REFRESH-ARGS as arguments.
-
- All arguments are evaluated before switching to BUFFER.
-
- -- Function: magit-mode-display-buffer buffer mode &optional
- switch-function
-
- This function display BUFFER in some window and select it. BUFFER
- may be a buffer or a string, the name of a buffer. The buffer is
- returned.
-
- Unless BUFFER is already displayed in the selected frame, store the
- previous window configuration as a buffer local value, so that it
- can later be restored by ‘magit-mode-bury-buffer’.
-
- The buffer is displayed and selected using SWITCH-FUNCTION. If that
- is ‘nil’ then ‘pop-to-buffer’ is used if the current buffer’s major
- mode derives from ‘magit-mode’. Otherwise ‘switch-to-buffer’ is
- used.
-
- -- Variable: magit-refresh-function
-
- The value of this buffer-local variable is the function used to
- refresh the current buffer. It is called with ‘magit-refresh-args’
- as arguments.
-
- -- Variable: magit-refresh-args
-
- The list of arguments used by ‘magit-refresh-function’ to refresh
- the current buffer. ‘magit-refresh-function’ is called with these
- arguments.
-
- The value is usually set using ‘magit-mode-setup’, but in some
- cases it’s also useful to provide commands which can change the
- value. For example, the ‘magit-diff-refresh-popup’ can be used to
- change any of the arguments used to display the diff, without
- having to specify again which differences should be shown.
- ‘magit-diff-more-context’, ‘magit-diff-less-context’, and
- ‘magit-diff-default-context’ change just the ‘-U<N>’ argument. In
- both case this is done by changing the value of this variable and
- then calling this ‘magit-refresh-function’.
-
-\1f
-File: magit.info, Node: Conventions, Prev: Refreshing buffers, Up: Plumbing
-
-10.4 Conventions
-================
-
-* Menu:
-
-* Confirmation and completion::
-* Theming Faces::
-
-\1f
-File: magit.info, Node: Confirmation and completion, Next: Theming Faces, Up: Conventions
-
-10.4.1 Confirmation and completion
-----------------------------------
-
-Dangerous operations that may lead to data loss have to be confirmed by
-default. With a multi-section selection, this is done using questions
-that can be answered with "yes" or "no". When the region isn’t active,
-or if it doesn’t constitute a valid section selection, then such
-commands instead read a single item in the minibuffer. When the value
-of the current section is among the possible choices, then that is
-presented as default choice. To confirm the action on a single item,
-the user has to answer ‘RET’ (instead of "yes"), and to abort, ‘C-g’
-(instead of "no"). But alternatively the user may also select another
-item, just like if the command had been invoked with no suitable section
-at point at all.
-
-\1f
-File: magit.info, Node: Theming Faces, Prev: Confirmation and completion, Up: Conventions
-
-10.4.2 Theming Faces
---------------------
-
-The default theme uses blue for local branches, green for remote
-branches, and goldenrod (brownish yellow) for tags. When creating a new
-theme, you should probably follow that example. If your theme already
-uses other colors, then stick to that.
-
- In older releases these reference faces used to have a background
-color and a box around them. The basic default faces no longer do so,
-to make Magit buffers much less noisy, and you should follow that
-example at least with regards to boxes. (Boxes were used in the past to
-work around a conflict between the highlighting overlay and text
-property backgrounds. That’s no longer necessary because highlighting
-no longer causes other background colors to disappear.) Alternatively
-you can keep the background color and/or box, but then have to take
-special care to adjust ‘magit-branch-current’ accordingly. By default
-it looks mostly like ‘magit-branch-local’, but with a box (by default
-the former is the only face that uses a box, exactly so that it sticks
-out). If the former also uses a box, then you have to make sure that it
-differs in some other way from the latter.
-
- The most difficult faces to theme are those related to diffs,
-headings, highlighting, and the region. There are faces that fall into
-all four groups - expect to spend some time getting this right.
-
- The ‘region’ face in the default theme, in both the light and dark
-variants, as well as in many other themes, distributed with Emacs or by
-third-parties, is very ugly. It is common to use a background color
-that really sticks out, which is ugly but if that were the only problem
-then it would be acceptable. Unfortunately many themes also set the
-foreground color, which ensures that all text within the region is
-readable. Without doing that there might be cases where some foreground
-color is too close to the region background color to still be readable.
-But it also means that text within the region loses all syntax
-highlighting.
-
- I consider the work that went into getting the ‘region’ face right to
-be a good indicator for the general quality of a theme. My
-recommendation for the ‘region’ face is this: use a background color
-slightly different from the background color of the ‘default’ face, and
-do not set the foreground color at all. So for a light theme you might
-use a light (possibly tinted) gray as the background color of ‘default’
-and a somewhat darker gray for the background of ‘region’. That should
-usually be enough to not collide with the foreground color of any other
-face. But if some other faces also set a light gray as background
-color, then you should also make sure it doesn’t collide with those (in
-some cases it might be acceptable though).
-
- Magit only uses the ‘region’ face when the region is "invalid" by its
-own definition. In a Magit buffer the region is used to either select
-multiple sibling sections, so that commands which support it act on all
-of these sections instead of just the current section, or to select
-lines within a single hunk section. In all other cases, the section is
-considered invalid and Magit won’t act on it. But such invalid sections
-happen, either because the user has not moved point enough yet to make
-it valid or because she wants to use a non-magit command to act on the
-region, e.g. ‘kill-region’.
-
- So using the regular ‘region’ face for invalid sections is a feature.
-It tells the user that Magit won’t be able to act on it. It’s
-acceptable if that face looks a bit odd and even (but less so) if it
-collides with the background colors of section headings and other things
-that have a background color.
-
- Magit highlights the current section. If a section has subsections,
-then all of them are highlighted. This is done using faces that have
-"highlight" in their names. For most sections,
-‘magit-section-highlight’ is used for both the body and the heading.
-Like the ‘region’ face, it should only set the background color to
-something similar to that of ‘default’. The highlight background color
-must be different from both the ‘region’ background color and the
-‘default’ background color.
-
- For diff related sections Magit uses various faces to highlight
-different parts of the selected section(s). Note that hunk headings,
-unlike all other section headings, by default have a background color,
-because it is useful to have very visible separators between hunks.
-That face ‘magit-diff-hunk-heading’, should be different from both
-‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as
-well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’.
-By default we do that by changing the foreground color. Changing the
-background color would lead to complications, and there are already
-enough we cannot get around. (Also note that it is generally a good
-idea for section headings to always be bold, but only for sections that
-have subsections).
-
- When there is a valid region selecting diff-related sibling sections,
-i.e. multiple files or hunks, then the bodies of all these sections use
-the respective highlight faces, but additionally the headings instead
-use one of the faces ‘magit-diff-file-heading-selection’ or
-‘magit-diff-hunk-heading-selection’. These faces have to be different
-from the regular highlight variants to provide explicit visual
-indication that the region is active.
-
- When theming diff related faces, start by setting the option
-‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only
-refine the current hunk or not use hunk refinement at all, but some of
-the users of your theme want all hunks to be refined, so you have to
-cater to that.
-
- (Also turn on ‘magit-diff-highlight-indentation’,
-‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and
-insert some whitespace errors into the code you use for testing.)
-
- For e.g. "added lines" you have to adjust three faces:
-‘magit-diff-added’, ‘magit-diff-added-highlight’, and
-‘smerge-refined-added’. Make sure that the latter works well with both
-of the former, as well as ‘smerge-other’ and ‘diff-added’. Then do the
-same for the removed lines, context lines, lines added by us, and lines
-added by them. Also make sure the respective added, removed, and
-context faces use approximately the same saturation for both the
-highlighted and unhighlighted variants. Also make sure the file and
-diff headings work nicely with context lines (e.g. make them look
-different). Line faces should set both the foreground and the
-background color. For example, for added lines use two different
-greens.
-
- It’s best if the foreground color of both the highlighted and the
-unhighlighted variants are the same, so you will need to have to find a
-color that works well on the highlight and unhighlighted background, the
-refine background, and the highlight context background. When there is
-an hunk internal region, then the added- and removed-lines background
-color is used only within that region. Outside the region the
-highlighted context background color is used. This makes it easier to
-see what is being staged. With an hunk internal region the hunk heading
-is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin
-lines that are added around the lines that fall within the region. The
-background color of that has to be distinct enough from the various
-other involved background colors.
-
- Nobody said this would be easy. If your theme restricts itself to a
-certain set of colors, then you should make an exception here.
-Otherwise it would be impossible to make the diffs look good in each and
-every variation. Actually you might want to just stick to the default
-definitions for these faces. You have been warned. Also please note
-that if you do not get this right, this will in some cases look to users
-like bugs in Magit - so please do it right or not at all.
-
-\1f
-File: magit.info, Node: FAQ, Next: Keystroke Index, Prev: Plumbing, Up: Top
-
-Appendix A FAQ
-**************
-
-Below you find a list of frequently asked questions. For a list of
-frequently *and recently* asked questions, i.e. questions that haven’t
-made it into the manual yet, see
-<https://github.com/magit/magit/wiki/FAQ>.
-
-* Menu:
-
-* Magit is slow::
-* I changed several thousand files at once and now Magit is unusable::
-* I am having problems committing::
-* Diffs are collapsed after un-/staging::
-* I don't understand how branching and pushing work::
-* I don’t like the key binding in v2.4: I don't like the key binding in v24.
-* I cannot install the pre-requisites for Magit v2::
-* I am using an Emacs release older than v24.4: I am using an Emacs release older than v244.
-* I am using a Git release older than v1.9.4: I am using a Git release older than v194.
-* I am using MS Windows and cannot push with Magit::
-* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
-* How to install the gitman info manual?::
-* How can I show Git's output?::
-* Diffs contain control sequences::
-* Expanding a file to show the diff causes it to disappear::
-* Point is wrong in the ‘COMMIT_EDITMSG’ buffer::
-* The mode-line information isn't always up-to-date::
-* Can Magit be used as ‘ediff-version-control-package’?::
-* How to show diffs for gpg-encrypted files?::
-* Emacs 24.5 hangs when loading Magit: Emacs 245 hangs when loading Magit.
-* Symbol's value as function is void ‘--some’::
-* Where is the branch manager::
-
-\1f
-File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ
-
-A.1 Magit is slow
-=================
-
-See *note Performance: Performance.
-
-\1f
-File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ
-
-A.2 I changed several thousand files at once and now Magit is unusable
-======================================================================
-
-Magit is *currently* not expected to work under such conditions. It
-sure would be nice if it did, and v2.5 will hopefully be a big step into
-that direction. But it might take until v3.1 to accomplish fully
-satisfactory performance, because that requires some heavy refactoring.
-
- But for now we recommend you use the command line to complete this
-one commit. Also see *note Performance: Performance.
-
-\1f
-File: magit.info, Node: I am having problems committing, Next: Diffs are collapsed after un-/staging, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ
-
-A.3 I am having problems committing
-===================================
-
-That likely means that Magit is having problems finding an appropriate
-emacsclient executable. See *note (with-editor)Configuring
-With-Editor:: and *note (with-editor)Debugging::.
-
-\1f
-File: magit.info, Node: Diffs are collapsed after un-/staging, Next: I don't understand how branching and pushing work, Prev: I am having problems committing, Up: FAQ
-
-A.4 Diffs are collapsed after un-/staging
-=========================================
-
-This typically happens on Windows and/or large repositories where
-preparing diffs takes longer than ‘magit-diff-expansion-threshold’. The
-default is one second, try increasing it to a larger value.
-
- Currently when one part of a Magit buffer has to be updated the whole
-buffer is recreated from scratch. That obviously isn’t good for
-performance and will be fixed eventually. Meanwhile we need a kludge
-that prevents the update from taking very long under certain
-circumstances, e.g. when showing the difference for hundrets of changes
-files.
-
- For that reason the variable ‘magit-diff-expansion-threshold’ was
-added, defaulting to one second. If it takes longer than that to
-recreate a Magit buffer, then no further diff sections are expanded
-because that’s one of the steps that take the longest. If a diff is not
-expanded, then some work can be delayed until it actually is.
-
- You can then still expand sections manually, but when you refresh the
-complete buffer explicitly using ‘g’ or by performing an action which
-triggers a refresh, then previously expanded diffs could be collapsed.
-You can set ‘magit-diff-expansion-threshold’ to a higher value to
-prevent that from happening.
-
-\1f
-File: magit.info, Node: I don't understand how branching and pushing work, Next: I don't like the key binding in v24, Prev: Diffs are collapsed after un-/staging, Up: FAQ
-
-A.5 I don’t understand how branching and pushing work
-=====================================================
-
-Please see *note Branching: Branching. and
-<http://emacsair.me/2016/01/18/magit-2.4>
-
-\1f
-File: magit.info, Node: I don't like the key binding in v24, Next: I cannot install the pre-requisites for Magit v2, Prev: I don't understand how branching and pushing work, Up: FAQ
-
-A.6 I don’t like the key binding in v2.4
-========================================
-
-Please see <http://emacsair.me/2016/01/1/restore-old-bindings>.
-
-\1f
-File: magit.info, Node: I cannot install the pre-requisites for Magit v2, Next: I am using an Emacs release older than v244, Prev: I don't like the key binding in v24, Up: FAQ
-
-A.7 I cannot install the pre-requisites for Magit v2
-====================================================
-
-An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies is
-available from <http://magit.vc/elpa/v1>. But note that v1.4.2 is
-obsolete and no longer maintained.
-
-\1f
-File: magit.info, Node: I am using an Emacs release older than v244, Next: I am using a Git release older than v194, Prev: I cannot install the pre-requisites for Magit v2, Up: FAQ
-
-A.8 I am using an Emacs release older than v24.4
-================================================
-
-At least Emacs v24.4 is required. There is no way around it, if you
-want to use Magit v2.
-
- If you own the machine you work on, then consider updating to the
-latest release provided by your distribution. If it doesn’t feature a
-recent enough release, then you will have to use a backport package or
-build Emacs from source.
-
- Installing Emacs from source is quite simple. See the instructions
-at <http://git.savannah.gnu.org/cgit/emacs.git/tree/INSTALL> and
-<http://git.savannah.gnu.org/cgit/emacs.git/tree/INSTALL.REPO> to get an
-idea of that this involves. But when you perform the installation then
-use the instructions for the release you are actually installing.
-
- Unfortunately these instructions do not cover the hardest part (which
-is the hardest part exactly because it is not covered there): installing
-the build time dependencies.
-
- For that you’ll need to perform a web search and find an appropriate
-tutorial for your distribution. If you think you should not have had to
-do that yourself, then consider informing me about the resources that
-helped you figure what to do for your specific setup, so that I can post
-a link here. That way those coming after you have it easier.
-
- An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies
-is available from <http://magit.vc/elpa/v1>.
-
-\1f
-File: magit.info, Node: I am using a Git release older than v194, Next: I am using MS Windows and cannot push with Magit, Prev: I am using an Emacs release older than v244, Up: FAQ
-
-A.9 I am using a Git release older than v1.9.4
-==============================================
-
-At least Git v1.9.4 is required. There is no way around it, if you want
-to use Magit v2.
-
- If you own the machine, then consider updating to the latest release
-provided by your distribution. If it doesn’t feature a recent enough
-release, then you will have to use a backport package or build Git from
-source.
-
- Installing Git from source is quite simple. See the instructions at
-<https://github.com/git/git/blob/master/INSTALL> to get an idea of that
-this involves. But when you perform the installation then use the
-instructions for the release you are actually installing.
-
- An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies
-is available from <http://magit.vc/elpa/v1>.
-
-\1f
-File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using OS X and SOMETHING works in shell but not in Magit, Prev: I am using a Git release older than v194, Up: FAQ
-
-A.10 I am using MS Windows and cannot push with Magit
-=====================================================
-
-It’s almost certain that Magit is only incidental to this issue. It is
-much more likely that this is a configuration issue, even if you can
-push on the command line.
-
- Detailed setup instructions can be found at
-<https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows>.
-
-\1f
-File: magit.info, Node: I am using OS X and SOMETHING works in shell but not in Magit, Next: How to install the gitman info manual?, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ
-
-A.11 I am using OS X and SOMETHING works in shell, but not in Magit
-===================================================================
-
-This usually occurs because Emacs doesn’t have the same environment
-variables as your shell. Try installing and configuring
-<https://github.com/purcell/exec-path-from-shell>. By default it
-synchronizes ‘$PATH’, which helps Magit find the same ‘git’ as the one
-you are using on the shell.
-
- If SOMETHING is "passphrase caching with gpg-agent for commit and/or
-tag signing", then you’ll also need to synchronize ‘$GPG_AGENT_INFO’.
-
-\1f
-File: magit.info, Node: How to install the gitman info manual?, Next: How can I show Git's output?, Prev: I am using OS X and SOMETHING works in shell but not in Magit, Up: FAQ
-
-A.12 How to install the gitman info manual?
-===========================================
-
-Git’s manpages can be exported as an info manual called ‘gitman’.
-Magit’s own info manual links to nodes in that manual instead of the
-actual manpages because texinfo sadly doesn’t support linking to
-manpages.
-
- Unfortunately many distributions do not install the ‘gitman’ manual
-by default. Some distributions may provide a separate package
-containing the info manual. Please let me know the name of that package
-for your distribution, so that I can mention here.
-
- If the distribution you are using does not offer a package that
-contains the ‘gitman’ manual, then you have to install it manually.
-Clone Git’s own Git repository, checkout the tag corresponding to the
-Git release you have installed, and follow the instructions in
-‘INSTALL’. The relevant make targets are ‘info’ and ‘install-info’.
-
- Alternatively you may add this advice to your ‘init.el’ file.
-
- (defadvice Info-follow-nearest-node (around gitman activate)
- "When encountering a cross reference to the `gitman' info
- manual, then instead of following that cross reference show
- the actual manpage using the function `man'."
- (let ((node (Info-get-token
- (point) "\\*note[ \n\t]+"
- "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
- (if (and node (string-match "^(gitman)\\(.+\\)" node))
- (progn (require 'man)
- (man (match-string 1 node)))
- ad-do-it)))
-
- Or if you are using MS Windows and ‘man’ is not available, use this
-variation with used the Emacs Lisp implementation provided by the
-‘woman’ package.
-
- (defadvice Info-follow-nearest-node (around gitman activate)
- "When encountering a cross reference to the `gitman' info
- manual, then instead of following that cross reference show
- the actual manpage using the function `woman'."
- (let ((node (Info-get-token
- (point) "\\*note[ \n\t]+"
- "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
- (if (and node (string-match "^(gitman)\\(.+\\)" node))
- (progn (require 'woman)
- (woman (match-string 1 node)))
- ad-do-it)))
-
- Did I mention that texinfo cross reference are just awful? (This is
-just one of many issues.)
-
-\1f
-File: magit.info, Node: How can I show Git's output?, Next: Diffs contain control sequences, Prev: How to install the gitman info manual?, Up: FAQ
-
-A.13 How can I show Git’s output?
-=================================
-
-To show the output of recently run git commands, press ‘$’ (or, if that
-isn’t available, ‘M-x magit-process-buffer’). This will show a buffer
-containing a section per git invocation; as always press ‘TAB’ to expand
-or collapse them.
-
- By default git’s output is only inserted into the process buffer if
-it is run for side-effects. When the output is consumed in some way
-then also inserting it into the process buffer would be to expensive.
-For debugging purposes it’s possible to do so anyway by setting
-‘magit-git-debug’ to ‘t’.
-
-\1f
-File: magit.info, Node: Diffs contain control sequences, Next: Expanding a file to show the diff causes it to disappear, Prev: How can I show Git's output?, Up: FAQ
-
-A.14 Diffs contain control sequences
-====================================
-
-This happens when you configure Git to always color diffs and/or all of
-its output. The valid values for relevant Git variables ‘color.ui’ and
-‘color.diff’ are ‘false’, ‘true’ and ‘always’, and the default is
-‘true’. You should leave it that because then you get colorful output
-in terminals but git’s output is consumed by something else, then no
-colors are used.
-
- If you actually use some other tool which expects that requires that
-you force git to output control sequences (which is highly unlikely),
-then you can override these settings just for Magit by using:
-
- (setq magit-git-global-arguments
- (nconc magit-git-global-arguments
- '("-c" "color.ui=false"
- "-c" "color.diff=false")))
-
-\1f
-File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the ‘COMMIT_EDITMSG’ buffer, Prev: Diffs contain control sequences, Up: FAQ
-
-A.15 Expanding a file to show the diff causes it to disappear
-=============================================================
-
-This is probably caused by a change of a ‘diff.*’ Git variable. You
-probably set that variable for a reason, and should therefore only undo
-that setting in Magit by customizing ‘magit-git-global-arguments’.
-
-\1f
-File: magit.info, Node: Point is wrong in the ‘COMMIT_EDITMSG’ buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ
-
-A.16 Point is wrong in the ‘COMMIT_EDITMSG’ buffer
-==================================================
-
-Neither Magit nor ‘git-commit‘ fiddle with point in the buffer used to
-write commit messages, so something else must be doing it.
-
- You have probably globally enabled a mode which does restore point in
-file-visiting buffers. It might be a bit surprising, but when you write
-a commit message, then you are actually editing a file.
-
- So you have to figure out which package is doing. ‘saveplace’,
-‘pointback’, and ‘session’ are likely candidates. These snippets might
-help:
-
- (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)")
-
- (with-eval-after-load 'pointback
- (lambda ()
- (when (or git-commit-mode git-rebase-mode)
- (pointback-mode -1))))
-
-\1f
-File: magit.info, Node: The mode-line information isn't always up-to-date, Next: Can Magit be used as ‘ediff-version-control-package’?, Prev: Point is wrong in the ‘COMMIT_EDITMSG’ buffer, Up: FAQ
-
-A.17 The mode-line information isn’t always up-to-date
-======================================================
-
-Magit is not responsible for the version control information that is
-being displayed in the mode-line and looks something like ‘Git-master’.
-The built-in "Version Control" package, also known as "VC", updates that
-information, and can be told to do so more often:
-
- (setq auto-revert-check-vc-info t)
-
- But doing so isn’t good for performance. For more (overly
-optimistic) information see *note (emacs)VC Mode Line::.
-
- If you don’t really care about seeing that information in the
-mode-line, but just don’t want to see _incorrect_ information, then
-consider disabling VC when using Git:
-
- (setq vc-handled-backends (delq 'Git vc-handled-backends))
-
- Or to disable it completely:
-
- (setq vc-handled-backends nil)
-
-\1f
-File: magit.info, Node: Can Magit be used as ‘ediff-version-control-package’?, Next: How to show diffs for gpg-encrypted files?, Prev: The mode-line information isn't always up-to-date, Up: FAQ
-
-A.18 Can Magit be used as ‘ediff-version-control-package’?
-==========================================================
-
-No, it cannot. For that to work the functions ‘ediff-magit-internal’
-and ‘ediff-magit-merge-internal’ would have to be implemented, and they
-are not. These two functions are only used by the three commands
-‘ediff-revision’, ‘ediff-merge-revisions-with-ancestor’, and
-‘ediff-merge-revisions’.
-
- These commands only delegate the task of populating buffers with
-certain revisions to the "internal" functions. The equally important
-task of determining which revisions are to be compared/merged is not
-delegated. Instead this is done without any support whatsoever, from
-the version control package/system - meaning that the user has to enter
-the revisions explicitly. Instead of implementing
-‘ediff-magit-internal’ we provide ‘magit-ediff-compare’, which handles
-both tasks like it is 2005.
-
- The other commands ‘ediff-merge-revisions’ and
-‘ediff-merge-revisions-with-ancestor’ are normally not what you want
-when using a modern version control system like Git. Instead of letting
-the user resolve only those conflicts which Git could not resolve on its
-own, they throw away all work done by Git and then expect the user to
-manually merge all conflicts, including those that had already been
-resolved. That made sense back in the days when version control systems
-couldn’t merge (or so I have been told), but not anymore. Once in a
-blue moon you might actually want to see all conflicts, in which case
-you *can* use these commands, which then use ‘ediff-vc-merge-internal’.
-So we don’t actually have to implement ‘ediff-magit-merge-internal’.
-Instead we provide the more useful command ‘magit-ediff-resolve’ which
-only shows yet-to-be resolved conflicts.
-
-\1f
-File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: Emacs 245 hangs when loading Magit, Prev: Can Magit be used as ‘ediff-version-control-package’?, Up: FAQ
-
-A.19 How to show diffs for gpg-encrypted files?
-===============================================
-
-Git supports showing diffs for encrypted files, but has to be told to do
-so. Since Magit just uses Git to get the diffs, configuring Git also
-affects the diffs displayed inside Magit.
-
- git config --global diff.gpg.textconv "gpg --no-tty --decrypt"
- echo "*.gpg filter=gpg diff=gpg" > .gitattributes
-
-\1f
-File: magit.info, Node: Emacs 245 hangs when loading Magit, Next: Symbol's value as function is void ‘--some’, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ
-
-A.20 Emacs 24.5 hangs when loading Magit
-========================================
-
-This is actually triggered by loading Tramp. See
-<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=20015> for details. You
-can work around the problem by setting
-‘tramp-ssh-controlmaster-options’. Changing your DNS server (e.g. to
-Google’s ‘8.8.8.8’) may also be sufficient to work around the issue.
-
-\1f
-File: magit.info, Node: Symbol's value as function is void ‘--some’, Next: Where is the branch manager, Prev: Emacs 245 hangs when loading Magit, Up: FAQ
-
-A.21 Symbol’s value as function is void ‘--some’
-================================================
-
-Update ‘dash’, restart Emacs, and then it will be defined.
-
-\1f
-File: magit.info, Node: Where is the branch manager, Prev: Symbol's value as function is void ‘--some’, Up: FAQ
-
-A.22 Where is the branch manager
-================================
-
-‘y’ is bound to the command that shows the "refs buffer", the successor
-of the "branch manager".
-
-\1f
-File: magit.info, Node: Keystroke Index, Next: Command Index, Prev: FAQ, Up: Top
-
-Appendix B Keystroke Index
-**************************
-
-\0\b[index\0\b]
-* Menu:
-
-* !: Running Git manually.
- (line 12)
-* ! !: Running Git manually.
- (line 19)
-* ! a: Running Git manually.
- (line 51)
-* ! b: Running Git manually.
- (line 55)
-* ! g: Running Git manually.
- (line 59)
-* ! k: Running Git manually.
- (line 47)
-* ! p: Running Git manually.
- (line 24)
-* ! s: Running Git manually.
- (line 33)
-* ! S: Running Git manually.
- (line 38)
-* $: Viewing Git output. (line 11)
-* +: Log Buffer. (line 53)
-* + <1>: Refreshing diffs. (line 58)
-* -: Refreshing diffs. (line 54)
-* 0: Refreshing diffs. (line 62)
-* 1: Section visibility. (line 26)
-* 2: Section visibility. (line 26)
-* 3: Section visibility. (line 26)
-* 4: Section visibility. (line 26)
-* =: Log Buffer. (line 47)
-* = <1>: Log Buffer. (line 57)
-* ^: Section movement. (line 31)
-* a: Applying. (line 33)
-* A: Cherry picking. (line 8)
-* A A: Cherry picking. (line 16)
-* A a: Cherry picking. (line 22)
-* A A <1>: Cherry picking. (line 35)
-* A a <1>: Cherry picking. (line 43)
-* A s: Cherry picking. (line 39)
-* B: Bisecting. (line 8)
-* b: The branch popup. (line 12)
-* B b: Bisecting. (line 31)
-* b b: The branch popup. (line 29)
-* b c: The branch popup. (line 47)
-* B g: Bisecting. (line 36)
-* B k: Bisecting. (line 41)
-* b k: The branch popup. (line 88)
-* b n: The branch popup. (line 37)
-* B r: Bisecting. (line 47)
-* b r: The branch popup. (line 94)
-* B s: Bisecting. (line 16)
-* b s: The branch popup. (line 54)
-* B u: Bisecting. (line 24)
-* b x: The branch popup. (line 71)
-* c: Initiating a commit. (line 8)
-* c <1>: Editing rebase sequences.
- (line 72)
-* c a: Initiating a commit. (line 18)
-* c A: Initiating a commit. (line 66)
-* c c: Initiating a commit. (line 13)
-* c e: Initiating a commit. (line 22)
-* c f: Initiating a commit. (line 42)
-* c F: Initiating a commit. (line 50)
-* c s: Initiating a commit. (line 54)
-* c S: Initiating a commit. (line 62)
-* c w: Initiating a commit. (line 32)
-* C-<return>: Diff buffer. (line 21)
-* C-<tab>: Section visibility. (line 13)
-* C-c C-a: Editing commit messages.
- (line 128)
-* C-c C-b: Log Buffer. (line 19)
-* C-c C-b <1>: Refreshing diffs. (line 80)
-* C-c C-c: Popup buffers and prefix commands.
- (line 20)
-* C-c C-c <1>: Select from log. (line 14)
-* C-c C-c <2>: Editing commit messages.
- (line 19)
-* C-c C-c <3>: Editing rebase sequences.
- (line 6)
-* C-c C-d: Refreshing diffs. (line 70)
-* C-c C-d <1>: Editing commit messages.
- (line 57)
-* C-c C-f: Log Buffer. (line 23)
-* C-c C-f <1>: Refreshing diffs. (line 84)
-* C-c C-i: Editing commit messages.
- (line 153)
-* C-c C-k: Select from log. (line 20)
-* C-c C-k <1>: Editing commit messages.
- (line 24)
-* C-c C-k <2>: Editing rebase sequences.
- (line 11)
-* C-c C-o: Editing commit messages.
- (line 144)
-* C-c C-p: Editing commit messages.
- (line 148)
-* C-c C-r: Editing commit messages.
- (line 132)
-* C-c C-s: Editing commit messages.
- (line 136)
-* C-c C-t: Editing commit messages.
- (line 140)
-* C-c C-w: Editing commit messages.
- (line 63)
-* C-c M-g: Minor mode for buffers visiting files.
- (line 19)
-* C-c M-g b: Minor mode for buffers visiting files.
- (line 76)
-* C-c M-g c: Minor mode for buffers visiting files.
- (line 33)
-* C-c M-g D: Minor mode for buffers visiting files.
- (line 39)
-* C-c M-g d: Minor mode for buffers visiting files.
- (line 47)
-* C-c M-g L: Minor mode for buffers visiting files.
- (line 58)
-* C-c M-g l: Minor mode for buffers visiting files.
- (line 65)
-* C-c M-g p: Minor mode for buffers visiting files.
- (line 82)
-* C-c M-g s: Minor mode for buffers visiting files.
- (line 24)
-* C-c M-g u: Minor mode for buffers visiting files.
- (line 28)
-* C-s M-s: Editing commit messages.
- (line 35)
-* C-w: Common commands. (line 21)
-* C-x g: Status buffer. (line 22)
-* C-x u: Editing rebase sequences.
- (line 89)
-* d: Diffing. (line 20)
-* D: Refreshing diffs. (line 11)
-* d c: Diffing. (line 67)
-* d d: Diffing. (line 25)
-* D f: Refreshing diffs. (line 45)
-* D g: Refreshing diffs. (line 16)
-* d p: Diffing. (line 59)
-* d r: Diffing. (line 29)
-* D r: Refreshing diffs. (line 40)
-* d s: Diffing. (line 49)
-* D s: Refreshing diffs. (line 21)
-* d t: Diffing. (line 72)
-* D t: Refreshing diffs. (line 36)
-* d u: Diffing. (line 55)
-* d w: Diffing. (line 43)
-* D w: Refreshing diffs. (line 28)
-* DEL: Log Buffer. (line 37)
-* DEL <1>: Diff buffer. (line 48)
-* DEL <2>: Blaming. (line 44)
-* DEL <3>: Editing rebase sequences.
- (line 28)
-* e: Ediffing. (line 9)
-* E: Ediffing. (line 21)
-* e <1>: Editing rebase sequences.
- (line 55)
-* E c: Ediffing. (line 65)
-* E i: Ediffing. (line 57)
-* E m: Ediffing. (line 35)
-* E r: Ediffing. (line 26)
-* E s: Ediffing. (line 48)
-* E u: Ediffing. (line 53)
-* E w: Ediffing. (line 61)
-* E z: Ediffing. (line 69)
-* f: Editing rebase sequences.
- (line 63)
-* f <1>: Fetching. (line 11)
-* F: Pulling. (line 11)
-* f a: Fetching. (line 38)
-* f e: Fetching. (line 24)
-* F e: Pulling. (line 24)
-* f m: Fetching. (line 42)
-* f o: Fetching. (line 28)
-* f p: Fetching. (line 16)
-* F p: Pulling. (line 16)
-* f r: Fetching. (line 33)
-* f u: Fetching. (line 20)
-* F u: Pulling. (line 20)
-* g: Automatic Refreshing of Magit Buffers.
- (line 22)
-* G: Automatic Refreshing of Magit Buffers.
- (line 31)
-* j: Diff buffer. (line 38)
-* k: Viewing Git output. (line 19)
-* k <1>: Applying. (line 40)
-* k <2>: Editing rebase sequences.
- (line 68)
-* k <3>: Stashing. (line 92)
-* l: Logging. (line 26)
-* L: Refreshing logs. (line 11)
-* L <1>: Log Buffer. (line 6)
-* l a: Logging. (line 56)
-* l b: Logging. (line 52)
-* L g: Refreshing logs. (line 16)
-* l h: Logging. (line 44)
-* l H: Reflog. (line 19)
-* l l: Logging. (line 31)
-* l L: Logging. (line 48)
-* l o: Logging. (line 37)
-* l O: Reflog. (line 15)
-* l r: Reflog. (line 11)
-* L s: Refreshing logs. (line 21)
-* L t: Refreshing logs. (line 36)
-* L w: Refreshing logs. (line 28)
-* m: Merging. (line 9)
-* M: Remotes. (line 8)
-* m a: Merging. (line 57)
-* M a: Remotes. (line 13)
-* m e: Merging. (line 30)
-* M k: Remotes. (line 28)
-* m m: Merging. (line 17)
-* m m <1>: Merging. (line 52)
-* m n: Merging. (line 37)
-* m p: Merging. (line 44)
-* M r: Remotes. (line 18)
-* M u: Remotes. (line 23)
-* M-1: Section visibility. (line 34)
-* M-2: Section visibility. (line 34)
-* M-3: Section visibility. (line 34)
-* M-4: Section visibility. (line 34)
-* M-<tab>: Section visibility. (line 17)
-* M-n: Section movement. (line 26)
-* M-n <1>: Editing commit messages.
- (line 45)
-* M-n <2>: Editing rebase sequences.
- (line 47)
-* M-p: Section movement. (line 20)
-* M-p <1>: Editing commit messages.
- (line 39)
-* M-p <2>: Editing rebase sequences.
- (line 43)
-* M-w: Blaming. (line 75)
-* M-w <1>: Common commands. (line 10)
-* M-x magit-blame: Blaming. (line 8)
-* M-x magit-blame-popup: Blaming. (line 24)
-* M-x magit-checkout-file: Resetting. (line 37)
-* M-x magit-clone: Repository setup. (line 16)
-* M-x magit-describe-section: Section types and values.
- (line 13)
-* M-x magit-describe-section <1>: Matching sections. (line 6)
-* M-x magit-find-file: Visiting blobs. (line 6)
-* M-x magit-find-file-other-window: Visiting blobs. (line 11)
-* M-x magit-init: Repository setup. (line 6)
-* M-x magit-log-buffer-file: Logging. (line 67)
-* M-x magit-reset-hard: Resetting. (line 32)
-* M-x magit-reset-head: Resetting. (line 21)
-* M-x magit-reset-index: Staging and unstaging.
- (line 88)
-* M-x magit-reset-index <1>: Resetting. (line 14)
-* M-x magit-reset-soft: Resetting. (line 26)
-* M-x magit-reverse-in-index: Staging and unstaging.
- (line 63)
-* M-x magit-stage-file: Staging from file-visiting buffers.
- (line 10)
-* M-x magit-toggle-buffer-lock: Modes and Buffers. (line 17)
-* M-x magit-unstage-file: Staging from file-visiting buffers.
- (line 18)
-* M-x magit-version: Git executable. (line 17)
-* M-x magit-wip-commit: Wip modes. (line 129)
-* n: Section movement. (line 16)
-* n <1>: Blaming. (line 54)
-* N: Blaming. (line 58)
-* n <2>: Editing rebase sequences.
- (line 39)
-* n <3>: Minor mode for buffers visiting blobs.
- (line 16)
-* o: Submodules. (line 8)
-* O: Subtree. (line 8)
-* o a: Submodules. (line 13)
-* O a: Subtree. (line 20)
-* o b: Submodules. (line 19)
-* O c: Subtree. (line 24)
-* o f: Submodules. (line 37)
-* O f: Subtree. (line 32)
-* o i: Submodules. (line 24)
-* o i <1>: Submodules. (line 41)
-* O m: Subtree. (line 28)
-* O p: Subtree. (line 36)
-* o s: Submodules. (line 33)
-* O s: Subtree. (line 41)
-* o u: Submodules. (line 28)
-* p: Section movement. (line 10)
-* p <1>: Blaming. (line 62)
-* P: Blaming. (line 66)
-* p <2>: Editing rebase sequences.
- (line 35)
-* P <1>: Pushing. (line 11)
-* p <3>: Minor mode for buffers visiting blobs.
- (line 12)
-* P e: Pushing. (line 35)
-* P m: Pushing. (line 53)
-* P o: Pushing. (line 39)
-* P p: Pushing. (line 16)
-* P r: Pushing. (line 44)
-* P t: Pushing. (line 59)
-* P T: Pushing. (line 65)
-* P u: Pushing. (line 26)
-* q: Quitting Windows. (line 6)
-* q <1>: Log Buffer. (line 12)
-* q <2>: Blaming. (line 70)
-* q <3>: Minor mode for buffers visiting blobs.
- (line 20)
-* r: Rebasing. (line 9)
-* r <1>: Editing rebase sequences.
- (line 51)
-* r a: Rebasing. (line 96)
-* r e: Rebasing. (line 34)
-* r e <1>: Rebasing. (line 92)
-* r f: Rebasing. (line 66)
-* r i: Rebasing. (line 62)
-* r m: Rebasing. (line 70)
-* r o: Rebasing. (line 40)
-* r p: Rebasing. (line 25)
-* r r: Rebasing. (line 81)
-* r s: Rebasing. (line 88)
-* r u: Rebasing. (line 30)
-* r w: Rebasing. (line 74)
-* RET: Diff buffer. (line 6)
-* RET <1>: References buffer. (line 99)
-* RET <2>: Blaming. (line 29)
-* RET <3>: Editing rebase sequences.
- (line 16)
-* s: Staging and unstaging.
- (line 29)
-* S: Staging and unstaging.
- (line 37)
-* s <1>: Editing rebase sequences.
- (line 59)
-* s-<tab>: Section visibility. (line 22)
-* SPC: Log Buffer. (line 27)
-* SPC <1>: Diff buffer. (line 44)
-* SPC <2>: Blaming. (line 34)
-* SPC <3>: Editing rebase sequences.
- (line 21)
-* t: Blaming. (line 79)
-* t <1>: Tagging. (line 8)
-* T: Notes. (line 8)
-* T a: Notes. (line 70)
-* T c: Notes. (line 65)
-* t k: Tagging. (line 18)
-* T m: Notes. (line 56)
-* t p: Tagging. (line 24)
-* T p: Notes. (line 29)
-* T r: Notes. (line 21)
-* T s: Notes. (line 33)
-* T S: Notes. (line 44)
-* t t: Tagging. (line 13)
-* T T: Notes. (line 13)
-* TAB: Section visibility. (line 9)
-* u: Staging and unstaging.
- (line 44)
-* U: Staging and unstaging.
- (line 53)
-* v: Applying. (line 44)
-* V: Reverting. (line 6)
-* V A: Reverting. (line 30)
-* V a: Reverting. (line 38)
-* V s: Reverting. (line 34)
-* V V: Reverting. (line 14)
-* V v: Reverting. (line 20)
-* W: Creating and sending patches.
- (line 6)
-* w: Applying patches. (line 8)
-* w a: Applying patches. (line 31)
-* w m: Applying patches. (line 19)
-* W p: Creating and sending patches.
- (line 11)
-* W r: Creating and sending patches.
- (line 17)
-* w s: Applying patches. (line 27)
-* w w: Applying patches. (line 13)
-* w w <1>: Applying patches. (line 23)
-* x: Editing rebase sequences.
- (line 76)
-* x <1>: Resetting. (line 8)
-* Y: Logging. (line 62)
-* y: References buffer. (line 6)
-* y <1>: Editing rebase sequences.
- (line 85)
-* y c: References buffer. (line 19)
-* y o: References buffer. (line 24)
-* y y: References buffer. (line 14)
-* z: Stashing. (line 8)
-* z a: Stashing. (line 58)
-* z b: Stashing. (line 84)
-* z d: Stashing. (line 71)
-* z f: Stashing. (line 88)
-* z i: Stashing. (line 20)
-* z I: Stashing. (line 46)
-* z l: Stashing. (line 76)
-* z p: Stashing. (line 64)
-* z v: Stashing. (line 80)
-* z w: Stashing. (line 25)
-* z W: Stashing. (line 51)
-* z x: Stashing. (line 32)
-* z z: Stashing. (line 13)
-* z Z: Stashing. (line 39)
-
--- /dev/null
+Authors
+=======
+
+The following people have contributed to Magit, including the
+libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el`
+which are distributed as separate Elpa packages.
+
+For statistics see https://magit.vc/stats/authors.html.
+
+Names below are sorted alphabetically.
+
+Author
+------
+
+- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
+
+Maintainer
+----------
+
+- Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+Developers
+----------
+
+- Kyle Meyer <kyleNOSPAMkyleam.com>
+- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
+
+Retired Maintainers and Developers
+----------------------------------
+
+- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
+- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
+- Pieter Praet <pieterNOSPAMpraet.org>
+- Phil Jackson <philNOSPAMshellarchive.co.uk>
+- Rémi Vanicat <vanicatNOSPAMdebian.org>
+- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+
+Contributors
+------------
+
+- Aaron Culich <aculichNOSPAMgmail.com>
+- Abdo Roig-Maranges <abdo.roigNOSPAMgmail.com>
+- Adam Porter <adamNOSPAMalphapapa.net>
+- Adam Spiers <emacsNOSPAMadamspiers.org>
+- Adeodato Simó <datoNOSPAMnet.com.org.es>
+- Ævar Arnfjörð Bjarmason <avarabNOSPAMgmail.com>
+- Alan Falloon <alan.falloonNOSPAMgmail.com>
+- Alexander Gramiak <fice-tNOSPAMprotonmail.com>
+- Alex Dunn <adunnNOSPAMucsb.edu>
+- Alexey Voinov <alexey.v.voinovNOSPAMgmail.com>
+- Alex Kost <alezostNOSPAMgmail.com>
+- Alex Ott <alexottNOSPAMgmail.com>
+- Andreas Fuchs <asfNOSPAMboinkor.net>
+- Andreas Liljeqvist <andreas.liljeqvistNOSPAMrobacks.se>
+- Andreas Rottmann <a.rottmannNOSPAMgmx.at>
+- Andrei Chițu <andrei.chitu1NOSPAMgmail.com>
+- Andrew Kirkpatrick <andrew.kirkpatrickNOSPAMadelaide.edu.au>
+- Andrew Schwartzmeyer <andrewNOSPAMschwartzmeyer.com>
+- Andrey Smirnov <andrew.smirnovNOSPAMgmail.com>
+- Andriy Kmit' <devNOSPAMmadand.net>
+- Andy Sawyer <gitNOSPAMpureabstract.org>
+- Barak A. Pearlmutter <barak+gitNOSPAMpearlmutter.net>
+- Bart Bakker <bartNOSPAMthesoftwarecraft.com>
+- Basil L. Contovounesios <contovobNOSPAMtcd.ie>
+- Bastian Beischer <beischerNOSPAMphysik.rwth-aachen.de>
+- Ben Walton <bwaltonNOSPAMartsci.utoronto.ca>
+- Bradley Wright <bradNOSPAMintranation.com>
+- Brandon W Maister <quodlibetorNOSPAMgmail.com>
+- Brian Warner <warnerNOSPAMlothar.com>
+- Bryan Shell <bryan.shellNOSPAMorbitz.com>
+- Carl Lieberman <liebermancarlNOSPAMgmail.com>
+- Chillar Anand <anand21nandaNOSPAMgmail.com>
+- Chris Bernard <cebernardNOSPAMgmail.com>
+- Chris Done <chrisdoneNOSPAMgmail.com>
+- Chris Moore <dooglusNOSPAMgmail.com>
+- Chris Ring <chrisNOSPAMringthis.com>
+- Chris Shoemaker <chrisNOSPAMmojotech.com>
+- Christian Dietrich <christian.dietrichNOSPAMinformatik.uni-erlangen.de>
+- Christian Kluge <ckfrakturfreakNOSPAMweb.de>
+- Christopher Monsanto <chrisNOSPAMmonsan.to>
+- Cornelius Mika <cornelius.mikaNOSPAMgmail.com>
+- Craig Andera <canderaNOSPAMwangdera.com>
+- Dale Hagglund <dale.hagglundNOSPAMgmail.com>
+- Damien Cassou <damienNOSPAMcassou.me>
+- Dan Erikson <derikson3NOSPAMgmail.com>
+- Daniel Brockman <danielNOSPAMgointeractive.se>
+- Daniel Farina <drfarinaNOSPAMacm.org>
+- Daniel Hackney <danNOSPAMhaxney.org>
+- Dan LaManna <dan.lamannaNOSPAMgmail.com>
+- Dato Simó <datoNOSPAMnet.com.org.es>
+- David Abrahams <daveNOSPAMboostpro.com>
+- David Hull <david.hullNOSPAMopenx.com>
+- David L. Rager <ragerdlNOSPAMgmail.com>
+- David Wallin <david.wallinNOSPAMgmail.com>
+- Dennis Paskorz <dennisNOSPAMwalltowall.com>
+- Divye Kapoor <divyeNOSPAMgoogle.com>
+- Dominique Quatravaux <domqNOSPAMgoogle.com>
+- Eli Barzilay <eliNOSPAMbarzilay.org>
+- Eric Davis <edNOSPAMnpri.org>
+- Eric Schulte <schulte.ericNOSPAMgmail.com>
+- Evgkeni Sampelnikof <esabofNOSPAMgmail.com>
+- Felix Geller <fgellerNOSPAMgmail.com>
+- Feng Li <fengliNOSPAMblackmagicdesign.com>
+- Florian Ragwitz <raflNOSPAMdebian.org>
+- Fritz Grabo <fritz.graboNOSPAMgmail.com>
+- Geoff Shannon <geoffpshannonNOSPAMgmail.com>
+- George Kadianakis <desnackedNOSPAMgmail.com>
+- Graham Clark <grclarkNOSPAMgmail.com>
+- Graham Dobbins <gdobbinsNOSPAMprotonmail.com>
+- Greg A. Woods <woodsNOSPAMplanix.com>
+- Greg Lucas <gregNOSPAMglucas.net>
+- Greg Sexton <gregsextonNOSPAMgmail.com>
+- Guillaume Martres <smarterNOSPAMubuntu.com>
+- Hannu Koivisto <azureNOSPAMiki.fi>
+- Hans-Peter Deifel <hpdeifelNOSPAMgmx.de>
+- Ian Eure <ian.eureNOSPAMgmail.com>
+- Ingo Lohmar <i.lohmarNOSPAMgmail.com>
+- Ivan Brennan <ivan.brennanNOSPAMgmail.com>
+- Jan Tatarik <jan.tatarikNOSPAMxing.com>
+- Jasper St. Pierre <jstpierreNOSPAMmecheye.net>
+- Jeff Bellegarde <jbellegardeNOSPAMwhitepages.com>
+- Jeff Dairiki <dairikiNOSPAMdairiki.org>
+- Jesse Alama <jesse.alamaNOSPAMgmail.com>
+- Johann Klähn <kljohannNOSPAMgmail.com>
+- John Mastro <john.b.mastroNOSPAMgmail.com>
+- John Wiegley <johnwNOSPAMnewartisans.com>
+- Jonas Bernoulli <jonasNOSPAMbernoul.li>
+- Jonathan Roes <jroesNOSPAMjroes.net>
+- Jordan Greenberg <jordanNOSPAMsoftwareslave.com>
+- Josiah Schwab <jschwabNOSPAMgmail.com>
+- Julien Danjou <julienNOSPAMdanjou.info>
+- Justin Caratzas <justin.caratzasNOSPAMgmail.com>
+- Kan-Ru Chen <kanruNOSPAMkanru.info>
+- Kan-Ru Chen <kosterNOSPAMdebian.org>
+- Keshav Kini <keshav.kiniNOSPAMgmail.com>
+- Kimberly Wolk <kimwolkNOSPAMhotmail.com>
+- Kyle Meyer <kyleNOSPAMkyleam.com>
+- Laurent Laffont <laurent.laffontNOSPAMgmail.com>
+- Laverne Schrock <laverneNOSPAMschrock.email>
+- Leandro Facchinetti <meNOSPAMleafac.com>
+- Lele Gaifax <leleNOSPAMmetapensiero.it>
+- Leo Liu <sdl.webNOSPAMgmail.com>
+- Leonardo Etcheverry <leoNOSPAMkalio.net>
+- Lingchao Xin <douglarekNOSPAMusers.noreply.github.com>
+- Lluís Vilanova <vilanovaNOSPAMac.upc.edu>
+- Loic Dachary <loicNOSPAMdachary.org>
+- Luís Oliveira <luismboNOSPAMgmail.com>
+- Luke Amdor <luke.amdorNOSPAMgmail.com>
+- Manuel Vázquez Acosta <mva.ledNOSPAMgmail.com>
+- Marcel Wolf <mwolfNOSPAMml1.net>
+- Marc Herbert <marc.herbertNOSPAMgmail.com>
+- Marcin Bachry <hegel666NOSPAMgmail.com>
+- Marco Craveiro <marco.craveiroNOSPAMgmail.com>
+- Marian Schubert <marian.schubertNOSPAMgmail.com>
+- Mario Rodas <marsamNOSPAMusers.noreply.github.com>
+- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
+- Mark Hepburn <Mark.HepburnNOSPAMcsiro.au>
+- Mark Karpov <markkarpovNOSPAMopmbx.org>
+- Mark Oteiza <mvoteizaNOSPAMudel.edu>
+- Matus Goljer <dota.keysNOSPAMgmail.com>
+- Michael Fogleman <michaelwfoglemanNOSPAMgmail.com>
+- Michael Griffiths <mikeyNOSPAMcich.li>
+- Michael Heerdegen <michael_heerdegenNOSPAMweb.de>
+- Michal Sojka <sojkam1NOSPAMfel.cvut.cz>
+- Miles Bader <milesNOSPAMgnu.org>
+- Miloš Mošić <mosic.milosNOSPAMgmail.com>
+- Mitchel Humpherys <mitch.specialNOSPAMgmail.com>
+- Moritz Bunkus <moritzNOSPAMbunkus.org>
+- Natalie Weizenbaum <nex342NOSPAMgmail.com>
+- Nguyễn Tuấn Anh <ubolontonNOSPAMgmail.com>
+- Nic Ferier <nicNOSPAMferrier.me.uk>
+- Nick Alcock <nick.alcockNOSPAMoracle.com>
+- Nick Alexander <nalexanderNOSPAMmozilla.com>
+- Nick Dimiduk <ndimidukNOSPAMgmail.com>
+- Nicklas Lindgren <niliNOSPAMgulmohar.se>
+- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
+- Nicolas Petton <nicolasNOSPAMpetton.fr>
+- Nicolas Richard <theonewiththeevillookNOSPAMyahoo.fr>
+- Nikolay Martynov <mar.kolyaNOSPAMgmail.com>
+- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
+- Ole Arndt <oliver.arndtNOSPAMcegedim.com>
+- Oleh Krehel <ohwoeowhoNOSPAMgmail.com>
+- Óscar Fuentes <ofvNOSPAMwanadoo.es>
+- Paul Stadig <paulNOSPAMstadig.name>
+- Pavel Holejsovsky <pavel.holejsovskyNOSPAMupek.com>
+- Pekka Pessi <nospamNOSPAMpessi.fi>
+- Peter Eisentraut <peterNOSPAMeisentraut.org>
+- Peter Jaros <peter.a.jarosNOSPAMgmail.com>
+- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
+- Peter Vasil <mailNOSPAMpetervasil.net>
+- Philippe Vaucher <philippe.vaucherNOSPAMgmail.com>
+- Philipp Haselwarter <philippNOSPAMhaselwarter.org>
+- Philip Weaver <philip.weaverNOSPAMgmail.com>
+- Phil Jackson <philNOSPAMshellarchive.co.uk>
+- Phil Sainty <philNOSPAMcatalyst.net.nz>
+- Pieter Praet <pieterNOSPAMpraet.org>
+- Prathamesh Sonpatki <csonpatkiNOSPAMgmail.com>
+- rabio <rabiodevNOSPAMo2.pl>
+- Rafael Laboissiere <rafaelNOSPAMlaboissiere.net>
+- Raimon Grau <raimonNOSPAM3scale.net>
+- Ramkumar Ramachandra <artagnonNOSPAMgmail.com>
+- Remco van 't Veer <rwvtveerNOSPAMxs4all.nl>
+- Rémi Vanicat <vanicatNOSPAMdebian.org>
+- René Stadler <mailNOSPAMrenestadler.de>
+- Richard Kim <emacs18NOSPAMgmail.com>
+- Robert Boone <robo4288NOSPAMgmail.com>
+- Robin Green <greenrdNOSPAMgreenrd.org>
+- Roger Crew <crewNOSPAMcs.stanford.edu>
+- Romain Francoise <romainNOSPAMorebokech.com>
+- Ron Parker <rparkerNOSPAMa123systems.com>
+- Roy Crihfield <rscrihfNOSPAMgmail.com>
+- Rüdiger Sonderfeld <ruedigerNOSPAMc-plusplus.net>
+- Russell Black <black.russellNOSPAMgmail.com>
+- Ryan C. Thompson <rctNOSPAMthompsonclan.org>
+- Samuel Bronson <naestenNOSPAMgmail.com>
+- Samuel W. Flint <swflintNOSPAMflintfam.org>
+- Sanjoy Das <sanjoyNOSPAMplayingwithpointers.com>
+- Sean Allred <codeNOSPAMseanallred.com>
+- Sean Bryant <sbryantNOSPAMhackinggibsons.com>
+- Sebastian Wiesner <lunaryornNOSPAMgmail.com>
+- Sébastien Gross <sebNOSPAMchezwam.org>
+- Seong-Kook Shin <cinskyNOSPAMgmail.com>
+- Sergey Pashinin <sergeyNOSPAMpashinin.com>
+- Sergey Vinokurov <serg.fooNOSPAMgmail.com>
+- Servilio Afre Puentes <afrepues@mcmaster.ca>
+- Silent Sphere <silentsphere110NOSPAMgmail.com>
+- Štěpán Němec <stepnemNOSPAMgmail.com>
+- Steven Chow <steveNOSPAMmyfreestuffapp.com>
+- Steven E. Harris <sehNOSPAMpanix.com>
+- Steven Thomas <sthomas314NOSPAMgmail.com>
+- Steven Vancoillie <steven.vancoillieNOSPAMrunbox.com>
+- Steve Purcell <steveNOSPAMsanityinc.com>
+- Suhail Shergill <suhailshergillNOSPAMgmail.com>
+- Sylvain Rousseau <thisirsNOSPAMgmail.com>
+- Syohei Yoshida <syohexNOSPAMgmail.com>
+- Takafumi Arakaki <aka.tkfNOSPAMgmail.com>
+- Teemu Likonen <tlikonenNOSPAMiki.fi>
+- Teruki Shigitani <teruki.shigitaniNOSPAMgmail.com>
+- Thierry Volpiatto <thierry.volpiattoNOSPAMgmail.com>
+- Thomas A Caswell <tcaswellNOSPAMgmail.com>
+- Thomas Frössman <thomasfNOSPAMjossystem.se>
+- Thomas Jost <thomas.jostNOSPAMgmail.com>
+- Thomas Riccardi <riccardi.thomasNOSPAMgmail.com>
+- Tibor Simko <tibor.simkoNOSPAMcern.ch>
+- Timo Juhani Lindfors <timo.lindforsNOSPAMiki.fi>
+- Tim Perkins <tprk77NOSPAMgmail.com>
+- Tim Wraight <timNOSPAMwraight.net>
+- Ting-Yu Lin <aethanycNOSPAMgmail.com>
+- Tom Feist <shabbleNOSPAMmetavore.org>
+- Tunc Uzlu <bb2020NOSPAMusers.noreply.github.com>
+- Vineet Naik <vineetNOSPAMhelpshift.com>
+- Wei Huang <weihNOSPAMopera.com>
+- Wilfred Hughes <meNOSPAMwilfred.me.uk>
+- Win Treese <treeseNOSPAMacm.org>
+- Xavier Noria <fxnNOSPAMhashref.com>
+- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+- York Zhao <gtdplatformNOSPAMgmail.com>
+- Yuichi Higashi <aaa707bNOSPAMgmail.com>
+- Zach Latta <zachNOSPAMzachlatta.com>
--- /dev/null
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
--- /dev/null
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+\1f
+File: dir, Node: Top This is the top of the INFO tree
+
+ This (the Directory node) gives a menu of major topics.
+ Typing "q" exits, "?" lists all Info commands, "d" returns here,
+ "h" gives a primer for first-timers,
+ "mEmacs<Return>" visits the Emacs manual, etc.
+
+ In Emacs, you can click mouse button 2 on a menu item or cross reference
+ to select it.
+
+* Menu:
+
+Emacs
+* Magit: (magit). Using Git from Emacs with Magit.
--- /dev/null
+;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Phil Jackson <philNOSPAMshellarchive.co.uk>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package assists the user in editing the list of commits to be
+;; rewritten during an interactive rebase.
+
+;; When the user initiates an interactive rebase, e.g. using "r e" in
+;; a Magit buffer or on the command line using "git rebase -i REV",
+;; Git invokes the `$GIT_SEQUENCE_EDITOR' (or if that is undefined
+;; `$GIT_EDITOR' or even `$EDITOR') letting the user rearrange, drop,
+;; reword, edit, and squash commits.
+
+;; This package provides the major-mode `git-rebase-mode' which makes
+;; doing so much more fun, by making the buffer more colorful and
+;; providing the following commands:
+;;
+;; C-c C-c Tell Git to make it happen.
+;; C-c C-k Tell Git that you changed your mind, i.e. abort.
+;;
+;; p Move point to previous line.
+;; n Move point to next line.
+;;
+;; M-p Move the commit at point up.
+;; M-n Move the commit at point down.
+;;
+;; k Drop the commit at point.
+;; c Don't drop the commit at point.
+;; r Change the message of the commit at point.
+;; e Edit the commit at point.
+;; s Squash the commit at point, into the one above.
+;; f Like "s" but don't also edit the commit message.
+;; x Add a script to be run with the commit at point
+;; being checked out.
+;;
+;; RET Show the commit at point in another buffer.
+;; C-/ Undo last change.
+
+;; You should probably also read the `git-rebase' manpage.
+
+;;; Code:
+
+(require 'dash)
+(require 'easymenu)
+(require 'server)
+(require 'with-editor)
+(require 'magit)
+
+(and (require 'async-bytecomp nil t)
+ (memq 'magit (bound-and-true-p async-bytecomp-allowed-packages))
+ (fboundp 'async-bytecomp-package-mode)
+ (async-bytecomp-package-mode 1))
+
+(eval-when-compile (require 'recentf))
+
+;;; Options
+;;;; Variables
+
+(defgroup git-rebase nil
+ "Edit Git rebase sequences."
+ :group 'tools)
+
+(defcustom git-rebase-auto-advance t
+ "Whether to move to next line after changing a line."
+ :group 'git-rebase
+ :type 'boolean)
+
+(defcustom git-rebase-show-instructions t
+ "Whether to show usage instructions inside the rebase buffer."
+ :group 'git-rebase
+ :type 'boolean)
+
+(defcustom git-rebase-confirm-cancel t
+ "Whether confirmation is required to cancel."
+ :group 'git-rebase
+ :type 'boolean)
+
+;;;; Faces
+
+(defgroup git-rebase-faces nil
+ "Faces used by Git-Rebase mode."
+ :group 'faces
+ :group 'git-rebase)
+
+(defface git-rebase-hash '((t (:inherit magit-hash)))
+ "Face for commit hashes."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-description nil
+ "Face for commit descriptions."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-killed-action
+ '((t (:inherit font-lock-comment-face :strike-through t)))
+ "Face for commented action and exec lines."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-comment-hash
+ '((t (:inherit git-rebase-hash :weight bold)))
+ "Face for commit hashes in commit message comments."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-comment-heading
+ '((t :inherit font-lock-keyword-face))
+ "Face used for headings in rebase message comments."
+ :group 'git-commit-faces)
+
+;;; Keymaps
+
+(defvar git-rebase-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map special-mode-map)
+ (define-key map (kbd "q") 'undefined)
+ (define-key map [remap undo] 'git-rebase-undo)
+ (define-key map (kbd "RET") 'git-rebase-show-commit)
+ (define-key map (kbd "SPC") 'git-rebase-show-or-scroll-up)
+ (define-key map (kbd "x") 'git-rebase-exec)
+ (define-key map (kbd "c") 'git-rebase-pick)
+ (define-key map (kbd "r") 'git-rebase-reword)
+ (define-key map (kbd "w") 'git-rebase-reword)
+ (define-key map (kbd "e") 'git-rebase-edit)
+ (define-key map (kbd "m") 'git-rebase-edit)
+ (define-key map (kbd "s") 'git-rebase-squash)
+ (define-key map (kbd "f") 'git-rebase-fixup)
+ (define-key map (kbd "y") 'git-rebase-insert)
+ (define-key map (kbd "k") 'git-rebase-kill-line)
+ (define-key map (kbd "C-k") 'git-rebase-kill-line)
+ (define-key map (kbd "p") 'git-rebase-backward-line)
+ (define-key map (kbd "n") 'forward-line)
+ (define-key map (kbd "M-p") 'git-rebase-move-line-up)
+ (define-key map (kbd "M-n") 'git-rebase-move-line-down)
+ (define-key map (kbd "M-<up>") 'git-rebase-move-line-up)
+ (define-key map (kbd "M-<down>") 'git-rebase-move-line-down)
+ (define-key map (kbd "C-x C-t") 'git-rebase-move-line-up)
+ map)
+ "Keymap for Git-Rebase mode.")
+
+(put 'git-rebase-reword :advertised-binding "r")
+(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p"))
+(put 'git-rebase-kill-line :advertised-binding "k")
+
+(easy-menu-define git-rebase-mode-menu git-rebase-mode-map
+ "Git-Rebase mode menu"
+ '("Rebase"
+ ["Pick" git-rebase-pick t]
+ ["Reword" git-rebase-reword t]
+ ["Edit" git-rebase-edit t]
+ ["Squash" git-rebase-squash t]
+ ["Fixup" git-rebase-fixup t]
+ ["Kill" git-rebase-kill-line t]
+ ["Execute" git-rebase-exec t]
+ ["Move Down" git-rebase-move-line-down t]
+ ["Move Up" git-rebase-move-line-up t]
+ "---"
+ ["Cancel" with-editor-cancel t]
+ ["Finish" with-editor-finish t]))
+
+(defvar git-rebase-command-descriptions
+ '((with-editor-finish . "tell Git to make it happen")
+ (with-editor-cancel . "tell Git that you changed your mind, i.e. abort")
+ (git-rebase-backward-line . "move point to previous line")
+ (forward-line . "move point to next line")
+ (git-rebase-move-line-up . "move the commit at point up")
+ (git-rebase-move-line-down . "move the commit at point down")
+ (git-rebase-show-commit . "show the commit at point in another buffer")
+ (undo . "undo last change")
+ (git-rebase-kill-line . "drop the commit at point")))
+
+;;; Commands
+
+(defun git-rebase-pick ()
+ "Use commit on current line."
+ (interactive)
+ (git-rebase-set-action "pick"))
+
+(defun git-rebase-reword ()
+ "Edit message of commit on current line."
+ (interactive)
+ (git-rebase-set-action "reword"))
+
+(defun git-rebase-edit ()
+ "Stop at the commit on the current line."
+ (interactive)
+ (git-rebase-set-action "edit"))
+
+(defun git-rebase-squash ()
+ "Meld commit on current line into previous commit, edit message."
+ (interactive)
+ (git-rebase-set-action "squash"))
+
+(defun git-rebase-fixup ()
+ "Meld commit on current line into previous commit, discard its message."
+ (interactive)
+ (git-rebase-set-action "fixup"))
+
+(defvar-local git-rebase-line nil)
+(defvar-local git-rebase-comment-re nil)
+
+(defun git-rebase-set-action (action)
+ (goto-char (line-beginning-position))
+ (if (and (looking-at git-rebase-line)
+ (not (string-match-p "\\(e\\|exec\\)$" (match-string 1))))
+ (let ((inhibit-read-only t))
+ (replace-match action t t nil 1)
+ (when git-rebase-auto-advance
+ (forward-line)))
+ (ding)))
+
+(defun git-rebase-line-p (&optional pos)
+ (save-excursion
+ (when pos (goto-char pos))
+ (goto-char (line-beginning-position))
+ (looking-at-p git-rebase-line)))
+
+(defun git-rebase-region-bounds ()
+ (when (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))))))
+
+(defun git-rebase-move-line-down (n)
+ "Move the current commit (or command) N lines down.
+If N is negative, move the commit up instead. With an active
+region, move all the lines that the region touches, not just the
+current line."
+ (interactive "p")
+ (-let* (((beg end) (or (git-rebase-region-bounds)
+ (list (line-beginning-position)
+ (1+ (line-end-position)))))
+ (pt-offset (- (point) beg))
+ (mark-offset (and mark-active (- (mark) beg))))
+ (save-restriction
+ (narrow-to-region
+ (point-min)
+ (1+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward git-rebase-line nil t))
+ (point))))
+ (if (or (and (< n 0) (= beg (point-min)))
+ (and (> n 0) (= end (point-max)))
+ (> end (point-max)))
+ (ding)
+ (goto-char (if (< n 0) beg end))
+ (forward-line n)
+ (atomic-change-group
+ (let ((inhibit-read-only t))
+ (insert (delete-and-extract-region beg end)))
+ (let ((new-beg (- (point) (- end beg))))
+ (when (use-region-p)
+ (setq deactivate-mark nil)
+ (set-mark (+ new-beg mark-offset)))
+ (goto-char (+ new-beg pt-offset))))))))
+
+(defun git-rebase-move-line-up (n)
+ "Move the current commit (or command) N lines up.
+If N is negative, move the commit down instead. With an active
+region, move all the lines that the region touches, not just the
+current line."
+ (interactive "p")
+ (git-rebase-move-line-down (- n)))
+
+(defun git-rebase-highlight-region (start end window rol)
+ (let ((inhibit-read-only t)
+ (deactivate-mark nil)
+ (bounds (git-rebase-region-bounds)))
+ (mapc #'delete-overlay magit-section-highlight-overlays)
+ (when bounds
+ (magit-section-make-overlay (car bounds) (cadr bounds)
+ 'magit-section-heading-selection))
+ (if (and bounds (not magit-keep-region-overlay))
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol)
+ (funcall (default-value 'redisplay-highlight-region-function)
+ start end window rol))))
+
+(defun git-rebase-unhighlight-region (rol)
+ (mapc #'delete-overlay magit-section-highlight-overlays)
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol))
+
+(defun git-rebase-kill-line ()
+ "Kill the current action line."
+ (interactive)
+ (goto-char (line-beginning-position))
+ (when (and (looking-at git-rebase-line)
+ (not (eq (char-after) (string-to-char comment-start))))
+ (let ((inhibit-read-only t))
+ (insert comment-start))
+ (when git-rebase-auto-advance
+ (forward-line))))
+
+(defun git-rebase-insert (rev)
+ "Read an arbitrary commit and insert it below current line."
+ (interactive (list (magit-read-branch-or-commit "Insert revision")))
+ (forward-line)
+ (--if-let (magit-rev-format "%h %s" rev)
+ (let ((inhibit-read-only t))
+ (insert "pick " it ?\n))
+ (user-error "Unknown revision")))
+
+(defun git-rebase-exec (arg)
+ "Insert a shell command to be run after the proceeding commit.
+
+If there already is such a command on the current line, then edit
+that instead. With a prefix argument insert a new command even
+when there already is one on the current line. With empty input
+remove the command on the current line, if any."
+ (interactive "P")
+ (let ((inhibit-read-only t) initial command)
+ (unless arg
+ (goto-char (line-beginning-position))
+ (when (looking-at (concat git-rebase-comment-re "?"
+ "\\(e\\|exec\\) \\(.*\\)"))
+ (setq initial (match-string-no-properties 2))))
+ (setq command (read-shell-command "Execute: " initial))
+ (pcase (list command initial)
+ (`("" nil) (ding))
+ (`("" ,_)
+ (delete-region (match-beginning 0) (1+ (match-end 0))))
+ (`(,_ nil)
+ (forward-line)
+ (insert (concat "exec " command "\n"))
+ (unless git-rebase-auto-advance
+ (forward-line -1)))
+ (_
+ (replace-match (concat "exec " command) t t)
+ (if git-rebase-auto-advance
+ (forward-line)
+ (goto-char (line-beginning-position)))))))
+
+(defun git-rebase-undo (&optional arg)
+ "Undo some previous changes.
+Like `undo' but works in read-only buffers."
+ (interactive "P")
+ (let ((inhibit-read-only t))
+ (undo arg)))
+
+(defun git-rebase--show-commit (&optional scroll)
+ (let ((disable-magit-save-buffers t))
+ (save-excursion
+ (goto-char (line-beginning-position))
+ (--if-let (and (looking-at git-rebase-line)
+ (match-string 2))
+ (if scroll
+ (magit-diff-show-or-scroll-up)
+ (apply #'magit-show-commit it (magit-diff-arguments)))
+ (ding)))))
+
+(defun git-rebase-show-commit ()
+ "Show the commit on the current line if any."
+ (interactive)
+ (git-rebase--show-commit))
+
+(defun git-rebase-show-or-scroll-up ()
+ "Update the commit buffer for commit on current line."
+ (interactive)
+ (git-rebase--show-commit t))
+
+(defun git-rebase-backward-line (&optional n)
+ "Move N lines backward (forward if N is negative).
+Like `forward-line' but go into the opposite direction."
+ (interactive "p")
+ (forward-line (- n)))
+
+;;; Mode
+
+;;;###autoload
+(define-derived-mode git-rebase-mode special-mode "Git Rebase"
+ "Major mode for editing of a Git rebase file.
+
+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."
+ :group 'git-rebase
+ (setq comment-start (or (magit-get "core.commentChar") "#"))
+ (setq git-rebase-comment-re (concat "^" (regexp-quote comment-start)))
+ (setq git-rebase-line
+ (concat "^\\(" (regexp-quote comment-start) "?"
+ "\\(?:[fprse]\\|pick\\|reword\\|edit\\|squash\\|fixup\\|exec\\)\\) "
+ "\\(?:\\([^ \n]+\\) \\(.*\\)\\)?"))
+ (setq font-lock-defaults (list (git-rebase-mode-font-lock-keywords) t t))
+ (unless git-rebase-show-instructions
+ (let ((inhibit-read-only t))
+ (flush-lines git-rebase-comment-re)))
+ (with-editor-mode 1)
+ (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)
+ (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)
+ (when (boundp 'save-place)
+ (setq save-place nil)))
+
+(defun git-rebase-cancel-confirm (force)
+ (or (not (buffer-modified-p))
+ force
+ (magit-confirm 'abort-rebase "Abort this rebase")))
+
+(defun git-rebase-autostash-save ()
+ (--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash"))
+ (push (cons 'stash it) with-editor-cancel-alist)))
+
+(defun git-rebase-autostash-apply ()
+ (--when-let (cdr (assq 'stash with-editor-cancel-alist))
+ (magit-stash-apply it)))
+
+(defun git-rebase-match-comment-line (limit)
+ (re-search-forward (concat git-rebase-comment-re ".*") limit t))
+
+(defun git-rebase-match-killed-action (limit)
+ (re-search-forward (concat git-rebase-comment-re "[^ \n].*") limit t))
+
+(defun git-rebase-mode-font-lock-keywords ()
+ "Font lock keywords for Git-Rebase mode."
+ `(("^\\([efprs]\\|pick\\|reword\\|edit\\|squash\\|fixup\\) \\([^ \n]+\\) \\(.*\\)"
+ (1 'font-lock-keyword-face)
+ (2 'git-rebase-hash)
+ (3 'git-rebase-description))
+ ("^\\(exec\\) \\(.*\\)"
+ (1 'font-lock-keyword-face)
+ (2 'git-rebase-description))
+ (git-rebase-match-comment-line 0 'font-lock-comment-face)
+ (git-rebase-match-killed-action 0 'git-rebase-killed-action t)
+ (,(format "^%s Rebase \\([^ ]*\\) onto \\([^ ]*\\)" comment-start)
+ (1 'git-rebase-comment-hash t)
+ (2 'git-rebase-comment-hash t))
+ (,(format "^%s \\(Commands:\\)" comment-start)
+ (1 'git-rebase-comment-heading 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."
+ (let ((inhibit-read-only t))
+ (save-excursion
+ (goto-char (point-min))
+ (when (and git-rebase-show-instructions
+ (re-search-forward
+ (concat git-rebase-comment-re " Commands:\n")
+ nil t))
+ (--each git-rebase-command-descriptions
+ (insert (format "%s %-8s %s\n"
+ comment-start
+ (substitute-command-keys (format "\\[%s]" (car it)))
+ (cdr it))))
+ (while (re-search-forward (concat git-rebase-comment-re
+ "\\( ?\\)\\([^,],\\) \\([^ ]+\\) = ")
+ nil t)
+ (let ((cmd (intern (concat "git-rebase-" (match-string 3)))))
+ (if (not (fboundp cmd))
+ (delete-region (line-beginning-position) (1+ (line-end-position)))
+ (replace-match " " t t nil 1)
+ (replace-match
+ (format "%-8s"
+ (mapconcat #'key-description
+ (--filter (not (eq (elt it 0) 'menu-bar))
+ (reverse (where-is-internal cmd)))
+ ", "))
+ t t nil 2))))))))
+
+(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t)
+
+(defun git-rebase-mode-disable-before-save-hook ()
+ (set (make-local-variable 'before-save-hook) nil))
+
+(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook)
+
+;;;###autoload
+(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
+;;;###autoload
+(add-to-list 'auto-mode-alist
+ (cons git-rebase-filename-regexp 'git-rebase-mode))
+
+(add-to-list 'with-editor-server-window-alist
+ (cons git-rebase-filename-regexp 'switch-to-buffer))
+
+(eval-after-load 'recentf
+ '(add-to-list 'recentf-exclude git-rebase-filename-regexp))
+
+(add-to-list 'with-editor-file-name-history-exclude git-rebase-filename-regexp)
+
+(provide 'git-rebase)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; git-rebase.el ends here
--- /dev/null
+;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements commands for applying Git diffs or parts
+;; of such a diff. The supported "apply variants" are apply, stage,
+;; unstage, discard, and reverse - more than Git itself knows about,
+;; at least at the porcelain level.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-diff)
+(require 'magit-wip)
+
+;; For `magit-apply'
+(declare-function magit-am-popup 'magit-sequence)
+;; For `magit-discard-files'
+(declare-function magit-checkout-stage 'magit)
+(declare-function magit-checkout-read-stage 'magit)
+(defvar auto-revert-verbose)
+;; For `magit-stage-untracked'
+(declare-function magit-submodule-add 'magit-submodule)
+(declare-function magit-submodule-read-name 'magit-submodule)
+
+(require 'dired)
+
+;;; Options
+
+(defcustom magit-delete-by-moving-to-trash t
+ "Whether Magit uses the system's trash can."
+ :package-version '(magit . "2.1.0")
+ :group 'magit
+ :type 'boolean)
+
+(defcustom magit-unstage-committed t
+ "Whether unstaging a committed change reverts it instead.
+
+A committed change cannot be unstaged, because staging and
+unstaging are actions that are concerned with the differences
+between the index and the working tree, not with committed
+changes.
+
+If this option is non-nil (the default), then typing \"u\"
+(`magit-unstage') on a committed change, causes it to be
+reversed in the index but not the working tree. For more
+information see command `magit-reverse-in-index'."
+ :package-version '(magit . "2.4.1")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-reverse-atomically nil
+ "Whether to reverse changes atomically.
+
+If some changes can be reversed while others cannot, then nothing
+is reversed if the value of this option is non-nil. But when it
+is nil, then the changes that can be reversed are reversed and
+for the other changes diff files are created that contain the
+rejected reversals."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+;;; Commands
+;;;; Apply
+
+(defun magit-apply (&rest args)
+ "Apply the change at point to the working tree.
+With a prefix argument fallback to a 3-way merge. Doing
+so causes the change to be applied to the index as well."
+ (interactive (and current-prefix-arg (list "--3way")))
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(,(or `unstaged `staged) ,_)
+ (user-error "Change is already in the working tree"))
+ (`(untracked ,(or `file `files))
+ (magit-am-popup))
+ (`(,_ region) (magit-apply-region it args))
+ (`(,_ hunk) (magit-apply-hunk it args))
+ (`(,_ hunks) (magit-apply-hunks it args))
+ (`(,_ file) (magit-apply-diff it args))
+ (`(,_ files) (magit-apply-diffs it args)))))
+
+(defun magit-apply--section-content (section)
+ (buffer-substring-no-properties (if (eq (magit-section-type section) 'hunk)
+ (magit-section-start section)
+ (magit-section-content section))
+ (magit-section-end section)))
+
+(defun magit-apply-diffs (sections &rest args)
+ (setq sections (magit-apply--get-diffs sections))
+ (magit-apply-patch sections args
+ (mapconcat
+ (lambda (s)
+ (concat (magit-diff-file-header s)
+ (magit-apply--section-content s)))
+ sections "")))
+
+(defun magit-apply-diff (section &rest args)
+ (setq section (car (magit-apply--get-diffs (list section))))
+ (magit-apply-patch section args
+ (concat (magit-diff-file-header section)
+ (magit-apply--section-content section))))
+
+(defun magit-apply-hunks (sections &rest args)
+ (let ((section (magit-section-parent (car sections))))
+ (when (string-match "^diff --cc" (magit-section-value section))
+ (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
+ (magit-apply-patch section args
+ (concat (magit-section-diff-header section)
+ (mapconcat 'magit-apply--section-content
+ sections "")))))
+
+(defun magit-apply-hunk (section &rest args)
+ (when (string-match "^diff --cc" (magit-section-parent-value section))
+ (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
+ (magit-apply-patch (magit-section-parent section) args
+ (concat (magit-diff-file-header section)
+ (magit-apply--section-content section))))
+
+(defun magit-apply-region (section &rest args)
+ (unless (magit-diff-context-p)
+ (user-error "Not enough context to apply region. Increase the context"))
+ (when (string-match "^diff --cc" (magit-section-parent-value section))
+ (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
+ (magit-apply-patch (magit-section-parent section) args
+ (concat (magit-diff-file-header section)
+ (magit-diff-hunk-region-patch section args))))
+
+(defun magit-apply-patch (section:s args patch)
+ (let* ((files (if (atom section:s)
+ (list (magit-section-value section:s))
+ (mapcar 'magit-section-value section:s)))
+ (command (symbol-name this-command))
+ (command (if (and command (string-match "^magit-\\([^-]+\\)" command))
+ (match-string 1 command)
+ "apply")))
+ (when (and magit-wip-before-change-mode (not inhibit-magit-refresh))
+ (magit-wip-commit-before-change files (concat " before " command)))
+ (with-temp-buffer
+ (insert patch)
+ (magit-run-git-with-input
+ "apply" args "-p0"
+ (unless (magit-diff-context-p) "--unidiff-zero")
+ "--ignore-space-change" "-"))
+ (unless inhibit-magit-refresh
+ (when magit-wip-after-apply-mode
+ (magit-wip-commit-after-apply files (concat " after " command)))
+ (magit-refresh))))
+
+(defun magit-apply--get-selection ()
+ (or (magit-region-sections 'hunk 'file)
+ (let ((section (magit-current-section)))
+ (pcase (magit-section-type section)
+ ((or `hunk `file) section)
+ ((or `staged `unstaged `untracked
+ `stashed-index `stashed-worktree `stashed-untracked)
+ (magit-section-children section))
+ (_ (user-error "Cannot apply this, it's not a change"))))))
+
+(defun magit-apply--get-diffs (sections)
+ (magit-section-case
+ ([file diffstat]
+ (--map (or (magit-get-section
+ (append `((file . ,(magit-section-value it)))
+ (magit-section-ident magit-root-section)))
+ (error "Cannot get required diff headers"))
+ sections))
+ (t sections)))
+
+;;;; Stage
+
+(defun magit-stage (&optional intent)
+ "Add the change at point to the staging area.
+With a prefix argument, INTENT, and an untracked file (or files)
+at point, stage the file but not its content."
+ (interactive "P")
+ (--if-let (and (derived-mode-p 'magit-mode) (magit-apply--get-selection))
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(untracked ,_) (magit-stage-untracked intent))
+ (`(unstaged region) (magit-apply-region it "--cached"))
+ (`(unstaged hunk) (magit-apply-hunk it "--cached"))
+ (`(unstaged hunks) (magit-apply-hunks it "--cached"))
+ (`(unstaged file) (magit-stage-1 "-u" (list (magit-section-value it))))
+ (`(unstaged files) (magit-stage-1 "-u" (magit-region-values)))
+ (`(unstaged list) (magit-stage-1 "-u"))
+ (`(staged ,_) (user-error "Already staged"))
+ (`(committed ,_) (user-error "Cannot stage committed changes"))
+ (`(undefined ,_) (user-error "Cannot stage this change")))
+ (call-interactively 'magit-stage-file)))
+
+;;;###autoload
+(defun magit-stage-file (file)
+ "Stage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be staged. Otherwise stage the file at point without
+requiring confirmation."
+ (interactive
+ (let* ((atpoint (magit-section-when (file)))
+ (current (magit-file-relative-name))
+ (choices (nconc (magit-modified-files)
+ (magit-untracked-files)))
+ (default (car (member (or atpoint current) choices))))
+ (list (if (or current-prefix-arg (not default))
+ (magit-completing-read "Stage file" choices
+ nil t nil nil default)
+ default))))
+ (magit-with-toplevel
+ (magit-stage-1 nil (list file))))
+
+;;;###autoload
+(defun magit-stage-modified (&optional all)
+ "Stage all changes to files modified in the worktree.
+Stage all new content of tracked files and remove tracked files
+that no longer exist in the working tree from the index also.
+With a prefix argument also stage previously untracked (but not
+ignored) files.
+\('git add --update|--all .')."
+ (interactive (progn (unless (or (not (magit-anything-staged-p))
+ (magit-confirm 'stage-all-changes))
+ (user-error "Abort"))
+ (list current-prefix-arg)))
+ (magit-with-toplevel
+ (magit-stage-1 (if all "--all" "-u"))))
+
+(defun magit-stage-1 (arg &optional files)
+ (magit-wip-commit-before-change files " before stage")
+ (magit-run-git "add" arg (if files (cons "--" files) "."))
+ (when magit-auto-revert-mode
+ (mapc #'magit-turn-on-auto-revert-mode-if-desired files))
+ (magit-wip-commit-after-apply files " after stage"))
+
+(defun magit-stage-untracked (&optional intent)
+ (let* ((section (magit-current-section))
+ (files (pcase (magit-diff-scope)
+ (`file (list (magit-section-value section)))
+ (`files (magit-region-values))
+ (`list (magit-untracked-files))))
+ plain repos)
+ (dolist (file files)
+ (if (magit-git-repo-p file t)
+ (push file repos)
+ (push file plain)))
+ (magit-wip-commit-before-change files " before stage")
+ (when plain
+ (magit-run-git "add" (and intent "--intent-to-add")
+ "--" plain)
+ (when magit-auto-revert-mode
+ (mapc #'magit-turn-on-auto-revert-mode-if-desired plain)))
+ (dolist (repo repos)
+ (save-excursion
+ (goto-char (magit-section-start
+ (magit-get-section
+ `((file . ,repo) (untracked) (status)))))
+ (magit-submodule-add
+ (let ((default-directory
+ (file-name-as-directory (expand-file-name repo))))
+ (magit-get "remote" (or (magit-get-remote) "origin") "url"))
+ repo
+ (magit-submodule-read-name repo))))
+ (magit-wip-commit-after-apply files " after stage")))
+
+;;;; Unstage
+
+(defun magit-unstage ()
+ "Remove the change at point from the staging area."
+ (interactive)
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(untracked ,_) (user-error "Cannot unstage untracked changes"))
+ (`(unstaged ,_) (user-error "Already unstaged"))
+ (`(staged region) (magit-apply-region it "--reverse" "--cached"))
+ (`(staged hunk) (magit-apply-hunk it "--reverse" "--cached"))
+ (`(staged hunks) (magit-apply-hunks it "--reverse" "--cached"))
+ (`(staged file) (magit-unstage-1 (list (magit-section-value it))))
+ (`(staged files) (magit-unstage-1 (magit-region-values)))
+ (`(staged list) (magit-unstage-all))
+ (`(committed ,_) (if magit-unstage-committed
+ (magit-reverse-in-index)
+ (user-error "Cannot unstage committed changes")))
+ (`(undefined ,_) (user-error "Cannot unstage this change")))))
+
+;;;###autoload
+(defun magit-unstage-file (file)
+ "Unstage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be unstaged. Otherwise unstage the file at point
+without requiring confirmation."
+ (interactive
+ (let* ((atpoint (magit-section-when (file)))
+ (current (magit-file-relative-name))
+ (choices (magit-staged-files))
+ (default (car (member (or atpoint current) choices))))
+ (list (if (or current-prefix-arg (not default))
+ (magit-completing-read "Unstage file" choices
+ nil t nil nil default)
+ default))))
+ (magit-with-toplevel
+ (magit-unstage-1 (list file))))
+
+(defun magit-unstage-1 (files)
+ (magit-wip-commit-before-change files " before unstage")
+ (if (magit-no-commit-p)
+ (magit-run-git "rm" "--cached" "--" files)
+ (magit-run-git "reset" "HEAD" "--" files))
+ (magit-wip-commit-after-apply files " after unstage"))
+
+;;;###autoload
+(defun magit-unstage-all ()
+ "Remove all changes from the staging area."
+ (interactive)
+ (when (or (and (not (magit-anything-unstaged-p))
+ (not (magit-untracked-files)))
+ (magit-confirm 'unstage-all-changes))
+ (magit-wip-commit-before-change nil " before unstage")
+ (magit-run-git "reset" "HEAD" "--")
+ (magit-wip-commit-after-apply nil " after unstage")))
+
+;;;; Discard
+
+(defun magit-discard ()
+ "Remove the change at point."
+ (interactive)
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(committed ,_) (user-error "Cannot discard committed changes"))
+ (`(undefined ,_) (user-error "Cannot discard this change"))
+ (`(,_ region) (magit-discard-region it))
+ (`(,_ hunk) (magit-discard-hunk it))
+ (`(,_ hunks) (magit-discard-hunks it))
+ (`(,_ file) (magit-discard-file it))
+ (`(,_ files) (magit-discard-files it))
+ (`(,_ list) (magit-discard-files it)))))
+
+(defun magit-discard-region (section)
+ (when (magit-confirm 'discard "Discard region")
+ (magit-discard-apply section 'magit-apply-region)))
+
+(defun magit-discard-hunk (section)
+ (when (magit-confirm 'discard "Discard hunk")
+ (magit-discard-apply section 'magit-apply-hunk)))
+
+(defun magit-discard-apply (section apply)
+ (if (eq (magit-diff-type section) 'unstaged)
+ (funcall apply section "--reverse")
+ (if (magit-anything-unstaged-p
+ nil (if (eq (magit-section-type section) 'file)
+ (magit-section-value section)
+ (magit-section-parent-value section)))
+ (progn (let ((inhibit-magit-refresh t))
+ (funcall apply section "--reverse" "--cached")
+ (funcall apply section "--reverse" "--reject"))
+ (magit-refresh))
+ (funcall apply section "--reverse" "--index"))))
+
+(defun magit-discard-hunks (sections)
+ (when (magit-confirm 'discard
+ (format "Discard %s 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)
+ (let ((section (car sections)))
+ (if (eq (magit-diff-type section) 'unstaged)
+ (funcall apply sections "--reverse")
+ (if (magit-anything-unstaged-p
+ nil (if (eq (magit-section-type section) 'file)
+ (magit-section-value section)
+ (magit-section-parent-value section)))
+ (progn (let ((inhibit-magit-refresh t))
+ (funcall apply sections "--reverse" "--cached")
+ (funcall apply sections "--reverse" "--reject"))
+ (magit-refresh))
+ (funcall apply sections "--reverse" "--index")))))
+
+(defun magit-discard-file (section)
+ (magit-discard-files (list section)))
+
+(defun magit-discard-files (sections)
+ (let ((auto-revert-verbose nil)
+ (type (magit-diff-type (car sections)))
+ (status (magit-file-status))
+ files delete resurrect rename discard discard-new resolve)
+ (dolist (section sections)
+ (let ((file (magit-section-value section)))
+ (push file files)
+ (pcase (cons (pcase type
+ (`staged ?X)
+ (`unstaged ?Y)
+ (`untracked ?Z))
+ (cddr (assoc file status)))
+ (`(?Z) (--each (magit-untracked-files nil file)
+ (push it delete)))
+ ((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete))
+ ((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete))
+ ((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve))
+ (`(,_ ?A ?A) (push file resolve))
+ (`(?X ?M ,(or ? ?M ?D)) (push section discard))
+ (`(?Y ,_ ?M ) (push section discard))
+ (`(?X ?A ?M ) (push file discard-new))
+ (`(?X ?C ?M ) (push file discard-new))
+ (`(?X ?A ,(or ? ?D)) (push file delete))
+ (`(?X ?C ,(or ? ?D)) (push file delete))
+ (`(?X ?D ,(or ? ?M )) (push file resurrect))
+ (`(?Y ,_ ?D ) (push file resurrect))
+ (`(?X ?R ,(or ? ?M ?D)) (push file rename)))))
+ (unwind-protect
+ (let ((inhibit-magit-refresh t))
+ (magit-wip-commit-before-change files " before discard")
+ (when resolve
+ (dolist (file (nreverse resolve))
+ (magit-checkout-stage file (magit-checkout-read-stage file))))
+ (magit-discard-files--resurrect (nreverse resurrect))
+ (magit-discard-files--delete (nreverse delete) status)
+ (magit-discard-files--rename (nreverse rename) status)
+ (magit-discard-files--discard (nreverse discard)
+ (nreverse discard-new))
+ (magit-wip-commit-after-apply files " after discard"))
+ (magit-refresh))))
+
+(defun magit-discard-files--resurrect (files)
+ (when (magit-confirm-files 'resurrect files)
+ (if (eq (magit-diff-type) 'staged)
+ (magit-call-git "reset" "--" files)
+ (magit-call-git "checkout" "--" files))))
+
+(defun magit-discard-files--delete (files status)
+ (when (if magit-delete-by-moving-to-trash
+ (magit-confirm-files 'trash files)
+ (magit-confirm-files 'delete files))
+ (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
+ (dolist (file files)
+ (if (memq (magit-diff-type) '(unstaged untracked))
+ (dired-delete-file file dired-recursive-deletes
+ magit-delete-by-moving-to-trash)
+ (pcase (nth 3 (assoc file status))
+ (? (delete-file file t)
+ (magit-call-git "rm" "--cached" "--" file))
+ (?M (let ((temp (magit-git-string "checkout-index" "--temp" file)))
+ (string-match
+ (format "\\(.+?\\)\t%s" (regexp-quote file)) temp)
+ (rename-file (match-string 1 temp)
+ (setq temp (concat file ".~{index}~")))
+ (delete-file temp t))
+ (magit-call-git "rm" "--cached" "--force" "--" file))
+ (?D (magit-call-git "checkout" "--" file)
+ (delete-file file t)
+ (magit-call-git "rm" "--cached" "--force" "--" file))))))))
+
+(defun magit-discard-files--rename (files status)
+ (when (magit-confirm 'rename "Undo rename %s" "Undo %i renames"
+ (mapcar (lambda (file)
+ (setq file (assoc file status))
+ (format "%s -> %s" (cadr file) (car file)))
+ files))
+ (dolist (file files)
+ (let ((orig (cadr (assoc file status))))
+ (if (file-exists-p file)
+ (magit-call-git "mv" file orig)
+ (magit-call-git "rm" "--cached" "--" file)
+ (magit-call-git "reset" "--" orig))))))
+
+(defun magit-discard-files--discard (sections new-files)
+ (let ((files (mapcar #'magit-section-value sections)))
+ (when (magit-confirm-files
+ 'discard (append files new-files)
+ (format "Discard %s changes in" (magit-diff-type)))
+ (if (eq (magit-diff-type (car sections)) 'unstaged)
+ (magit-call-git "checkout" "--" files)
+ (when new-files
+ (magit-call-git "add" "--" new-files)
+ (magit-call-git "reset" "--" new-files))
+ (let ((binaries (magit-staged-binary-files)))
+ (when binaries
+ (setq sections
+ (--filter (not (member (magit-section-value it) 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-modified-files t)))
+ (setq binaries (--separate (member it modified) binaries)))
+ (when (cadr binaries)
+ (magit-call-git "reset" "--" (cadr binaries)))
+ (when (car binaries)
+ (user-error
+ (concat
+ "Cannot discard staged changes to binary files, "
+ "which also have unstaged changes. Unstage instead.")))))))))
+
+;;;; Reverse
+
+(defun magit-reverse (&rest args)
+ "Reverse the change at point in the working tree.
+With a prefix argument fallback to a 3-way merge. Doing
+so causes the change to be applied to the index as well."
+ (interactive (and current-prefix-arg (list "--3way")))
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(untracked ,_) (user-error "Cannot reverse untracked changes"))
+ (`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
+ (`(,_ region) (magit-reverse-region it args))
+ (`(,_ hunk) (magit-reverse-hunk it args))
+ (`(,_ hunks) (magit-reverse-hunks it args))
+ (`(,_ file) (magit-reverse-file it args))
+ (`(,_ files) (magit-reverse-files it args))
+ (`(,_ list) (magit-reverse-files it args)))))
+
+(defun magit-reverse-region (section args)
+ (when (magit-confirm 'reverse "Reverse region")
+ (magit-reverse-apply section 'magit-apply-region args)))
+
+(defun magit-reverse-hunk (section args)
+ (when (magit-confirm 'reverse "Reverse hunk")
+ (magit-reverse-apply section 'magit-apply-hunk args)))
+
+(defun magit-reverse-hunks (sections args)
+ (when (magit-confirm 'reverse
+ (format "Reverse %s 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)
+ (magit-reverse-files (list section) args))
+
+(defun magit-reverse-files (sections args)
+ (-let [(binaries sections)
+ (let ((bs (magit-staged-binary-files)))
+ (--separate (member (magit-section-value it) bs) sections))]
+ (when (magit-confirm-files 'reverse (mapcar #'magit-section-value sections))
+ (if (= (length sections) 1)
+ (magit-reverse-apply (car sections) 'magit-apply-diff args)
+ (magit-reverse-apply sections 'magit-apply-diffs args)))
+ (when binaries
+ (user-error "Cannot reverse binary files"))))
+
+(defun magit-reverse-apply (section:s apply args)
+ (funcall apply section:s "--reverse" args
+ (and (not magit-reverse-atomically)
+ (not (member "--3way" args))
+ "--reject")))
+
+(defun magit-reverse-in-index (&rest args)
+ "Reverse the change at point in the index but not the working tree.
+
+Use this command to extract a change from `HEAD', while leaving
+it in the working tree, so that it can later be committed using
+a separate commit. A typical workflow would be:
+
+0. Optionally make sure that there are no uncommitted changes.
+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.
+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\"
+ and then type \"c c\" to create a new commit."
+ (interactive)
+ (magit-reverse (cons "--cached" args)))
+
+;;; magit-apply.el ends soon
+(provide 'magit-apply)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-apply.el ends here
--- /dev/null
+;;; magit-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+\f
+;;;### (autoloads nil "git-rebase" "git-rebase.el" (22576 8242 0
+;;;;;; 0))
+;;; Generated autoloads from git-rebase.el
+
+(autoload 'git-rebase-mode "git-rebase" "\
+Major mode for editing of a Git rebase file.
+
+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.
+
+\(fn)" t nil)
+
+(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
+
+(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp 'git-rebase-mode))
+
+;;;***
+\f
+;;;### (autoloads nil "magit" "magit.el" (22576 8242 0 0))
+;;; Generated autoloads from magit.el
+
+(autoload 'magit-status "magit" "\
+Show the status of the current Git repository in a buffer.
+With a prefix argument prompt for a repository to be shown.
+With two prefix arguments prompt for an arbitrary directory.
+If that directory isn't the root of an existing repository
+then offer to initialize it as a new repository.
+
+\(fn &optional DIRECTORY)" t nil)
+
+(autoload 'magit-status-internal "magit" "\
+
+
+\(fn DIRECTORY)" nil nil)
+ (autoload 'magit-show-refs-popup "magit" nil t)
+
+(autoload 'magit-show-refs-head "magit" "\
+List and compare references in a dedicated buffer.
+Refs are compared with `HEAD'.
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-show-refs-current "magit" "\
+List and compare references in a dedicated buffer.
+Refs are compared with the current branch or `HEAD' if
+it is detached.
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-show-refs "magit" "\
+List and compare references in a dedicated buffer.
+Refs are compared with a branch read form the user.
+
+\(fn &optional REF ARGS)" t nil)
+
+(autoload 'magit-find-file "magit" "\
+View FILE from REV.
+Switch to a buffer visiting blob REV:FILE,
+creating one if none already exists.
+
+\(fn REV FILE)" t nil)
+
+(autoload 'magit-find-file-other-window "magit" "\
+View FILE from REV, in another window.
+Like `magit-find-file', but create a new window or reuse an
+existing one.
+
+\(fn REV FILE)" t nil)
+
+(autoload 'magit-dired-jump "magit" "\
+Visit file at point using Dired.
+With a prefix argument, visit in another window. If there
+is no file at point then instead visit `default-directory'.
+
+\(fn &optional OTHER-WINDOW)" t nil)
+
+(autoload 'magit-checkout-file "magit" "\
+Checkout FILE from REV.
+
+\(fn REV FILE)" t nil)
+
+(autoload 'magit-init "magit" "\
+Initialize a Git repository, then show its status.
+
+If the directory is below an existing repository, then the user
+has to confirm that a new one should be created inside. If the
+directory is the root of the existing repository, then the user
+has to confirm that it should be reinitialized.
+
+Non-interactively DIRECTORY is (re-)initialized unconditionally.
+
+\(fn DIRECTORY)" t nil)
+ (autoload 'magit-branch-popup "magit" nil t)
+
+(autoload 'magit-checkout "magit" "\
+Checkout REVISION, updating the index and the working tree.
+If REVISION is a local branch then that becomes the current
+branch. If it is something else then `HEAD' becomes detached.
+Checkout fails if the working tree or the staging area contain
+changes.
+
+\(git checkout REVISION).
+
+\(fn REVISION)" t nil)
+
+(autoload 'magit-branch "magit" "\
+Create BRANCH at branch or revision START-POINT.
+
+\(git branch [ARGS] BRANCH START-POINT).
+
+\(fn BRANCH START-POINT &optional ARGS)" t nil)
+
+(autoload 'magit-branch-and-checkout "magit" "\
+Create and checkout BRANCH at branch or revision START-POINT.
+
+\(git checkout [ARGS] -b BRANCH START-POINT).
+
+\(fn BRANCH START-POINT &optional ARGS)" t nil)
+
+(autoload 'magit-branch-orphan "magit" "\
+Create and checkout an orphan BRANCH with contents from revision START-POINT.
+
+\(git checkout --orphan [ARGS] BRANCH START-POINT).
+
+\(fn BRANCH START-POINT &optional ARGS)" t nil)
+
+(autoload 'magit-branch-spinoff "magit" "\
+Create new branch from the unpushed commits.
+
+Create and checkout a new branch starting at and tracking the
+current branch. That branch in turn is reset to the last commit
+it shares with its upstream. If the current branch has no
+upstream or no unpushed commits, then the new branch is created
+anyway and the previously current branch is not touched.
+
+This is useful to create a feature branch after work has already
+began on the old branch (likely but not necessarily \"master\").
+
+If the current branch is a member of the value of option
+`magit-branch-prefer-remote-upstream' (which see), then the
+current branch will be used as the starting point as usual, but
+the upstream of the starting-point may be used as the upstream
+of the new branch, instead of the starting-point itself.
+
+If optional FROM is non-nil, then the source branch is reset to
+that commit, instead of to the last commit it shares with its
+upstream. Interactively, FROM is non-nil, when the region
+selects some commits, and among those commits, FROM it is the
+commit that is the fewest commits ahead of the source branch.
+
+The commit at the other end of the selection actually does not
+matter, all commits between FROM and `HEAD' are moved to the new
+branch. If FROM is not reachable from `HEAD' or is reachable
+from the source branch's upstream, then an error is raised.
+
+\(fn BRANCH &optional FROM &rest ARGS)" t nil)
+
+(autoload 'magit-branch-reset "magit" "\
+Reset a branch to the tip of another branch or any other commit.
+
+When the branch being reset is the current branch, then do a
+hard reset. If there are any uncommitted changes, then the user
+has to confirming the reset because those changes would be lost.
+
+This is useful when you have started work on a feature branch but
+realize it's all crap and want to start over.
+
+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.
+
+\(fn BRANCH TO &optional ARGS SET-UPSTREAM)" t nil)
+
+(autoload 'magit-branch-delete "magit" "\
+Delete one or multiple branches.
+If the region marks multiple branches, then offer to delete
+those, otherwise prompt for a single branch to be deleted,
+defaulting to the branch at point.
+
+\(fn BRANCHES &optional FORCE)" t nil)
+
+(autoload 'magit-branch-rename "magit" "\
+Rename branch OLD to NEW.
+With prefix, forces the rename even if NEW already exists.
+
+\(git branch -m|-M OLD NEW).
+
+\(fn OLD NEW &optional FORCE)" t nil)
+
+(autoload 'magit-branch-config-popup "magit" "\
+Popup console for setting branch variables.
+
+\(fn BRANCH)" t nil)
+
+(autoload 'magit-edit-branch*description "magit" "\
+Edit the description of the current branch.
+With a prefix argument edit the description of another branch.
+
+The description for the branch named NAME is stored in the Git
+variable `branch.<name>.description'.
+
+\(fn BRANCH)" t nil)
+
+(autoload 'magit-set-branch*merge/remote "magit" "\
+Set or unset the upstream of the current branch.
+With a prefix argument do so for another branch.
+
+When the branch in question already has an upstream then simply
+unsets it. Invoke this command again to set another upstream.
+
+Together the Git variables `branch.<name>.remote' and
+`branch.<name>.merge' define the upstream branch of the local
+branch named NAME. The value of `branch.<name>.remote' is the
+name of the upstream remote. The value of `branch.<name>.merge'
+is the full reference of the upstream branch, on the remote.
+
+Non-interactively, when UPSTREAM is non-nil, then always set it
+as the new upstream, regardless of whether another upstream was
+already set. When nil, then always unset.
+
+\(fn BRANCH UPSTREAM)" t nil)
+
+(autoload 'magit-cycle-branch*rebase "magit" "\
+Cycle the value of `branch.<name>.rebase' for the current branch.
+With a prefix argument cycle the value for another branch.
+
+The Git variables `branch.<name>.rebase' controls whether pulling
+into the branch named NAME is done by rebasing that branch onto
+the fetched branch or by merging that branch.
+
+When `true' then pulling is done by rebasing.
+When `false' then pulling is done by merging.
+
+When that variable is undefined then the value of `pull.rebase'
+is used instead. It defaults to `false'.
+
+\(fn BRANCH)" t nil)
+
+(autoload 'magit-cycle-branch*pushRemote "magit" "\
+Cycle the value of `branch.<name>.pushRemote' for the current branch.
+With a prefix argument cycle the value for another branch.
+
+The Git variable `branch.<name>.pushRemote' specifies the remote
+that the branch named NAME is usually pushed to. The value has
+to be the name of an existing remote.
+
+If that variable is undefined, then the value of the Git variable
+`remote.pushDefault' is used instead, provided that it is defined,
+which by default it is not.
+
+\(fn BRANCH)" t nil)
+
+(autoload 'magit-cycle-pull\.rebase "magit" "\
+Cycle the repository-local value of `pull.rebase'.
+
+The Git variable `pull.rebase' specifies whether pulling is done
+by rebasing or by merging. It can be overwritten using the Git
+variable `branch.<name>.rebase'.
+
+When `true' then pulling is done by rebasing.
+When `false' (the default) then pulling is done by merging.
+
+\(fn)" t nil)
+
+(autoload 'magit-cycle-remote\.pushDefault "magit" "\
+Cycle the repository-local value of `remote.pushDefault'.
+
+The Git variable `remote.pushDefault' specifies the remote that
+local branches are usually pushed to. It can be overwritten
+using the Git variable `branch.<name>.pushRemote'.
+
+\(fn)" t nil)
+
+(autoload 'magit-cycle-branch*autoSetupMerge "magit" "\
+Cycle the repository-local value of `branch.autoSetupMerge'.
+
+The Git variable `branch.autoSetupMerge' under what circumstances
+creating a branch (named NAME) should result in the variables
+`branch.<name>.merge' and `branch.<name>.remote' being set
+according to the starting point used to create the branch. If
+the starting point isn't a branch, then these variables are never
+set.
+
+When `always' then the variables are set regardless of whether
+the starting point is a local or a remote branch.
+
+When `true' (the default) then the variable are set when the
+starting point is a remote branch, but not when it is a local
+branch.
+
+When `false' then the variables are never set.
+
+\(fn)" t nil)
+
+(autoload 'magit-cycle-branch*autoSetupRebase "magit" "\
+Cycle the repository-local value of `branch.autoSetupRebase'.
+
+The Git variable `branch.autoSetupRebase' specifies whether
+creating a branch (named NAME) should result in the variable
+`branch.<name>.rebase' being set to `true'.
+
+When `always' then the variable is set regardless of whether the
+starting point is a local or a remote branch.
+
+When `local' then the variable are set when the starting point
+is a local branch, but not when it is a remote branch.
+
+When `remote' then the variable are set when the starting point
+is a remote branch, but not when it is a local branch.
+
+When `never' (the default) then the variable is never set.
+
+\(fn)" t nil)
+ (autoload 'magit-merge-popup "magit" nil t)
+
+(autoload 'magit-merge "magit" "\
+Merge commit REV into the current branch; using default message.
+
+Unless there are conflicts or a prefix argument is used create a
+merge commit using a generic commit message and without letting
+the user inspect the result. With a prefix argument pretend the
+merge failed to give the user the opportunity to inspect the
+merge.
+
+\(git merge --no-edit|--no-commit [ARGS] REV)
+
+\(fn REV &optional ARGS NOCOMMIT)" t nil)
+
+(autoload 'magit-merge-editmsg "magit" "\
+Merge commit REV into the current branch; and edit message.
+Perform the merge and prepare a commit message but let the user
+edit it.
+
+\(git merge --edit --no-ff [ARGS] rev)
+
+\(fn REV &optional ARGS)" t nil)
+
+(autoload 'magit-merge-nocommit "magit" "\
+Merge commit REV into the current branch; pretending it failed.
+Pretend the merge failed to give the user the opportunity to
+inspect the merge and change the commit message.
+
+\(git merge --no-commit --no-ff [ARGS] rev)
+
+\(fn REV &optional ARGS)" t nil)
+
+(autoload 'magit-merge-preview "magit" "\
+Preview result of merging REV into the current branch.
+
+\(fn REV)" t nil)
+
+(autoload 'magit-merge-abort "magit" "\
+Abort the current merge operation.
+
+\(git merge --abort)
+
+\(fn)" t nil)
+ (autoload 'magit-reset-popup "magit" nil t)
+
+(autoload 'magit-reset-index "magit" "\
+Reset the index to COMMIT.
+Keep the head and working tree as-is, so if COMMIT refers to the
+head this effectively unstages all changes.
+
+\(git reset COMMIT .)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset "magit" "\
+Reset the head and index to COMMIT, but not the working tree.
+With a prefix argument also reset the working tree.
+
+\(git reset --mixed|--hard COMMIT)
+
+\(fn COMMIT &optional HARD)" t nil)
+
+(autoload 'magit-reset-head "magit" "\
+Reset the head and index to COMMIT, but not the working tree.
+
+\(git reset --mixed COMMIT)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-soft "magit" "\
+Reset the head to COMMIT, but not the index and working tree.
+
+\(git reset --soft REVISION)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-hard "magit" "\
+Reset the head, index, and working tree to COMMIT.
+
+\(git reset --hard REVISION)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-worktree-checkout "magit" "\
+Checkout BRANCH in a new worktree at PATH.
+
+\(fn PATH BRANCH)" t nil)
+
+(autoload 'magit-worktree-branch "magit" "\
+Create a new BRANCH and check it out in a new worktree at PATH.
+
+\(fn PATH BRANCH START-POINT &optional FORCE)" t nil)
+ (autoload 'magit-tag-popup "magit" nil t)
+
+(autoload 'magit-tag "magit" "\
+Create a new tag with the given NAME at REV.
+With a prefix argument annotate the tag.
+
+\(git tag [--annotate] NAME REV)
+
+\(fn NAME REV &optional ARGS)" t nil)
+
+(autoload 'magit-tag-delete "magit" "\
+Delete one or more tags.
+If the region marks multiple tags (and nothing else), then offer
+to delete those, otherwise prompt for a single tag to be deleted,
+defaulting to the tag at point.
+
+\(git tag -d TAGS)
+
+\(fn TAGS)" t nil)
+ (autoload 'magit-notes-popup "magit" nil t)
+ (autoload 'magit-file-popup "magit" nil t)
+
+(defvar global-magit-file-mode nil "\
+Non-nil if Global Magit-File mode is enabled.
+See the `global-magit-file-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `global-magit-file-mode'.")
+
+(custom-autoload 'global-magit-file-mode "magit" nil)
+
+(autoload 'global-magit-file-mode "magit" "\
+Toggle Magit-File mode in all buffers.
+With prefix ARG, enable Global Magit-File mode if ARG is positive;
+otherwise, disable it. If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
+Magit-File mode is enabled in all buffers where
+`magit-file-mode-turn-on' would do it.
+See `magit-file-mode' for more information on Magit-File mode.
+
+\(fn &optional ARG)" t nil)
+ (autoload 'magit-dispatch-popup "magit" nil t)
+ (autoload 'magit-run-popup "magit" nil t)
+
+(autoload 'magit-git-command "magit" "\
+Execute a Git subcommand asynchronously, displaying the output.
+With a prefix argument run Git in the root of the current
+repository, otherwise in `default-directory'.
+
+\(fn ARGS DIRECTORY)" t nil)
+
+(autoload 'magit-git-command-topdir "magit" "\
+Execute a Git subcommand asynchronously, displaying the output.
+Run Git in the top-level directory of the current repository.
+
+\(fn)" t nil)
+
+(autoload 'magit-shell-command "magit" "\
+Execute a shell command asynchronously, displaying the output.
+With a prefix argument run the command in the root of the current
+repository, otherwise in `default-directory'.
+
+\(fn ARGS DIRECTORY)" t nil)
+
+(autoload 'magit-shell-command-topdir "magit" "\
+Execute a shell command asynchronously, displaying the output.
+Run the command in the top-level directory of the current repository.
+
+\(fn)" t nil)
+
+(autoload 'magit-list-repositories "magit" "\
+Display a list of repositories.
+
+Use the options `magit-repository-directories'
+and `magit-repository-directories-depth' to
+control which repositories are displayed.
+
+\(fn)" t nil)
+
+(autoload 'magit-version "magit" "\
+Return the version of Magit currently in use.
+When called interactive also show the used versions of Magit,
+Git, and Emacs in the echo area.
+
+\(fn)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-apply" "magit-apply.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-apply.el
+
+(autoload 'magit-stage-file "magit-apply" "\
+Stage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be staged. Otherwise stage the file at point without
+requiring confirmation.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-stage-modified "magit-apply" "\
+Stage all changes to files modified in the worktree.
+Stage all new content of tracked files and remove tracked files
+that no longer exist in the working tree from the index also.
+With a prefix argument also stage previously untracked (but not
+ignored) files.
+\('git add --update|--all .').
+
+\(fn &optional ALL)" t nil)
+
+(autoload 'magit-unstage-file "magit-apply" "\
+Unstage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be unstaged. Otherwise unstage the file at point
+without requiring confirmation.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-unstage-all "magit-apply" "\
+Remove all changes from the staging area.
+
+\(fn)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-autorevert" "magit-autorevert.el" (22576
+;;;;;; 8242 0 0))
+;;; Generated autoloads from magit-autorevert.el
+
+(defvar magit-revert-buffers t)
+
+(defvar magit-auto-revert-mode (and magit-revert-buffers (not global-auto-revert-mode) (not noninteractive)) "\
+Non-nil if Magit-Auto-Revert mode is enabled.
+See the `magit-auto-revert-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `magit-auto-revert-mode'.")
+
+(custom-autoload 'magit-auto-revert-mode "magit-autorevert" nil)
+
+(autoload 'magit-auto-revert-mode "magit-autorevert" "\
+Toggle Auto-Revert mode in all buffers.
+With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive;
+otherwise, disable it. If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
+Auto-Revert mode is enabled in all buffers where
+`magit-turn-on-auto-revert-mode-if-desired' would do it.
+See `auto-revert-mode' for more information on Auto-Revert mode.
+
+\(fn &optional ARG)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-bisect" "magit-bisect.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-bisect.el
+ (autoload 'magit-bisect-popup "magit-bisect" nil t)
+
+(autoload 'magit-bisect-start "magit-bisect" "\
+Start a bisect session.
+
+Bisecting a bug means to find the commit that introduced it.
+This command starts such a bisect session by asking for a know
+good and a bad commit. To move the session forward use the
+other actions from the bisect popup (\\<magit-status-mode-map>\\[magit-bisect-popup]).
+
+\(fn BAD GOOD)" t nil)
+
+(autoload 'magit-bisect-reset "magit-bisect" "\
+After bisecting, cleanup bisection state and return to original `HEAD'.
+
+\(fn)" t nil)
+
+(autoload 'magit-bisect-good "magit-bisect" "\
+While bisecting, mark the current commit as good.
+Use this after you have asserted that the commit does not contain
+the bug in question.
+
+\(fn)" t nil)
+
+(autoload 'magit-bisect-bad "magit-bisect" "\
+While bisecting, mark the current commit as bad.
+Use this after you have asserted that the commit does contain the
+bug in question.
+
+\(fn)" t nil)
+
+(autoload 'magit-bisect-skip "magit-bisect" "\
+While bisecting, skip the current commit.
+Use this if for some reason the current commit is not a good one
+to test. This command lets Git choose a different one.
+
+\(fn)" t nil)
+
+(autoload 'magit-bisect-run "magit-bisect" "\
+Bisect automatically by running commands after each step.
+
+Unlike `git bisect run' this can be used before bisecting has
+begun. In that case it behaves like `git bisect start; git
+bisect run'.
+
+\(fn CMDLINE &optional BAD GOOD)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-blame" "magit-blame.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-blame.el
+ (autoload 'magit-blame-popup "magit-blame" nil t)
+
+(autoload 'magit-blame "magit-blame" "\
+Display edit history of FILE up to REVISION.
+
+Interactively blame the file being visited in the current buffer.
+If the buffer visits a revision of that file, then blame up to
+that revision, otherwise blame the file's full history, including
+uncommitted changes.
+
+If Magit-Blame mode is already turned on then blame recursively, by
+visiting REVISION:FILE (using `magit-find-file'), where revision
+is the revision before the revision that added the lines at
+point.
+
+ARGS is a list of additional arguments to pass to `git blame';
+only arguments available from `magit-blame-popup' should be used.
+
+\(fn REVISION FILE &optional ARGS)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-commit" "magit-commit.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-commit.el
+
+(autoload 'magit-commit "magit-commit" "\
+Create a new commit on HEAD.
+With a prefix argument amend to the commit at HEAD instead.
+
+\(git commit [--amend] ARGS)
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-commit-amend "magit-commit" "\
+Amend the last commit.
+
+\(git commit --amend ARGS)
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-commit-extend "magit-commit" "\
+Amend the last commit, without editing the 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.
+\(git commit
+--amend --no-edit)
+
+\(fn &optional ARGS OVERRIDE-DATE)" t nil)
+
+(autoload 'magit-commit-reword "magit-commit" "\
+Reword the last commit, ignoring staged changes.
+
+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.
+
+\(git commit --amend --only)
+
+\(fn &optional ARGS OVERRIDE-DATE)" t nil)
+
+(autoload 'magit-commit-fixup "magit-commit" "\
+Create a fixup commit.
+
+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'.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-squash "magit-commit" "\
+Create a squash commit, without editing the squash 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'.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-augment "magit-commit" "\
+Create a squash commit, editing the squash 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'.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-instant-fixup "magit-commit" "\
+Create a fixup commit targeting COMMIT and instantly rebase.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-instant-squash "magit-commit" "\
+Create a squash commit targeting COMMIT and instantly rebase.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-diff" "magit-diff.el" (22576 8242 0
+;;;;;; 0))
+;;; Generated autoloads from magit-diff.el
+
+(autoload 'magit-diff-popup "magit-diff" "\
+Popup console for diff commands.
+
+\(fn ARG)" t nil)
+
+(autoload 'magit-diff-buffer-file-popup "magit-diff" "\
+Popup console for diff commands.
+
+This is a variant of `magit-diff-popup' which shows the same popup
+but which limits the diff to the file being visited in the current
+buffer.
+
+\(fn)" t nil)
+
+(autoload 'magit-diff-dwim "magit-diff" "\
+Show changes for the thing at point.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff "magit-diff" "\
+Show differences between two commits.
+
+REV-OR-RANGE should be a range or a single revision. If it is a
+revision, then show changes in the working tree relative to that
+revision. If it is a range, but one side is omitted, then show
+changes relative to `HEAD'.
+
+If the region is active, use the revisions on the first and last
+line of the region as the two sides of the range. With a prefix
+argument, instead of diffing the revisions, choose a revision to
+view changes along, starting at the common ancestor of both
+revisions (i.e., use a \"...\" range).
+
+\(fn REV-OR-RANGE &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff-working-tree "magit-diff" "\
+Show changes between the current working tree and the `HEAD' commit.
+With a prefix argument show changes between the working tree and
+a commit read from the minibuffer.
+
+\(fn &optional REV ARGS FILES)" t nil)
+
+(autoload 'magit-diff-staged "magit-diff" "\
+Show changes between the index and the `HEAD' commit.
+With a prefix argument show changes between the index and
+a commit read from the minibuffer.
+
+\(fn &optional REV ARGS FILES)" t nil)
+
+(autoload 'magit-diff-unstaged "magit-diff" "\
+Show changes between the working tree and the index.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff-while-committing "magit-diff" "\
+While committing, show the changes that are about to be committed.
+While amending, invoking the command again toggles between
+showing just the new changes or all the changes that will
+be committed.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff-buffer-file "magit-diff" "\
+Show diff for the blob or file visited in the current buffer.
+
+\(fn)" t nil)
+
+(autoload 'magit-diff-paths "magit-diff" "\
+Show changes between any two files on disk.
+
+\(fn A B)" t nil)
+
+(autoload 'magit-show-commit "magit-diff" "\
+Show the revision at point.
+If there is no revision at point or with a prefix argument prompt
+for a revision.
+
+\(fn REV &optional ARGS FILES MODULE)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-ediff" "magit-ediff.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-ediff.el
+ (autoload 'magit-ediff-popup "magit-ediff" nil t)
+
+(autoload 'magit-ediff-resolve "magit-ediff" "\
+Resolve outstanding conflicts in FILE using Ediff.
+FILE has to be relative to the top directory of the repository.
+
+In the rare event that you want to manually resolve all
+conflicts, including those already resolved by Git, use
+`ediff-merge-revisions-with-ancestor'.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-stage "magit-ediff" "\
+Stage and unstage changes to FILE using Ediff.
+FILE has to be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-compare "magit-ediff" "\
+Compare REVA:FILEA with REVB:FILEB using Ediff.
+
+FILEA and FILEB have to be relative to the top directory of the
+repository. If REVA or REVB is nil then this stands for the
+working tree state.
+
+If the region is active, use the revisions on the first and last
+line of the region. With a prefix argument, instead of diffing
+the revisions, choose a revision to view changes along, starting
+at the common ancestor of both revisions (i.e., use a \"...\"
+range).
+
+\(fn REVA REVB FILEA FILEB)" t nil)
+
+(autoload 'magit-ediff-dwim "magit-ediff" "\
+Compare, stage, or resolve using Ediff.
+This command tries to guess what file, and what commit or range
+the user wants to compare, stage, or resolve using Ediff. It
+might only be able to guess either the file, or range or commit,
+in which case the user is asked about the other. It might not
+always guess right, in which case the appropriate `magit-ediff-*'
+command has to be used explicitly. If it cannot read the user's
+mind at all, then it asks the user for a command to run.
+
+\(fn)" t nil)
+
+(autoload 'magit-ediff-show-staged "magit-ediff" "\
+Show staged changes using Ediff.
+
+This only allows looking at the changes; to stage, unstage,
+and discard changes using Ediff, use `magit-ediff-stage'.
+
+FILE must be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-show-unstaged "magit-ediff" "\
+Show unstaged changes using Ediff.
+
+This only allows looking at the changes; to stage, unstage,
+and discard changes using Ediff, use `magit-ediff-stage'.
+
+FILE must be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-show-working-tree "magit-ediff" "\
+Show changes between HEAD and working tree using Ediff.
+FILE must be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-show-commit "magit-ediff" "\
+Show changes introduced by COMMIT using Ediff.
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-ediff-show-stash "magit-ediff" "\
+Show changes introduced by STASH using Ediff.
+`magit-ediff-show-stash-with-index' controls whether a
+three-buffer Ediff is used in order to distinguish changes in the
+stash that were staged.
+
+\(fn STASH)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-extras" "magit-extras.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-extras.el
+
+(autoload 'magit-run-git-gui "magit-extras" "\
+Run `git gui' for the current git repository.
+
+\(fn)" t nil)
+
+(autoload 'magit-run-git-gui-blame "magit-extras" "\
+Run `git gui blame' on the given FILENAME and COMMIT.
+Interactively run it for the current file and the HEAD, with a
+prefix or when the current file cannot be determined let the user
+choose. When the current buffer is visiting FILENAME instruct
+blame to center around the line point is on.
+
+\(fn COMMIT FILENAME &optional LINENUM)" t nil)
+
+(autoload 'magit-run-gitk "magit-extras" "\
+Run `gitk' in the current repository.
+
+\(fn)" t nil)
+
+(autoload 'magit-run-gitk-branches "magit-extras" "\
+Run `gitk --branches' in the current repository.
+
+\(fn)" t nil)
+
+(autoload 'magit-run-gitk-all "magit-extras" "\
+Run `gitk --all' in the current repository.
+
+\(fn)" t nil)
+
+(autoload 'magit-clean "magit-extras" "\
+Remove untracked files from the working tree.
+With a prefix argument also remove ignored files,
+with two prefix arguments remove ignored files only.
+
+\(git clean -f -d [-x|-X])
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'magit-gitignore "magit-extras" "\
+Instruct Git to ignore FILE-OR-PATTERN.
+With a prefix argument only ignore locally.
+
+\(fn FILE-OR-PATTERN &optional LOCAL)" t nil)
+
+(autoload 'magit-gitignore-locally "magit-extras" "\
+Instruct Git to locally ignore FILE-OR-PATTERN.
+
+\(fn FILE-OR-PATTERN)" t nil)
+
+(autoload 'magit-add-change-log-entry "magit-extras" "\
+Find change log file and add date entry and item for current change.
+This differs from `add-change-log-entry' (which see) in that
+it acts on the current hunk in a Magit buffer instead of on
+a position in a file-visiting buffer.
+
+\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil)
+
+(autoload 'magit-add-change-log-entry-other-window "magit-extras" "\
+Find change log file in other window and add entry and item.
+This differs from `add-change-log-entry-other-window' (which see)
+in that it acts on the current hunk in a Magit buffer instead of
+on a position in a file-visiting buffer.
+
+\(fn &optional WHOAMI FILE-NAME)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-log" "magit-log.el" (22576 8242 0 0))
+;;; Generated autoloads from magit-log.el
+
+(autoload 'magit-log-buffer-file-popup "magit-log" "\
+Popup console for log commands.
+
+This is a variant of `magit-log-popup' which shows the same popup
+but which limits the log to the file being visited in the current
+buffer.
+
+\(fn)" t nil)
+
+(autoload 'magit-log-current "magit-log" "\
+Show log for the current branch.
+When `HEAD' is detached or with a prefix argument show log for
+one or more revs read from the minibuffer.
+
+\(fn REVS &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log "magit-log" "\
+Show log for one or more revs read from the minibuffer.
+The user can input any revision or revisions separated by a
+space, or even ranges, but only branches and tags, and a
+representation of the commit at point, are available as
+completion candidates.
+
+\(fn REVS &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-head "magit-log" "\
+Show log for `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-branches "magit-log" "\
+Show log for all local branches and `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-all-branches "magit-log" "\
+Show log for all local and remote branches and `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-all "magit-log" "\
+Show log for all references and `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-buffer-file "magit-log" "\
+Show log for the blob or file visited in the current buffer.
+With a prefix argument or when `--follow' is part of
+`magit-log-arguments', then follow renames.
+
+\(fn &optional FOLLOW BEG END)" t nil)
+
+(autoload 'magit-reflog-current "magit-log" "\
+Display the reflog of the current branch.
+
+\(fn)" t nil)
+
+(autoload 'magit-reflog "magit-log" "\
+Display the reflog of a branch.
+
+\(fn REF)" t nil)
+
+(autoload 'magit-reflog-head "magit-log" "\
+Display the `HEAD' reflog.
+
+\(fn)" t nil)
+
+(autoload 'magit-log-move-to-parent "magit-log" "\
+Move to the Nth parent of the current commit.
+
+\(fn &optional N)" t nil)
+
+(autoload 'magit-cherry "magit-log" "\
+Show commits in a branch that are not merged in the upstream branch.
+
+\(fn HEAD UPSTREAM)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-remote" "magit-remote.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-remote.el
+
+(autoload 'magit-clone "magit-remote" "\
+Clone the REPOSITORY to DIRECTORY.
+Then show the status buffer for the new repository.
+
+\(fn REPOSITORY DIRECTORY)" t nil)
+ (autoload 'magit-remote-popup "magit-remote" nil t)
+
+(autoload 'magit-remote-add "magit-remote" "\
+Add a remote named REMOTE and fetch it.
+
+\(fn REMOTE URL)" t nil)
+
+(autoload 'magit-remote-rename "magit-remote" "\
+Rename the remote named OLD to NEW.
+
+\(fn OLD NEW)" t nil)
+
+(autoload 'magit-remote-set-url "magit-remote" "\
+Change the url of the remote named REMOTE to URL.
+
+\(fn REMOTE URL)" t nil)
+
+(autoload 'magit-remote-remove "magit-remote" "\
+Delete the remote named REMOTE.
+
+\(fn REMOTE)" t nil)
+
+(autoload 'magit-remote-set-head "magit-remote" "\
+Set the local representation of REMOTE's default branch.
+Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
+accordingly. With a prefix argument query for the branch to be
+used, which allows you to select an incorrect value if you fancy
+doing that.
+
+\(fn REMOTE &optional BRANCH)" t nil)
+
+(autoload 'magit-remote-unset-head "magit-remote" "\
+Unset the local representation of REMOTE's default branch.
+Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\".
+
+\(fn REMOTE)" t nil)
+ (autoload 'magit-fetch-popup "magit-remote" nil t)
+
+(autoload 'magit-fetch-from-pushremote "magit-remote" "\
+Fetch from the push-remote of the current branch.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-fetch-from-upstream "magit-remote" "\
+Fetch from the upstream repository of the current branch.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-fetch "magit-remote" "\
+Fetch from another repository.
+
+\(fn REMOTE ARGS)" t nil)
+
+(autoload 'magit-fetch-branch "magit-remote" "\
+Fetch a BRANCH from a REMOTE.
+
+\(fn REMOTE BRANCH ARGS)" t nil)
+
+(autoload 'magit-fetch-refspec "magit-remote" "\
+Fetch a REFSPEC from a REMOTE.
+
+\(fn REMOTE REFSPEC ARGS)" t nil)
+
+(autoload 'magit-fetch-all "magit-remote" "\
+Fetch from all remotes.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-fetch-all-prune "magit-remote" "\
+Fetch from all remotes, and prune.
+Prune remote tracking branches for branches that have been
+removed on the respective remote.
+
+\(fn)" t nil)
+
+(autoload 'magit-fetch-all-no-prune "magit-remote" "\
+Fetch from all remotes.
+
+\(fn)" t nil)
+ (autoload 'magit-pull-popup "magit-remote" nil t)
+ (autoload 'magit-pull-and-fetch-popup "magit-remote" nil t)
+
+(autoload 'magit-pull-from-pushremote "magit-remote" "\
+Pull from the push-remote of the current branch.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-pull-from-upstream "magit-remote" "\
+Pull from the upstream of the current branch.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-pull "magit-remote" "\
+Pull from a branch read in the minibuffer.
+
+\(fn SOURCE ARGS)" t nil)
+ (autoload 'magit-push-popup "magit-remote" nil t)
+
+(autoload 'magit-push-current-to-pushremote "magit-remote" "\
+Push the current branch to `branch.<name>.pushRemote'.
+If that variable is unset, then push to `remote.pushDefault'.
+
+When `magit-push-current-set-remote-if-missing' is non-nil and
+the push-remote is not configured, then read the push-remote from
+the user, set it, and then push to it. With a prefix argument
+the push-remote can be changed before pushed to it.
+
+\(fn ARGS &optional PUSH-REMOTE)" t nil)
+
+(autoload 'magit-push-current-to-upstream "magit-remote" "\
+Push the current branch to its upstream branch.
+
+When `magit-push-current-set-remote-if-missing' is non-nil and
+the upstream is not configured, then read the upstream from the
+user, set it, and then push to it. With a prefix argument the
+upstream can be changed before pushed to it.
+
+\(fn ARGS &optional UPSTREAM)" t nil)
+
+(autoload 'magit-push-current "magit-remote" "\
+Push the current branch to a branch read in the minibuffer.
+
+\(fn TARGET ARGS)" t nil)
+
+(autoload 'magit-push "magit-remote" "\
+Push an arbitrary branch or commit somewhere.
+Both the source and the target are read in the minibuffer.
+
+\(fn SOURCE TARGET ARGS)" t nil)
+
+(autoload 'magit-push-refspecs "magit-remote" "\
+Push one or multiple REFSPECS to a REMOTE.
+Both the REMOTE and the REFSPECS are read in the minibuffer. To
+use multiple REFSPECS, separate them with commas. Completion is
+only available for the part before the colon, or when no colon
+is used.
+
+\(fn REMOTE REFSPECS ARGS)" t nil)
+
+(autoload 'magit-push-matching "magit-remote" "\
+Push all matching branches to another repository.
+If multiple remotes exist, then read one from the user.
+If just one exists, use that without requiring confirmation.
+
+\(fn REMOTE &optional ARGS)" t nil)
+
+(autoload 'magit-push-tags "magit-remote" "\
+Push all tags to another repository.
+If only one remote exists, then push to that. Otherwise prompt
+for a remote, offering the remote configured for the current
+branch as default.
+
+\(fn REMOTE &optional ARGS)" t nil)
+
+(autoload 'magit-push-tag "magit-remote" "\
+Push a tag to another repository.
+
+\(fn TAG REMOTE &optional ARGS)" t nil)
+
+(autoload 'magit-push-implicitly "magit-remote" "\
+Push somewhere without using an explicit refspec.
+
+This command simply runs \"git push -v [ARGS]\". ARGS are the
+arguments specified in the popup buffer. No explicit refspec
+arguments are used. Instead the behavior depends on at least
+these Git variables: `push.default', `remote.pushDefault',
+`branch.<branch>.pushRemote', `branch.<branch>.remote',
+`branch.<branch>.merge', and `remote.<remote>.push'.
+
+To add this command to the push popup add this to your init file:
+
+ (with-eval-after-load \\='magit-remote
+ (magit-define-popup-action \\='magit-push-popup ?P
+ 'magit-push-implicitly--desc
+ 'magit-push-implicitly ?p t))
+
+The function `magit-push-implicitly--desc' attempts to predict
+what this command will do, the value it returns is displayed in
+the popup buffer.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-push-to-remote "magit-remote" "\
+Push to REMOTE without using an explicit refspec.
+The REMOTE is read in the minibuffer.
+
+This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
+are the arguments specified in the popup buffer. No refspec
+arguments are used. Instead the behavior depends on at least
+these Git variables: `push.default', `remote.pushDefault',
+`branch.<branch>.pushRemote', `branch.<branch>.remote',
+`branch.<branch>.merge', and `remote.<remote>.push'.
+
+To add this command to the push popup add this to your init file:
+
+ (with-eval-after-load \\='magit-remote
+ (magit-define-popup-action \\='magit-push-popup ?r
+ 'magit-push-to-remote--desc
+ 'magit-push-to-remote ?p t))
+
+\(fn REMOTE ARGS)" t nil)
+ (autoload 'magit-patch-popup "magit-remote" nil t)
+
+(autoload 'magit-format-patch "magit-remote" "\
+Create patches for the commits in RANGE.
+When a single commit is given for RANGE, create a patch for the
+changes introduced by that commit (unlike 'git format-patch'
+which creates patches for all commits that are reachable from
+HEAD but not from the specified commit).
+
+\(fn RANGE ARGS)" t nil)
+
+(autoload 'magit-request-pull "magit-remote" "\
+Request upstream to pull from you public repository.
+
+URL is the url of your publically accessible repository.
+START is a commit that already is in the upstream repository.
+END is the last commit, usually a branch name, which upstream
+is asked to pull. START has to be reachable from that commit.
+
+\(fn URL START END)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-sequence" "magit-sequence.el" (22576
+;;;;;; 8242 0 0))
+;;; Generated autoloads from magit-sequence.el
+
+(autoload 'magit-sequencer-continue "magit-sequence" "\
+Resume the current cherry-pick or revert sequence.
+
+\(fn)" t nil)
+
+(autoload 'magit-sequencer-skip "magit-sequence" "\
+Skip the stopped at commit during a cherry-pick or revert sequence.
+
+\(fn)" t nil)
+
+(autoload 'magit-sequencer-abort "magit-sequence" "\
+Abort the current cherry-pick or revert sequence.
+This discards all changes made since the sequence started.
+
+\(fn)" t nil)
+ (autoload 'magit-cherry-pick-popup "magit-sequence" nil t)
+
+(autoload 'magit-cherry-pick "magit-sequence" "\
+Cherry-pick COMMIT.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then pick all of them,
+without prompting.
+
+\(fn COMMIT &optional ARGS)" t nil)
+
+(autoload 'magit-cherry-apply "magit-sequence" "\
+Apply the changes in COMMIT but do not commit them.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then apply all of them,
+without prompting.
+
+\(fn COMMIT &optional ARGS)" t nil)
+ (autoload 'magit-revert-popup "magit-sequence" nil t)
+
+(autoload 'magit-revert "magit-sequence" "\
+Revert COMMIT by creating a new commit.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting.
+
+\(fn COMMIT &optional ARGS)" t nil)
+
+(autoload 'magit-revert-no-commit "magit-sequence" "\
+Revert COMMIT by applying it in reverse to the worktree.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting.
+
+\(fn COMMIT &optional ARGS)" t nil)
+ (autoload 'magit-am-popup "magit-sequence" nil t)
+
+(autoload 'magit-am-apply-patches "magit-sequence" "\
+Apply the patches FILES.
+
+\(fn &optional FILES ARGS)" t nil)
+
+(autoload 'magit-am-apply-maildir "magit-sequence" "\
+Apply the patches from MAILDIR.
+
+\(fn &optional MAILDIR ARGS)" t nil)
+
+(autoload 'magit-am-continue "magit-sequence" "\
+Resume the current patch applying sequence.
+
+\(fn)" t nil)
+
+(autoload 'magit-am-skip "magit-sequence" "\
+Skip the stopped at patch during a patch applying sequence.
+
+\(fn)" t nil)
+
+(autoload 'magit-am-abort "magit-sequence" "\
+Abort the current patch applying sequence.
+This discards all changes made since the sequence started.
+
+\(fn)" t nil)
+ (autoload 'magit-rebase-popup "magit-sequence" nil t)
+
+(autoload 'magit-rebase-onto-pushremote "magit-sequence" "\
+Rebase the current branch onto `branch.<name>.pushRemote'.
+If that variable is unset, then rebase onto `remote.pushDefault'.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-rebase-onto-upstream "magit-sequence" "\
+Rebase the current branch onto its upstream branch.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-rebase "magit-sequence" "\
+Rebase the current branch onto a branch read in the minibuffer.
+All commits that are reachable from head but not from the
+selected branch TARGET are being rebased.
+
+\(fn TARGET ARGS)" t nil)
+
+(autoload 'magit-rebase-subset "magit-sequence" "\
+Rebase a subset of the current branches history onto a new base.
+Rebase commits from START to `HEAD' onto NEWBASE.
+START has to be selected from a list of recent commits.
+
+\(fn NEWBASE START ARGS)" t nil)
+
+(autoload 'magit-rebase-interactive "magit-sequence" "\
+Start an interactive rebase sequence.
+
+\(fn COMMIT ARGS)" t nil)
+
+(autoload 'magit-rebase-autosquash "magit-sequence" "\
+Combine squash and fixup commits with their intended targets.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-rebase-edit-commit "magit-sequence" "\
+Edit a single older commit using rebase.
+
+\(fn COMMIT ARGS)" t nil)
+
+(autoload 'magit-rebase-reword-commit "magit-sequence" "\
+Reword a single older commit using rebase.
+
+\(fn COMMIT ARGS)" t nil)
+
+(autoload 'magit-rebase-continue "magit-sequence" "\
+Restart the current rebasing operation.
+In some cases this pops up a commit message buffer for you do
+edit. With a prefix argument the old message is reused as-is.
+
+\(fn &optional NOEDIT)" t nil)
+
+(autoload 'magit-rebase-skip "magit-sequence" "\
+Skip the current commit and restart the current rebase operation.
+
+\(fn)" t nil)
+
+(autoload 'magit-rebase-edit "magit-sequence" "\
+Edit the todo list of the current rebase operation.
+
+\(fn)" t nil)
+
+(autoload 'magit-rebase-abort "magit-sequence" "\
+Abort the current rebase operation, restoring the original branch.
+
+\(fn)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-stash" "magit-stash.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-stash.el
+ (autoload 'magit-stash-popup "magit-stash" nil t)
+
+(autoload 'magit-stash "magit-stash" "\
+Create a stash of the index and working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-stash-index "magit-stash" "\
+Create a stash of the index only.
+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.
+
+\(fn MESSAGE)" t nil)
+
+(autoload 'magit-stash-worktree "magit-stash" "\
+Create a stash of unstaged changes in the working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-stash-keep-index "magit-stash" "\
+Create a stash of the index and working tree, keeping index intact.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-snapshot "magit-stash" "\
+Create a snapshot of the index and working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-snapshot-index "magit-stash" "\
+Create a snapshot of the index only.
+Unstaged and untracked changes are not stashed.
+
+\(fn)" t nil)
+
+(autoload 'magit-snapshot-worktree "magit-stash" "\
+Create a snapshot of unstaged changes in the working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-stash-apply "magit-stash" "\
+Apply a stash to the working tree.
+Try to preserve the stash index. If that fails because there
+are staged changes, apply without preserving the stash index.
+
+\(fn STASH)" t nil)
+
+(autoload 'magit-stash-drop "magit-stash" "\
+Remove a stash from the stash list.
+When the region is active offer to drop all contained stashes.
+
+\(fn STASH)" t nil)
+
+(autoload 'magit-stash-clear "magit-stash" "\
+Remove all stashes saved in REF's reflog by deleting REF.
+
+\(fn REF)" t nil)
+
+(autoload 'magit-stash-branch "magit-stash" "\
+Create and checkout a new BRANCH from STASH.
+
+\(fn STASH BRANCH)" t nil)
+
+(autoload 'magit-stash-format-patch "magit-stash" "\
+Create a patch from STASH
+
+\(fn STASH)" t nil)
+
+(autoload 'magit-stash-list "magit-stash" "\
+List all stashes in a buffer.
+
+\(fn)" t nil)
+
+(autoload 'magit-stash-show "magit-stash" "\
+Show all diffs of a stash in a buffer.
+
+\(fn STASH &optional ARGS FILES)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-submodule" "magit-submodule.el" (22576
+;;;;;; 8242 0 0))
+;;; Generated autoloads from magit-submodule.el
+ (autoload 'magit-submodule-popup "magit-submodule" nil t)
+
+(autoload 'magit-submodule-add "magit-submodule" "\
+Add the repository at URL as a submodule.
+
+Optional PATH is the path to the submodule relative to the root
+of the superproject. If it is nil, then the path is determined
+based on the URL.
+
+Optional NAME is the name of the submodule. If it is nil, then
+PATH also becomes the name.
+
+\(fn URL &optional PATH NAME)" t nil)
+
+(autoload 'magit-submodule-read-name "magit-submodule" "\
+
+
+\(fn PATH)" nil nil)
+
+(autoload 'magit-submodule-setup "magit-submodule" "\
+Clone and register missing submodules and checkout appropriate commits.
+
+\(fn)" t nil)
+
+(autoload 'magit-submodule-init "magit-submodule" "\
+Register submodules listed in \".gitmodules\" into \".git/config\".
+
+\(fn)" t nil)
+
+(autoload 'magit-submodule-update "magit-submodule" "\
+Clone missing submodules and checkout appropriate commits.
+With a prefix argument also register submodules in \".git/config\".
+
+\(fn &optional INIT)" t nil)
+
+(autoload 'magit-submodule-sync "magit-submodule" "\
+Update each submodule's remote URL according to \".gitmodules\".
+
+\(fn)" t nil)
+
+(autoload 'magit-submodule-fetch "magit-submodule" "\
+Fetch all submodules.
+With a prefix argument fetch all remotes.
+
+\(fn &optional ALL)" t nil)
+
+(autoload 'magit-submodule-deinit "magit-submodule" "\
+Unregister the submodule at PATH.
+
+\(fn PATH)" t nil)
+
+(autoload 'magit-insert-submodules "magit-submodule" "\
+Insert sections for all modules.
+For each section insert the path and the output of `git describe --tags'.
+
+\(fn)" nil nil)
+
+(autoload 'magit-insert-modules-unpulled-from-upstream "magit-submodule" "\
+Insert sections for modules that haven't been pulled from the upstream.
+These sections can be expanded to show the respective commits.
+
+\(fn)" nil nil)
+
+(autoload 'magit-insert-modules-unpulled-from-pushremote "magit-submodule" "\
+Insert sections for modules that haven't been pulled from the push-remote.
+These sections can be expanded to show the respective commits.
+
+\(fn)" nil nil)
+
+(autoload 'magit-insert-modules-unpushed-to-upstream "magit-submodule" "\
+Insert sections for modules that haven't been pushed to the upstream.
+These sections can be expanded to show the respective commits.
+
+\(fn)" nil nil)
+
+(autoload 'magit-insert-modules-unpushed-to-pushremote "magit-submodule" "\
+Insert sections for modules that haven't been pushed to the push-remote.
+These sections can be expanded to show the respective commits.
+
+\(fn)" nil nil)
+
+(autoload 'magit-list-submodules "magit-submodule" "\
+Display a list of the current repository's submodules.
+
+\(fn)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-subtree" "magit-subtree.el" (22576 8242
+;;;;;; 0 0))
+;;; Generated autoloads from magit-subtree.el
+ (autoload 'magit-subtree-popup "magit-subtree" nil t)
+
+(autoload 'magit-subtree-add "magit-subtree" "\
+Add COMMIT from REPOSITORY as a new subtree at PREFIX.
+
+\(fn PREFIX REPOSITORY COMMIT ARGS)" t nil)
+
+(autoload 'magit-subtree-add-commit "magit-subtree" "\
+Add COMMIT as a new subtree at PREFIX.
+
+\(fn PREFIX COMMIT ARGS)" t nil)
+
+(autoload 'magit-subtree-merge "magit-subtree" "\
+Merge COMMIT into the PREFIX subtree.
+
+\(fn PREFIX COMMIT ARGS)" t nil)
+
+(autoload 'magit-subtree-pull "magit-subtree" "\
+Pull COMMIT from REPOSITORY into the PREFIX subtree.
+
+\(fn PREFIX REPOSITORY COMMIT ARGS)" t nil)
+
+(autoload 'magit-subtree-push "magit-subtree" "\
+Extract the history of the subtree PREFIX and push it to REF on REPOSITORY.
+
+\(fn PREFIX REPOSITORY REF ARGS)" t nil)
+
+(autoload 'magit-subtree-split "magit-subtree" "\
+Extract the history of the subtree PREFIX.
+
+\(fn PREFIX COMMIT ARGS)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil "magit-wip" "magit-wip.el" (22576 8242 0 0))
+;;; Generated autoloads from magit-wip.el
+
+(defvar magit-wip-after-save-mode nil "\
+Non-nil if Magit-Wip-After-Save mode is enabled.
+See the `magit-wip-after-save-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `magit-wip-after-save-mode'.")
+
+(custom-autoload 'magit-wip-after-save-mode "magit-wip" nil)
+
+(autoload 'magit-wip-after-save-mode "magit-wip" "\
+Toggle Magit-Wip-After-Save-Local mode in all buffers.
+With prefix ARG, enable Magit-Wip-After-Save mode if ARG is positive;
+otherwise, disable it. If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
+Magit-Wip-After-Save-Local mode is enabled in all buffers where
+`magit-wip-after-save-local-mode-turn-on' would do it.
+See `magit-wip-after-save-local-mode' for more information on Magit-Wip-After-Save-Local mode.
+
+\(fn &optional ARG)" t nil)
+
+(defvar magit-wip-after-apply-mode nil "\
+Non-nil if Magit-Wip-After-Apply mode is enabled.
+See the `magit-wip-after-apply-mode' command
+for a description of this minor mode.")
+
+(custom-autoload 'magit-wip-after-apply-mode "magit-wip" nil)
+
+(autoload 'magit-wip-after-apply-mode "magit-wip" "\
+Commit to work-in-progress refs.
+
+After applying a change using any \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected files to the current wip refs. For each branch there
+may be two wip refs; one contains snapshots of the files as found
+in the worktree and the other contains snapshots of the entries
+in the index.
+
+\(fn &optional ARG)" t nil)
+
+(defvar magit-wip-before-change-mode nil "\
+Non-nil if Magit-Wip-Before-Change mode is enabled.
+See the `magit-wip-before-change-mode' command
+for a description of this minor mode.")
+
+(custom-autoload 'magit-wip-before-change-mode "magit-wip" nil)
+
+(autoload 'magit-wip-before-change-mode "magit-wip" "\
+Commit to work-in-progress refs before certain destructive changes.
+
+Before invoking a revert command or an \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected tracked files to the current wip refs. For each branch
+there may be two wip refs; one contains snapshots of the files
+as found in the worktree and the other contains snapshots of the
+entries in the index.
+
+Only changes to files which could potentially be affected by the
+command which is about to be called are committed.
+
+\(fn &optional ARG)" t nil)
+
+;;;***
+\f
+;;;### (autoloads nil nil ("magit-core.el" "magit-git.el" "magit-mode.el"
+;;;;;; "magit-pkg.el" "magit-process.el" "magit-section.el" "magit-utils.el")
+;;;;;; (22576 8242 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; magit-autoloads.el ends here
--- /dev/null
+;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonas@bernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+
+(require 'magit-git)
+
+(require 'autorevert)
+
+(defgroup magit-auto-revert nil
+ "Revert buffers when files in repository change."
+ :group 'auto-revert
+ :group 'magit-extensions)
+
+(defcustom auto-revert-buffer-list-filter nil
+ "Filter that determines which buffers `auto-revert-buffers' reverts.
+
+This option is provided by `magit', which also redefines
+`auto-revert-buffers' to respect it. Magit users who do not turn
+on the local mode `auto-revert-mode' themselves, are best served
+by setting the value to `magit-auto-revert-repository-buffers-p'.
+
+However the default is nil, to not disturb users who do use the
+local mode directly. If you experience delays when running Magit
+commands, then you should consider using one of the predicates
+provided by Magit - especially if you also use Tramp.
+
+Users who do turn on `auto-revert-mode' in buffers in which Magit
+doesn't do that for them, should likely not use any filter.
+Users who turn on `global-auto-revert-mode', do not have to worry
+about this option, because it is disregarded if the global mode
+is enabled."
+ :package-version '(magit . "2.4.2")
+ :group 'auto-revert
+ :group 'magit-auto-revert
+ :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
+ "Whether `magit-auto-revert-mode' only reverts tracked files."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-auto-revert
+ :type 'boolean
+ :set (lambda (var val)
+ (set var val)
+ (when (and (bound-and-true-p magit-auto-revert-mode)
+ (featurep 'magit-autorevert))
+ (magit-auto-revert-mode -1)
+ (magit-auto-revert-mode))))
+
+(defcustom magit-auto-revert-immediately t
+ "Whether Magit reverts buffers immediately.
+
+If this is non-nil and either `global-auto-revert-mode' or
+`magit-auto-revert-mode' is enabled, then Magit immediately
+reverts buffers by explicitly calling `auto-revert-buffers'
+after running git for side-effects.
+
+If `auto-revert-use-notify' is non-nil (and file notifications
+are actually supported), then `magit-auto-revert-immediately'
+does not have to be non-nil, because the reverts happen
+immediately anyway.
+
+If `magit-auto-revert-immediately' and `auto-revert-use-notify'
+are both nil, then reverts happen after `auto-revert-interval'
+seconds of user inactivity. That is not desirable."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-auto-revert
+ :type 'boolean)
+
+(defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
+ (if file
+ (--when-let (find-buffer-visiting file)
+ (with-current-buffer it
+ (magit-turn-on-auto-revert-mode-if-desired)))
+ (when (and buffer-file-name
+ (file-readable-p buffer-file-name)
+ (magit-toplevel)
+ (or (not magit-auto-revert-tracked-only)
+ (magit-file-tracked-p buffer-file-name)))
+ (auto-revert-mode))))
+
+;;;###autoload
+(defvar magit-revert-buffers t)
+(make-obsolete-variable 'magit-revert-buffers 'magit-auto-revert-mode
+ "Magit 2.4.0")
+
+;;;###autoload
+(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
+ magit-turn-on-auto-revert-mode-if-desired
+ :package-version '(magit . "2.4.0")
+ :group 'magit
+ :group 'magit-auto-revert
+ ;; When `global-auto-revert-mode' is enabled, then this mode is
+ ;; redundant. When `magit-revert-buffers' is nil, then the user has
+ ;; opted out of the automatic reverts while the old implementation
+ ;; was still in use. In all other cases enable the mode because if
+ ;; buffers are not automatically reverted that would make many very
+ ;; common tasks much more cumbersome.
+ :init-value (and magit-revert-buffers
+ (not global-auto-revert-mode)
+ (not noninteractive)))
+;; - Unfortunately `:init-value t' only sets the value of the mode
+;; variable but does not cause the mode function to be called.
+;; - I don't think it works like this on purpose, but since one usually
+;; should not enable global modes by default, it is understandable.
+;; - If the user has set the variable `magit-auto-revert-mode' to nil
+;; after loading magit (instead of doing so before loading magit or
+;; by using the function), then we should still respect that setting.
+;; - If the user has set the obsolete variable `magit-revert-buffers'
+;; to nil before or after loading magit, then we should still respect
+;; that setting.
+;; - If the user sets one of these variables after loading magit and
+;; after `after-init-hook' has run, then that won't have an effect
+;; and there is nothing we can do about it.
+(defun magit-auto-revert-mode--init-kludge ()
+ "This is an internal kludge to be used on `after-init-hook'.
+Do not use this function elsewhere, and don't remove it from
+the `after-init-hook'. For more information see the comments
+and code surrounding the definition of this function."
+ ;; `magit-revert-buffers' may have been set to nil before the alias
+ ;; had been established, so consult the value of both variables.
+ (if (and magit-auto-revert-mode magit-revert-buffers)
+ (let ((start (current-time)))
+ (magit-message "Turning on magit-auto-revert-mode...")
+ (magit-auto-revert-mode 1)
+ (magit-message
+ "Turning on magit-auto-revert-mode...done%s"
+ (let ((elapsed (float-time (time-subtract (current-time) start))))
+ (if (> elapsed 0.2)
+ (format " (%.3fs, %s buffers checked)" elapsed
+ (length (buffer-list)))
+ ""))))
+ (magit-auto-revert-mode -1)))
+(if after-init-time
+ ;; Since `after-init-hook' has already been
+ ;; run, turn the mode on or off right now.
+ (magit-auto-revert-mode--init-kludge)
+ ;; By the time the init file has been fully loaded the
+ ;; values of the relevant variables might have changed.
+ (add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t))
+
+(put 'magit-auto-revert-mode 'function-documentation
+ "Toggle Magit Auto Revert mode.
+With a prefix argument ARG, enable Magit Auto Revert mode if ARG
+is positive, and disable it otherwise. If called from Lisp,
+enable the mode if ARG is omitted or nil.
+
+Magit Auto Revert mode is a global minor mode that reverts
+buffers associated with a file that is located inside a Git
+repository when the file changes on disk. Use `auto-revert-mode'
+to revert a particular buffer. Or use `global-auto-revert-mode'
+to revert all file-visiting buffers, not just those that visit
+a file located inside a Git repository.
+
+This global mode works by turning on the buffer-local mode
+`auto-revert-mode' at the time a buffer is first created. The
+local mode is turned on if the visited file is being tracked in
+a Git repository at the time when the buffer is created.
+
+If `magit-auto-revert-tracked-only' is non-nil (the default),
+then only tracked files are reverted. But if you stage a
+previously untracked file using `magit-stage', then this mode
+notices that.
+
+Unlike `global-auto-revert-mode', this mode never reverts any
+buffers that are not visiting files.
+
+The behavior of this mode can be customized using the options
+in the `autorevert' and `magit-autorevert' groups.
+
+This function calls the hook `magit-auto-revert-mode-hook'.")
+
+(defun magit-auto-revert-buffers ()
+ (when (and magit-auto-revert-immediately
+ (or global-auto-revert-mode
+ (and magit-auto-revert-mode auto-revert-buffer-list)))
+ (let ((auto-revert-buffer-list-filter
+ (or auto-revert-buffer-list-filter
+ 'magit-auto-revert-repository-buffer-p)))
+ (auto-revert-buffers))))
+
+(defvar magit-auto-revert-toplevel nil)
+
+(when (< emacs-major-version 25)
+ (defvar auto-revert-buffers-counter 1
+ "Incremented each time `auto-revert-buffers' is called"))
+
+(defun magit-auto-revert-buffer-p (buffer)
+ "Return t if BUFFER visits a file inside the current repository.
+The current repository is the one in which `default-directory' is
+located. If there is no current repository, then return t for
+any BUFFER."
+ (magit-auto-revert-repository-buffer-p buffer t))
+
+(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback)
+ "Return t if BUFFER visits a file inside the current repository.
+The current repository is the one in which `default-directory' is
+located. If there is no current repository, then return FALLBACK
+\(which defaults to nil) for any BUFFER."
+ ;; Call `magit-toplevel' just once per cycle.
+ (unless (and magit-auto-revert-toplevel
+ (= (cdr magit-auto-revert-toplevel)
+ auto-revert-buffers-counter))
+ (setq magit-auto-revert-toplevel
+ (cons (or (magit-toplevel) 'no-repo)
+ auto-revert-buffers-counter)))
+ (let ((top (car magit-auto-revert-toplevel)))
+ (if (eq top 'no-repo)
+ fallback
+ (let ((dir (with-current-buffer buffer default-directory)))
+ (and (equal (file-remote-p dir)
+ (file-remote-p top))
+ ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
+ (file-in-directory-p dir top))))))
+
+(defun auto-revert-buffers--buffer-list-filter ()
+ (when (< emacs-major-version 25)
+ (cl-incf auto-revert-buffers-counter))
+ (when auto-revert-buffer-list-filter
+ (setq auto-revert-buffer-list
+ (--filter auto-revert-buffer-list-filter
+ auto-revert-buffer-list))))
+
+(advice-add 'auto-revert-buffers :before
+ 'auto-revert-buffers--buffer-list-filter)
+
+(custom-add-to-group 'magit 'auto-revert-check-vc-info 'custom-variable)
+
+;;; magit-autorevert.el ends soon
+(provide 'magit-autorevert)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-autorevert.el ends here
--- /dev/null
+;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Use a binary search to find the commit that introduced a bug.
+
+;;; Code:
+
+(require 'magit)
+
+(defcustom magit-bisect-show-graph t
+ "Whether to use `--graph' in the log showing commits yet to be bisected."
+ :package-version '(magit . "2.8.0")
+ :group 'magit-status
+ :type 'boolean)
+
+(defface magit-bisect-good
+ '((t :foreground "DarkOliveGreen"))
+ "Face for good bisect revisions."
+ :group 'magit-faces)
+
+(defface magit-bisect-skip
+ '((t :foreground "DarkGoldenrod"))
+ "Face for skipped bisect revisions."
+ :group 'magit-faces)
+
+(defface magit-bisect-bad
+ '((t :foreground "IndianRed4"))
+ "Face for bad bisect revisions."
+ :group 'magit-faces)
+
+;;;###autoload (autoload 'magit-bisect-popup "magit-bisect" nil t)
+(magit-define-popup magit-bisect-popup
+ "Popup console for bisect commands."
+ 'magit-commands
+ :man-page "git-bisect"
+ :actions '((?B "Start" magit-bisect-start)
+ (?s "Start script" magit-bisect-run))
+ :sequence-actions '((?b "Bad" magit-bisect-bad)
+ (?g "Good" magit-bisect-good)
+ (?k "Skip" magit-bisect-skip)
+ (?r "Reset" magit-bisect-reset)
+ (?s "Run script" magit-bisect-run))
+ :sequence-predicate 'magit-bisect-in-progress-p)
+
+;;;###autoload
+(defun magit-bisect-start (bad good)
+ "Start a bisect session.
+
+Bisecting a bug means to find the commit that introduced it.
+This command starts such a bisect session by asking for a know
+good and a bad commit. To move the session forward use the
+other actions from the bisect popup (\
+\\<magit-status-mode-map>\\[magit-bisect-popup])."
+ (interactive (if (magit-bisect-in-progress-p)
+ (user-error "Already bisecting")
+ (magit-bisect-start-read-args)))
+ (magit-git-bisect "start" (list bad good) t))
+
+(defun magit-bisect-start-read-args ()
+ (let ((b (magit-read-branch-or-commit "Start bisect with bad revision")))
+ (list b (magit-read-other-branch-or-commit "Good revision" b))))
+
+;;;###autoload
+(defun magit-bisect-reset ()
+ "After bisecting, cleanup bisection state and return to original `HEAD'."
+ (interactive)
+ (when (magit-confirm 'reset-bisect)
+ (magit-run-git "bisect" "reset")
+ (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT")))))
+
+;;;###autoload
+(defun magit-bisect-good ()
+ "While bisecting, mark the current commit as good.
+Use this after you have asserted that the commit does not contain
+the bug in question."
+ (interactive)
+ (magit-git-bisect "good"))
+
+;;;###autoload
+(defun magit-bisect-bad ()
+ "While bisecting, mark the current commit as bad.
+Use this after you have asserted that the commit does contain the
+bug in question."
+ (interactive)
+ (magit-git-bisect "bad"))
+
+;;;###autoload
+(defun magit-bisect-skip ()
+ "While bisecting, skip the current commit.
+Use this if for some reason the current commit is not a good one
+to test. This command lets Git choose a different one."
+ (interactive)
+ (magit-git-bisect "skip"))
+
+;;;###autoload
+(defun magit-bisect-run (cmdline &optional bad good)
+ "Bisect automatically by running commands after each step.
+
+Unlike `git bisect run' this can be used before bisecting has
+begun. In that case it behaves like `git bisect start; git
+bisect run'."
+ (interactive (let ((args (and (not (magit-bisect-in-progress-p))
+ (magit-bisect-start-read-args))))
+ (cons (read-shell-command "Bisect shell command: ") args)))
+ (when (and bad good)
+ (magit-bisect-start bad good))
+ (magit-git-bisect "run" (list cmdline)))
+
+(defun magit-git-bisect (subcommand &optional args no-assert)
+ (unless (or no-assert (magit-bisect-in-progress-p))
+ (user-error "Not bisecting"))
+ (magit-with-toplevel
+ (magit-run-git-with-logfile
+ (magit-git-dir "BISECT_CMD_OUTPUT") "bisect" subcommand args)))
+
+(defun magit-bisect-in-progress-p ()
+ (file-exists-p (magit-git-dir "BISECT_LOG")))
+
+(defun magit-insert-bisect-output ()
+ "While bisecting, insert section with output from `git bisect'."
+ (when (magit-bisect-in-progress-p)
+ (let* ((lines
+ (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT"))
+ (list "Bisecting: (no saved bisect output)"
+ "It appears you have invoked `git bisect' from a shell."
+ "There is nothing wrong with that, we just cannot display"
+ "anything useful here. Consult the shell output instead.")))
+ (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))))
+ (magit-insert-section ((eval (if bad-line 'commit 'bisect-output))
+ (and bad-line (match-string 1 bad-line)))
+ (magit-insert-heading
+ (propertize (or bad-line (pop lines))
+ 'face 'magit-section-heading))
+ (dolist (line lines)
+ (insert line "\n"))))
+ (insert "\n")))
+
+(defun magit-insert-bisect-rest ()
+ "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-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis)
+ "bisect" "visualize" "git" "log"
+ "--format=%h%d %s" "--decorate=full"
+ (and magit-bisect-show-graph "--graph")))))
+
+(defun magit-insert-bisect-log ()
+ "While bisecting, insert section logging bisect progress."
+ (when (magit-bisect-in-progress-p)
+ (magit-insert-section (bisect-log)
+ (magit-insert-heading "Bisect Log:")
+ (magit-git-wash #'magit-wash-bisect-log "bisect" "log")
+ (insert ?\n))))
+
+(defun magit-wash-bisect-log (_args)
+ (let (beg)
+ (while (progn (setq beg (point-marker))
+ (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t))
+ (magit-bind-match-strings (heading) nil
+ (magit-delete-match)
+ (save-restriction
+ (narrow-to-region beg (point))
+ (goto-char (point-min))
+ (magit-insert-section (bisect-log heading t)
+ (insert (propertize heading 'face 'magit-section-secondary-heading))
+ (magit-insert-heading)
+ (magit-wash-sequence
+ (apply-partially 'magit-log-wash-rev 'bisect-log
+ (magit-abbrev-length)))
+ (insert ?\n)))))
+ (when (re-search-forward
+ "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t)
+ (magit-bind-match-strings (hash) nil
+ (magit-delete-match)
+ (magit-insert-section (bisect-log)
+ (insert hash " is the first bad commit\n"))))))
+
+;;; magit-bisect.el ends soon
+(provide 'magit-bisect)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-bisect.el ends here
--- /dev/null
+;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Annotates each line in file-visiting buffer with information from
+;; the revision which last modified the line.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defgroup magit-blame nil
+ "Blame support for Magit."
+ :group 'magit-extensions)
+
+(defcustom magit-blame-heading-format "%-20a %C %s"
+ "Format string used for blame headings.
+
+The following placeholders are recognized:
+
+ %H hash
+ %s summary
+ %a author
+ %A author time
+ %c committer
+ %C committer time
+
+The author and committer time formats can be specified with
+`magit-blame-time-format'."
+ :group 'magit-blame
+ :type 'string)
+
+(defcustom magit-blame-time-format "%F %H:%M"
+ "Format for time strings in blame headings."
+ :group 'magit-blame
+ :type 'string)
+
+(defcustom magit-blame-show-headings t
+ "Whether to initially show blame block headings.
+The headings can also be toggled locally using command
+`magit-blame-toggle-headings'."
+ :group 'magit-blame
+ :type 'boolean)
+
+(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode)
+ "List of modes not compatible with Magit-Blame mode.
+This modes are turned off when Magit-Blame mode is turned on,
+and then turned on again when turning off the latter."
+ :group 'magit-blame
+ :type '(repeat (symbol :tag "Mode")))
+
+(make-variable-buffer-local 'magit-blame-disabled-modes)
+
+(defcustom magit-blame-mode-lighter " Blame"
+ "The mode-line lighter of the Magit-Blame mode."
+ :group 'magit-blame
+ :type '(choice (const :tag "No lighter" "") string))
+
+(unless (find-lisp-object-file-name 'magit-blame-goto-chunk-hook 'defvar)
+ (add-hook 'magit-blame-goto-chunk-hook 'magit-blame-maybe-update-revision-buffer))
+(defcustom magit-blame-goto-chunk-hook '(magit-blame-maybe-update-revision-buffer)
+ "Hook run by `magit-blame-next-chunk' and `magit-blame-previous-chunk'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-blame
+ :type 'hook
+ :options '(magit-blame-maybe-update-revision-buffer))
+
+(defface magit-blame-heading
+ '((((class color) (background light))
+ :background "grey80"
+ :foreground "black")
+ (((class color) (background dark))
+ :background "grey25"
+ :foreground "white"))
+ "Face for blame headings."
+ :group 'magit-faces)
+
+(defface magit-blame-summary
+ '((t :inherit magit-blame-heading))
+ "Face used for commit summary in blame headings."
+ :group 'magit-faces)
+
+(defface magit-blame-hash
+ '((t :inherit magit-blame-heading))
+ "Face used for commit hash in blame headings."
+ :group 'magit-faces)
+
+(defface magit-blame-name
+ '((t :inherit magit-blame-heading))
+ "Face used for author and committer names in blame headings."
+ :group 'magit-faces)
+
+(defface magit-blame-date
+ '((t :inherit magit-blame-heading))
+ "Face used for dates in blame headings."
+ :group 'magit-faces)
+
+;;; Code
+
+(defvar magit-blame-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\r" 'magit-show-commit)
+ (define-key map "\s" 'magit-diff-show-or-scroll-up)
+ (define-key map "\d" 'magit-diff-show-or-scroll-down)
+ (define-key map "b" 'magit-blame-popup)
+ (define-key map "n" 'magit-blame-next-chunk)
+ (define-key map "N" 'magit-blame-next-chunk-same-commit)
+ (define-key map "p" 'magit-blame-previous-chunk)
+ (define-key map "P" 'magit-blame-previous-chunk-same-commit)
+ (define-key map "q" 'magit-blame-quit)
+ (define-key map "t" 'magit-blame-toggle-headings)
+ (define-key map "\M-w" 'magit-blame-copy-hash)
+ map)
+ "Keymap for `magit-blame-mode'.")
+
+(defun magit-blame-put-keymap-before-view-mode ()
+ "Put `magit-blame-mode' ahead of `view-mode' in `minor-mode-map-alist'."
+ (--when-let (assq 'magit-blame-mode
+ (cl-member 'view-mode minor-mode-map-alist :key #'car))
+ (setq minor-mode-map-alist
+ (cons it (delq it minor-mode-map-alist))))
+ (remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode))
+
+(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)
+
+(defvar-local magit-blame-buffer-read-only nil)
+(defvar-local magit-blame-cache nil)
+(defvar-local magit-blame-process nil)
+(defvar-local magit-blame-recursive-p nil)
+(defvar-local magit-blame-separator nil)
+
+(define-minor-mode magit-blame-mode
+ "Display blame information inline.
+\n\\{magit-blame-mode-map}"
+ :lighter magit-blame-mode-lighter
+ (cond (magit-blame-mode
+ (when (called-interactively-p 'any)
+ (setq magit-blame-mode nil)
+ (user-error
+ (concat "Don't call `magit-blame-mode' directly; "
+ "instead use `magit-blame' or `magit-blame-popup'")))
+ (setq magit-blame-buffer-read-only buffer-read-only)
+ (read-only-mode 1)
+ (dolist (mode magit-blame-disable-modes)
+ (when (and (boundp mode) (symbol-value mode))
+ (funcall mode -1)
+ (push mode magit-blame-disabled-modes)))
+ (setq magit-blame-separator (magit-blame-format-separator)))
+ (t
+ (unless magit-blame-buffer-read-only
+ (read-only-mode -1))
+ (dolist (mode magit-blame-disabled-modes)
+ (funcall mode 1))
+ (when (process-live-p magit-blame-process)
+ (kill-process magit-blame-process))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (dolist (ov (overlays-in (point-min) (point-max)))
+ (when (overlay-get ov 'magit-blame)
+ (delete-overlay ov))))))))
+
+(defun auto-revert-handler--unless-magit-blame-mode ()
+ "If Magit-Blame mode is on, then do nothing. See #1731."
+ magit-blame-mode)
+
+(advice-add 'auto-revert-handler :before-until
+ 'auto-revert-handler--unless-magit-blame-mode)
+
+;;;###autoload (autoload 'magit-blame-popup "magit-blame" nil t)
+(magit-define-popup magit-blame-popup
+ "Popup console for blame commands."
+ 'magit-commands
+ :man-page "git-blame"
+ :switches '((?w "Ignore whitespace" "-w")
+ (?r "Do not treat root commits as boundaries" "--root"))
+ :options '((?M "Detect lines moved or copied within a file" "-M")
+ (?C "Detect lines moved or copied between files" "-C"))
+ :actions '((?b "Blame" magit-blame))
+ :default-arguments '("-w")
+ :default-action 'magit-blame)
+
+;;;###autoload
+(defun magit-blame (revision file &optional args line)
+ "Display edit history of FILE up to REVISION.
+
+Interactively blame the file being visited in the current buffer.
+If the buffer visits a revision of that file, then blame up to
+that revision, otherwise blame the file's full history, including
+uncommitted changes.
+
+If Magit-Blame mode is already turned on then blame recursively, by
+visiting REVISION:FILE (using `magit-find-file'), where revision
+is the revision before the revision that added the lines at
+point.
+
+ARGS is a list of additional arguments to pass to `git blame';
+only arguments available from `magit-blame-popup' should be used.
+\n(fn REVISION FILE &optional ARGS)" ; LINE is for internal use
+ (interactive
+ (let ((args (magit-blame-arguments)))
+ (if magit-blame-mode
+ (--if-let (magit-blame-chunk-get :previous-hash)
+ (list it (magit-blame-chunk-get :previous-file)
+ args (magit-blame-chunk-get :previous-start))
+ (user-error "Block has no further history"))
+ (--if-let (magit-file-relative-name nil 'tracked)
+ (list (or magit-buffer-refname magit-buffer-revision) it args)
+ (if buffer-file-name
+ (user-error "Buffer isn't visiting a tracked file")
+ (user-error "Buffer isn't visiting a file"))))))
+ (let ((toplevel (or (magit-toplevel)
+ (user-error "Not in git repository"))))
+ (let ((default-directory toplevel))
+ (if revision
+ (magit-find-file revision file)
+ (--if-let (find-buffer-visiting file)
+ (progn (switch-to-buffer it)
+ (save-buffer))
+ (find-file file))))
+ (let ((default-directory toplevel))
+ (widen)
+ (when line
+ (setq magit-blame-recursive-p t)
+ (goto-char (point-min))
+ (forward-line (1- line)))
+ (unless magit-blame-mode
+ (setq magit-blame-cache (make-hash-table :test 'equal))
+ (let ((show-headings magit-blame-show-headings))
+ (magit-blame-mode 1)
+ (setq-local magit-blame-show-headings show-headings))
+ (message "Blaming...")
+ (let ((magit-process-popup-time -1)
+ (inhibit-magit-refresh t))
+ (magit-run-git-async
+ "blame" "--incremental" args
+ "-L" (format "%s,%s"
+ (line-number-at-pos (window-start))
+ (line-number-at-pos (1- (window-end nil t))))
+ revision "--" file))
+ (setq magit-blame-process magit-this-process)
+ (set-process-filter magit-this-process 'magit-blame-process-filter)
+ (set-process-sentinel
+ magit-this-process
+ `(lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (magit-process-sentinel process event)
+ (magit-blame-assert-buffer process)
+ (with-current-buffer (process-get process 'command-buf)
+ (when magit-blame-mode
+ (let ((magit-process-popup-time -1)
+ (inhibit-magit-refresh t)
+ (default-directory ,default-directory))
+ (magit-run-git-async "blame" "--incremental" ,@args
+ ,revision "--" ,file))
+ (setq magit-blame-process magit-this-process)
+ (set-process-filter
+ magit-this-process 'magit-blame-process-filter)
+ (set-process-sentinel
+ magit-this-process 'magit-blame-process-sentinel))))))))))
+
+(defun magit-blame-process-sentinel (process event)
+ (let ((status (process-status process)))
+ (when (memq status '(exit signal))
+ (magit-process-sentinel process event)
+ (if (and (eq status 'exit)
+ (zerop (process-exit-status process)))
+ (message "Blaming...done")
+ (magit-blame-assert-buffer process)
+ (with-current-buffer (process-get process 'command-buf)
+ (magit-blame-mode -1))
+ (message "Blaming...failed")))))
+
+(defvar magit-blame-log nil
+ "Whether to log blame output to the process buffer.
+This is intended for debugging purposes.")
+
+(defun magit-blame-process-filter (process string)
+ (when magit-blame-log
+ (magit-process-filter process string))
+ (--when-let (process-get process 'partial-line)
+ (setq string (concat it string))
+ (setf (process-get process 'partial-line) nil))
+ (magit-blame-assert-buffer process)
+ (with-current-buffer (process-get process 'command-buf)
+ (when (and magit-blame-mode
+ (zerop (process-exit-status process)))
+ (let ((chunk (process-get process 'chunk))
+ (lines (split-string string "\n" t)))
+ (unless (string-match-p "\n\\'" string)
+ (process-put process 'chunk chunk)
+ (process-put process 'partial-line (car (last lines)))
+ (setq lines (butlast lines)))
+ (dolist (line lines)
+ (cond
+ ((equal line ""))
+ ((not chunk)
+ (string-match
+ "^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)" line)
+ (setq chunk
+ (list :hash (let ((hash (match-string 1 line)))
+ (unless (equal hash (make-string 40 ?0))
+ hash))
+ :previous-start (string-to-number (match-string 2 line))
+ :start (string-to-number (match-string 3 line))
+ :lines (string-to-number (match-string 4 line)))))
+ ((string-match "^filename \\(.+\\)" line)
+ (let* ((hash (plist-get chunk :hash))
+ (file (match-string 1 line)))
+ (--if-let (gethash hash magit-blame-cache)
+ (setq chunk (nconc chunk it))
+ (plist-put chunk :filename file)
+ (puthash hash chunk magit-blame-cache)))
+ (magit-blame-make-overlay chunk)
+ (setq chunk nil))
+ ((string-match "^previous \\(.\\{40\\}\\) \\(.+\\)" line)
+ (plist-put chunk :previous-hash (match-string 1 line))
+ (plist-put chunk :previous-file (match-string 2 line)))
+ ((string-match "^\\([^ ]+?-mail\\) <\\([^>]+\\)>" line)
+ (plist-put chunk (intern (concat ":" (match-string 1 line)))
+ (string-to-number (match-string 2 line))))
+ ((string-match "^\\([^ ]+?-\\(?:time\\|tz\\)\\) \\(.+\\)" line)
+ (plist-put chunk (intern (concat ":" (match-string 1 line)))
+ (string-to-number (match-string 2 line))))
+ ((string-match "^\\([^ ]+\\) \\(.+\\)" line)
+ (plist-put chunk (intern (concat ":" (match-string 1 line)))
+ (match-string 2 line))))
+ (process-put process 'chunk chunk))))))
+
+(defun magit-blame-assert-buffer (process)
+ (unless (buffer-live-p (process-get process 'command-buf))
+ (kill-process process)
+ (user-error "Buffer being blamed has been killed")))
+
+(defun magit-blame-make-overlay (chunk)
+ (let ((ov (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (forward-line (1- (plist-get chunk :start)))
+ (--when-let (--first (overlay-get it 'magit-blame)
+ (overlays-at (point)))
+ (delete-overlay it))
+ (make-overlay (point)
+ (progn (forward-line
+ (plist-get chunk :lines))
+ (point))))))
+ (heading (magit-blame-format-heading chunk)))
+ (overlay-put ov 'magit-blame chunk)
+ (overlay-put ov 'magit-blame-heading heading)
+ (overlay-put ov 'before-string
+ (if magit-blame-show-headings
+ heading
+ magit-blame-separator))))
+
+(defun magit-blame-format-separator ()
+ (propertize
+ (concat (propertize " " 'display '(space :height (2)))
+ (propertize "\n" 'line-height t))
+ 'face (list :background (face-attribute 'magit-blame-heading :background))))
+
+(defun magit-blame-format-heading (chunk)
+ (with-temp-buffer
+ (insert (format-spec
+ (concat magit-blame-heading-format "\n")
+ `((?H . ,(propertize (or (plist-get chunk :hash) "")
+ 'face 'magit-blame-hash))
+ (?s . ,(propertize (or (plist-get chunk :summary) "")
+ 'face 'magit-blame-summary))
+ (?a . ,(propertize (or (plist-get chunk :author) "")
+ 'face 'magit-blame-name))
+ (?A . ,(propertize (magit-blame-format-time-string
+ magit-blame-time-format
+ (plist-get chunk :author-time)
+ (plist-get chunk :author-tz))
+ 'face 'magit-blame-date))
+ (?c . ,(propertize (or (plist-get chunk :committer) "")
+ 'face 'magit-blame-name))
+ (?C . ,(propertize (magit-blame-format-time-string
+ magit-blame-time-format
+ (plist-get chunk :committer-time)
+ (plist-get chunk :committer-tz))
+ 'face 'magit-blame-date)))))
+ (goto-char (point-min))
+ (while (not (eobp))
+ (let ((face (get-text-property (point) 'face))
+ (next (or (next-single-property-change (point) 'face)
+ (point-max))))
+ (unless face
+ (put-text-property (point) next 'face 'magit-blame-heading))
+ (goto-char next)))
+ (buffer-string)))
+
+(defun magit-blame-format-time-string (format time tz)
+ (format-time-string
+ format (seconds-to-time (+ time (* (/ tz 100) 60 60) (* (% tz 100) 60)))))
+
+(defun magit-blame-quit ()
+ "Turn off Magit-Blame mode.
+If the buffer was created during a recursive blame,
+then also kill the buffer."
+ (interactive)
+ (if magit-blame-recursive-p
+ (kill-buffer)
+ (magit-blame-mode -1)))
+
+(defun magit-blame-next-chunk ()
+ "Move to the next chunk."
+ (interactive)
+ (--if-let (next-single-char-property-change (point) 'magit-blame)
+ (progn (goto-char it)
+ (run-hooks 'magit-blame-goto-chunk-hook))
+ (user-error "No more chunks")))
+
+(defun magit-blame-previous-chunk ()
+ "Move to the previous chunk."
+ (interactive)
+ (--if-let (previous-single-char-property-change (point) 'magit-blame)
+ (progn (goto-char it)
+ (run-hooks 'magit-blame-goto-chunk-hook))
+ (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)"
+ (interactive)
+ (-if-let (hash (magit-blame-chunk-get :hash))
+ (let ((pos (point)) ov)
+ (save-excursion
+ (while (and (not ov)
+ (not (= pos (if previous (point-min) (point-max))))
+ (setq pos (funcall
+ (if previous
+ 'previous-single-char-property-change
+ 'next-single-char-property-change)
+ pos 'magit-blame)))
+ (--when-let (magit-blame-overlay-at pos)
+ (when (equal (magit-blame-chunk-get :hash pos) hash)
+ (setq ov it)))))
+ (if ov
+ (goto-char (overlay-start ov))
+ (user-error "No more chunks from same commit")))
+ (user-error "This chunk hasn't been blamed yet")))
+
+(defun magit-blame-previous-chunk-same-commit ()
+ "Move to the previous chunk from the same commit."
+ (interactive)
+ (magit-blame-next-chunk-same-commit 'previous-single-char-property-change))
+
+(defun magit-blame-toggle-headings ()
+ "Show or hide blame chunk headings."
+ (interactive)
+ (setq-local magit-blame-show-headings (not magit-blame-show-headings))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (let ((next (next-single-char-property-change (point) 'magit-blame)))
+ (--when-let (magit-blame-overlay-at (point))
+ (overlay-put it 'before-string
+ (if magit-blame-show-headings
+ (overlay-get it 'magit-blame-heading)
+ magit-blame-separator)))
+ (goto-char (or next (point-max))))))))
+
+(defun magit-blame-copy-hash ()
+ "Save hash of the current chunk's commit to the kill ring.
+
+When the region is active, then save that to the `kill-ring',
+like `kill-ring-save' would."
+ (interactive)
+ (if (use-region-p)
+ (copy-region-as-kill nil nil 'region)
+ (kill-new (message "%s" (magit-blame-chunk-get :hash)))))
+
+(defun magit-blame-chunk-get (key &optional pos)
+ (--when-let (magit-blame-overlay-at pos)
+ (plist-get (overlay-get it 'magit-blame) key)))
+
+(defun magit-blame-overlay-at (&optional pos)
+ (--first (overlay-get it 'magit-blame)
+ (overlays-at (or pos (point)))))
+
+(defun magit-blame-maybe-update-revision-buffer ()
+ (unless magit--update-revision-buffer
+ (setq magit--update-revision-buffer nil)
+ (-when-let* ((commit (magit-blame-chunk-get :hash))
+ (buffer (magit-mode-get-buffer 'magit-revision-mode nil t)))
+ (setq magit--update-revision-buffer (list commit buffer))
+ (run-with-idle-timer
+ magit-update-other-window-delay nil
+ (lambda ()
+ (-let [(rev buf) magit--update-revision-buffer]
+ (setq magit--update-revision-buffer nil)
+ (when (buffer-live-p buf)
+ (let ((magit-display-buffer-noselect t))
+ (apply #'magit-show-commit rev (magit-diff-arguments))))))))))
+
+;;; magit-blame.el ends soon
+(provide 'magit-blame)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-blame.el ends here
--- /dev/null
+;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements commands for creating Git commits. These
+;; commands just initiate the commit, support for writing the commit
+;; messages is implemented in `git-commit.el'.
+
+;;; Code:
+
+(require 'magit)
+(require 'magit-sequence)
+
+(eval-when-compile (require 'epa)) ; for `epa-protocol'
+(eval-when-compile (require 'epg))
+(declare-function epg-sub-key-id 'epg)
+(declare-function epg-key-sub-key-list 'epg)
+(declare-function epg-key-user-id-list 'epg)
+(declare-function epg-user-id-string 'epg)
+(declare-function epg-decode-dn 'epg)
+(declare-function epg-list-keys 'epg)
+
+;;; Options
+
+(defcustom magit-commit-arguments nil
+ "The arguments used when committing."
+ :group 'magit-commands
+ :type '(repeat (string :tag "Argument")))
+
+(defcustom magit-commit-ask-to-stage 'verbose
+ "Whether to ask to stage everything when committing and nothing is staged."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "Ask showing diff" verbose)
+ (const :tag "Ask" t)
+ (const :tag "Don't ask" nil)))
+
+(defcustom magit-commit-show-diff t
+ "Whether the relevant diff is automatically shown when committing."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-commit-extend-override-date t
+ "Whether using `magit-commit-extend' changes the committer date."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-commit-reword-override-date t
+ "Whether using `magit-commit-reword' changes the committer date."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-commit-squash-confirm t
+ "Whether the commit targeted by squash and fixup has to be confirmed.
+When non-nil then the commit at point (if any) is used as default
+choice, otherwise it has to be confirmed. This option only
+affects `magit-commit-squash' and `magit-commit-fixup'. The
+\"instant\" variants always require confirmation because making
+an error while using those is harder to recover from."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+;;; Code
+
+(defun magit-commit-popup (&optional arg)
+ "Popup console for commit commands."
+ (interactive "P")
+ (--if-let (magit-commit-message-buffer)
+ (switch-to-buffer it)
+ (magit-invoke-popup 'magit-commit-popup nil arg)))
+
+(defvar magit-commit-popup
+ '(:variable magit-commit-arguments
+ :man-page "git-commit"
+ :switches ((?a "Stage all modified and deleted files" "--all")
+ (?e "Allow empty commit" "--allow-empty")
+ (?v "Show diff of changes to be committed" "--verbose")
+ (?n "Bypass git hooks" "--no-verify")
+ (?s "Add Signed-off-by line" "--signoff")
+ (?R "Claim authorship and reset author date" "--reset-author"))
+ :options ((?A "Override the author" "--author=")
+ (?S "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key)
+ (?C "Reuse commit message" "--reuse-message="))
+ :actions ((?c "Commit" magit-commit)
+ (?e "Extend" magit-commit-extend)
+ (?f "Fixup" magit-commit-fixup)
+ (?F "Instant Fixup" magit-commit-instant-fixup) nil
+ (?w "Reword" magit-commit-reword)
+ (?s "Squash" magit-commit-squash)
+ (?S "Instant Squash" magit-commit-instant-squash) nil
+ (?a "Amend" magit-commit-amend)
+ (?A "Augment" magit-commit-augment))
+ :max-action-columns 4
+ :default-action magit-commit))
+
+(magit-define-popup-keys-deferred 'magit-commit-popup)
+
+(defun magit-commit-arguments nil
+ (if (eq magit-current-popup 'magit-commit-popup)
+ magit-current-popup-args
+ magit-commit-arguments))
+
+(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)))))
+
+;;;###autoload
+(defun magit-commit (&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))))
+ (when (setq args (magit-commit-assert args))
+ (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-run-git-with-editor "commit" "--amend" args))
+
+;;;###autoload
+(defun magit-commit-extend (&optional args override-date)
+ "Amend the last commit, without editing the 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)"
+ (interactive (list (magit-commit-arguments)
+ (if current-prefix-arg
+ (not magit-commit-extend-override-date)
+ magit-commit-extend-override-date)))
+ (when (setq args (magit-commit-assert args (not override-date)))
+ (let ((process-environment process-environment))
+ (unless override-date
+ (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
+ (magit-run-git-with-editor "commit" "--amend" "--no-edit" args))))
+
+;;;###autoload
+(defun magit-commit-reword (&optional args override-date)
+ "Reword the last commit, ignoring staged changes.
+
+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)"
+ (interactive (list (magit-commit-arguments)
+ (if current-prefix-arg
+ (not magit-commit-reword-override-date)
+ magit-commit-reword-override-date)))
+ (let ((process-environment process-environment))
+ (unless override-date
+ (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
+ (magit-run-git-with-editor "commit" "--amend" "--only" args)))
+
+;;;###autoload
+(defun magit-commit-fixup (&optional commit args)
+ "Create a fixup commit.
+
+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'."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--fixup" commit args))
+
+;;;###autoload
+(defun magit-commit-squash (&optional commit args)
+ "Create a squash commit, without editing the squash 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'."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--squash" commit args))
+
+;;;###autoload
+(defun magit-commit-augment (&optional commit args)
+ "Create a squash commit, editing the squash 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'."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--squash" commit args nil t))
+
+;;;###autoload
+(defun magit-commit-instant-fixup (&optional commit args)
+ "Create a fixup commit targeting COMMIT and instantly rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--fixup" commit args t))
+
+;;;###autoload
+(defun magit-commit-instant-squash (&optional commit args)
+ "Create a squash commit targeting COMMIT and instantly rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--squash" commit args t))
+
+(defun magit-commit-squash-internal
+ (option commit &optional args rebase edit confirmed)
+ (-when-let (args (magit-commit-assert args t))
+ (if (and commit
+ (or confirmed
+ (not (or rebase
+ current-prefix-arg
+ magit-commit-squash-confirm))))
+ (let ((magit-commit-show-diff nil))
+ (push (concat option "=" commit) args)
+ (unless edit
+ (push "--no-edit" args))
+ (if rebase
+ (magit-with-editor
+ (magit-call-git
+ "commit" (-remove-first
+ (apply-partially #'string-match-p "\\`--gpg-sign=")
+ args)))
+ (magit-run-git-with-editor "commit" args)))
+ (magit-log-select
+ `(lambda (commit)
+ (magit-commit-squash-internal ,option commit ',args ,rebase ,edit t)
+ ,@(when rebase
+ `((magit-rebase-interactive-1 commit
+ (list "--autosquash" "--autostash")
+ "" "true"))))
+ (format "Type %%p on a commit to %s into it,"
+ (substring option 2)))
+ (when magit-commit-show-diff
+ (let ((magit-display-buffer-noselect t))
+ (apply #'magit-diff-staged nil (magit-diff-arguments)))))))
+
+(defun magit-commit-assert (args &optional strict)
+ (cond
+ ((or (magit-anything-staged-p)
+ (and (magit-anything-unstaged-p)
+ ;; ^ Everything of nothing is still nothing.
+ (member "--all" args))
+ (and (not strict)
+ ;; ^ For amend variants that don't make sense otherwise.
+ (or (member "--amend" args)
+ (member "--allow-empty" args))))
+ (or args (list "--")))
+ ((and (magit-rebase-in-progress-p)
+ (not (magit-anything-unstaged-p))
+ (y-or-n-p "Nothing staged. Continue in-progress rebase? "))
+ (magit-run-git-sequencer "rebase" "--continue")
+ nil)
+ ((and (file-exists-p (magit-git-dir "MERGE_MSG"))
+ (not (magit-anything-unstaged-p)))
+ (or args (list "--")))
+ ((not (magit-anything-unstaged-p))
+ (user-error "Nothing staged (or unstaged)"))
+ (magit-commit-ask-to-stage
+ (when (eq magit-commit-ask-to-stage 'verbose)
+ (magit-diff-unstaged))
+ (prog1 (when (y-or-n-p "Nothing staged. Stage and commit everything? ")
+ (magit-run-git "add" "-u" ".")
+ (or args (list "--")))
+ (when (and (eq magit-commit-ask-to-stage 'verbose)
+ (derived-mode-p 'magit-diff-mode))
+ (magit-mode-bury-buffer))))
+ (t
+ (user-error "Nothing staged"))))
+
+(defun magit-commit-diff ()
+ (-when-let (fn (and git-commit-mode
+ magit-commit-show-diff
+ (pcase last-command
+ (`magit-commit
+ (apply-partially 'magit-diff-staged nil))
+ (`magit-commit-amend 'magit-diff-while-amending)
+ (`magit-commit-reword 'magit-diff-while-amending))))
+ (-when-let (diff-buffer (magit-mode-get-buffer 'magit-diff-mode))
+ ;; This window just started displaying the commit message
+ ;; buffer. Without this that buffer would immediately be
+ ;; replaced with the diff buffer. See #2632.
+ (unrecord-window-buffer nil diff-buffer))
+ (condition-case nil
+ (let ((magit-inhibit-save-previous-winconf 'unset)
+ (magit-display-buffer-noselect t)
+ (inhibit-quit nil))
+ (message "Diffing changes to be committed (C-g to abort diffing)")
+ (funcall fn (car (magit-diff-arguments))))
+ (quit))))
+
+;; Mention `magit-diff-while-committing' because that's
+;; always what I search for when I try to find this line.
+(add-hook 'server-switch-hook 'magit-commit-diff)
+
+(add-to-list 'with-editor-server-window-alist
+ (cons git-commit-filename-regexp 'switch-to-buffer))
+
+(defvar magit-gpg-secret-key-hist nil)
+
+(defun magit-read-gpg-secret-key (prompt &optional _initial-input)
+ (require 'epa)
+ (let ((keys (--map (concat (epg-sub-key-id (car (epg-key-sub-key-list it)))
+ " "
+ (-when-let (id-obj (car (epg-key-user-id-list it)))
+ (let ((id-str (epg-user-id-string id-obj)))
+ (if (stringp id-str)
+ id-str
+ (epg-decode-dn id-obj)))))
+ (epg-list-keys (epg-make-context epa-protocol) nil t))))
+ (car (split-string (magit-completing-read
+ prompt keys nil nil nil 'magit-gpg-secret-key-hist
+ (car (or magit-gpg-secret-key-hist keys)))
+ " "))))
+
+(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert
+ "Used by `magit-commit-add-log' to insert a single entry.")
+
+(defun magit-commit-add-log ()
+ "Add a stub for the current change into the commit message buffer.
+If no commit is in progress, then initiate it. Use the function
+specified by variable `magit-commit-add-log-insert-function' to
+actually insert the entry."
+ (interactive)
+ (let ((hunk (magit-section-when 'hunk it))
+ (log (magit-commit-message-buffer)) buf pos)
+ (save-window-excursion
+ (call-interactively #'magit-diff-visit-file)
+ (setq buf (current-buffer)
+ pos (point)))
+ (unless log
+ (unless (magit-commit-assert nil)
+ (user-error "Abort"))
+ (magit-commit)
+ (while (not (setq log (magit-commit-message-buffer)))
+ (sit-for 0.01)))
+ (save-excursion
+ (with-current-buffer buf
+ (goto-char pos)
+ (funcall magit-commit-add-log-insert-function log
+ (magit-file-relative-name)
+ (and hunk (add-log-current-defun)))))))
+
+(defun magit-commit-add-log-insert (buffer file defun)
+ (with-current-buffer buffer
+ (undo-boundary)
+ (goto-char (point-max))
+ (while (re-search-backward (concat "^" comment-start) nil t))
+ (cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file)
+ nil t)
+ (when (equal (match-string 1) defun)
+ (setq defun nil))
+ (re-search-forward ": "))
+ (t
+ (when (re-search-backward "^[\\*(].+\n" nil t)
+ (goto-char (match-end 0)))
+ (while (re-search-forward "^[^\\*#\n].*\n" nil t))
+ (if defun
+ (progn (insert (format "* %s (%s): \n" file defun))
+ (setq defun nil))
+ (insert (format "* %s: \n" file)))
+ (backward-char)
+ (unless (looking-at "\n[\n\\']")
+ (insert ?\n)
+ (backward-char))))
+ (when defun
+ (forward-line)
+ (let ((limit (save-excursion
+ (and (re-search-forward "^\\*" nil t)
+ (point)))))
+ (unless (or (looking-back (format "(%s): " defun)
+ (line-beginning-position))
+ (re-search-forward (format "^(%s): " defun) limit t))
+ (while (re-search-forward "^[^\\*#\n].*\n" limit t))
+ (insert (format "(%s): \n" defun))
+ (backward-char))))))
+
+;;; magit-commit.el ends soon
+(provide 'magit-commit)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-commit.el ends here
--- /dev/null
+;;; magit-core.el --- core functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library requires several other libraries, so that yet other
+;; libraries can just require this one, instead of having to require
+;; all the other ones. In other words this separates the low-level
+;; stuff from the rest. It also defines some Custom groups.
+
+;;; Code:
+
+(require 'magit-utils)
+(require 'magit-section)
+(require 'magit-git)
+(require 'magit-mode)
+(require 'magit-popup)
+(require 'magit-process)
+(require 'magit-autorevert)
+
+(defgroup magit nil
+ "Controlling Git from Emacs."
+ :group 'tools)
+
+(defgroup magit-commands nil
+ "Options controlling behavior of certain commands."
+ :group 'magit)
+
+(defgroup magit-modes nil
+ "Modes used or provided by Magit."
+ :group 'magit)
+
+(defgroup magit-extensions nil
+ "Extensions to Magit."
+ :group 'magit)
+
+(defgroup magit-faces nil
+ "Faces used by Magit."
+ :group 'magit
+ :group 'faces)
+
+(custom-add-to-group 'magit-modes 'magit-popup 'custom-group)
+(custom-add-to-group 'magit-faces 'magit-popup-faces 'custom-group)
+(custom-add-to-group 'magit-modes 'git-commit 'custom-group)
+(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group)
+(custom-add-to-group 'magit-modes 'git-rebase 'custom-group)
+(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group)
+(custom-add-to-group 'magit-process 'with-editor 'custom-group)
+
+(custom-add-to-group 'magit 'vc-follow-symlinks 'custom-variable)
+
+;;; magit-core.el ends soon
+(provide 'magit-core)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-core.el ends here
--- /dev/null
+;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for looking at Git diffs and
+;; commits.
+
+;;; Code:
+
+(require 'git-commit)
+(require 'magit-core)
+
+;; For `magit-diff-popup'
+(declare-function magit-stash-show 'magit-stash)
+;; For `magit-diff-visit-file'
+(declare-function dired-jump 'dired-x)
+(declare-function magit-find-file-noselect 'magit)
+(declare-function magit-status-internal 'magit)
+;; For `magit-diff-while-committing'
+(declare-function magit-commit-message-buffer 'magit)
+;; For `magit-insert-revision-gravatar'
+(defvar gravatar-size)
+;; For `magit-show-commit' and `magit-diff-show-or-scroll'
+(declare-function magit-blame-chunk-get 'magit-blame)
+(declare-function magit-blame-mode 'magit-blame)
+(defvar magit-blame-mode)
+(defvar git-rebase-line)
+
+(require 'diff-mode)
+(require 'smerge-mode)
+
+;;; Options
+;;;; Diff Mode
+
+(defgroup magit-diff nil
+ "Inspect and manipulate Git diffs."
+ :group 'magit-modes)
+
+(custom-add-to-group 'magit-diff 'smerge-refine-ignore-whitespace
+ 'custom-variable)
+
+(defcustom magit-diff-mode-hook nil
+ "Hook run after entering Magit-Diff mode."
+ :group 'magit-diff
+ :type 'hook)
+
+(defcustom magit-diff-sections-hook
+ '(magit-insert-diff
+ magit-insert-xref-buttons)
+ "Hook run to insert sections into a `magit-diff-mode' buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type 'hook)
+
+(defcustom magit-diff-expansion-threshold 1.0
+ "After how many seconds not to expand anymore diffs.
+
+Except in status buffers, diffs are usually start out fully
+expanded. Because that can take a long time, all diffs that
+haven't been fontified during a refresh before the threshold
+defined here are instead displayed with their bodies collapsed.
+
+Note that this can cause sections that were previously expanded
+to be collapsed. So you should not pick a very low value here.
+
+The hook function `magit-diff-expansion-threshold' has to be a
+member of `magit-section-set-visibility-hook' for this option
+to have any effect"
+ :package-version '(magit . "2.1.0")
+ :group 'magit-diff
+ :type 'float)
+
+(defcustom magit-diff-highlight-hunk-body t
+ "Whether to highlight bodies of selected hunk sections.
+This only has an effect if `magit-diff-highlight' is a
+member of `magit-section-highlight-hook', which see."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-show-lines-boundary t
+ "This option is obsolete.
+If you have set this to nil, then remove that customization, and
+instead customize `magit-diff-highlight-hunk-region-functions'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-highlight-hunk-region-functions
+ '(magit-diff-highlight-hunk-region-dim-outside
+ magit-diff-highlight-hunk-region-using-overlays)
+ "The functions used to highlight the hunk-internal region.
+
+`magit-diff-highlight-hunk-region-dim-outside' overlays the outside
+of the hunk internal selection with a face that causes the added and
+removed lines to have the same background color as context lines.
+This function should not be removed from the value of this option.
+
+`magit-diff-highlight-hunk-region-using-overlays' and
+`magit-diff-highlight-hunk-region-using-underline' emphasize the
+region by placing delimiting horizonal lines before and after it.
+Both of these functions have glitches which cannot be fixed due
+to limitations of Emacs' display engine. For more information
+see https://github.com/magit/magit/issues/2758 ff.
+
+Instead of, or in addition to, using delimiting horizontal lines,
+to emphasize the boundaries, you may which to emphasize the text
+itself, using `magit-diff-highlight-hunk-region-using-face'.
+
+In terminal frames it's not possible to draw lines as the overlay
+and underline variants normally do, so there they fall back to
+calling the face function instead."
+ :package-version '(magit . "2.9.0")
+ :set-after '(magit-diff-show-lines-boundaries)
+ :group 'magit-diff
+ :type 'hook
+ :options '(magit-diff-highlight-hunk-region-dim-outside
+ magit-diff-highlight-hunk-region-using-underline
+ magit-diff-highlight-hunk-region-using-overlays
+ magit-diff-highlight-hunk-region-using-face))
+
+(defcustom magit-diff-unmarked-lines-keep-foreground t
+ "Whether `magit-diff-highlight-hunk-region-dim-outside' preserves foreground.
+When this is set to nil, then that function only adjusts the
+foreground color but added and removed lines outside the region
+keep their distinct foreground colors."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-refine-hunk nil
+ "Whether to show word-granularity differences within diff hunks.
+
+nil never show fine differences.
+t show fine differences for the current diff hunk only.
+`all' show fine differences for all displayed diff hunks."
+ :group 'magit-diff
+ :safe (lambda (val) (memq val '(nil t all)))
+ :type '(choice (const :tag "Never" nil)
+ (const :tag "Current" t)
+ (const :tag "All" all)))
+
+(put 'magit-diff-refine-hunk 'permanent-local t)
+
+(defcustom magit-diff-paint-whitespace t
+ "Specify where to highlight whitespace errors.
+See `magit-highlight-trailing-whitespace',
+`magit-highlight-indentation'. The symbol t means in all diffs,
+`status' means only in the status buffer, and nil means nowhere."
+ :group 'magit-diff
+ :safe (lambda (val) (memq val '(t nil status)))
+ :type '(choice (const :tag "Always" t)
+ (const :tag "Never" nil)
+ (const :tag "In status buffer" status)))
+
+(defcustom magit-diff-highlight-trailing t
+ "Whether to highlight whitespace at the end of a line in diffs.
+Used only when `magit-diff-paint-whitespace' is non-nil."
+ :group 'magit-diff
+ :safe 'booleanp
+ :type 'boolean)
+
+(defcustom magit-diff-highlight-indentation nil
+ "Highlight the \"wrong\" indentation style.
+Used only when `magit-diff-paint-whitespace' is non-nil.
+
+The value is a list of cons cells. The car is a regular
+expression, and the cdr is the value that applies to repositories
+whose directory matches the regular expression. If more than one
+element matches, then the *last* element in the list applies.
+The default value should therefore come first in the list.
+
+If the value is `tabs', highlight indentation with tabs. If the
+value is an integer, highlight indentation with at least that
+many spaces. Otherwise, highlight neither."
+ :group 'magit-diff
+ :type `(repeat (cons (string :tag "Directory regexp")
+ (choice (const :tag "Tabs" tabs)
+ (integer :tag "Spaces" :value ,tab-width)
+ (const :tag "Neither" nil)))))
+
+(defcustom magit-diff-hide-trailing-cr-characters
+ (and (memq system-type '(ms-dos windows-nt)) t)
+ "Whether to hide ^M characters at the end of a line in diffs."
+ :package-version '(magit . "2.6.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-visit-previous-blob t
+ "Whether `magit-diff-visit-file' may visit the previous blob.
+
+When this is t and point is on a removed line in a diff for a
+committed change, then `magit-diff-visit-file' visits the blob
+from the last revision which still had that line.
+
+Currently this is only supported for committed changes, for
+staged and unstaged changes `magit-diff-visit-file' always
+visits the file in the working tree."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+;;;; File Diff
+
+(defcustom magit-diff-buffer-file-locked t
+ "Whether `magit-diff-buffer-file' uses a decicated buffer."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :group 'magit-diff
+ :type 'boolean)
+
+;;;; Revision Mode
+
+(defgroup magit-revision nil
+ "Inspect and manipulate Git commits."
+ :group 'magit-modes)
+
+(defcustom magit-revision-mode-hook nil
+ "Hook run after entering Magit-Revision mode."
+ :group 'magit-revision
+ :type 'hook)
+
+(defcustom magit-revision-sections-hook
+ '(magit-insert-revision-tag
+ magit-insert-revision-headers
+ magit-insert-revision-message
+ magit-insert-revision-notes
+ magit-insert-revision-diff
+ magit-insert-xref-buttons)
+ "Hook run to insert sections into a `magit-revision-mode' buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type 'hook)
+
+(defcustom magit-revision-headers-format "\
+Author: %aN <%aE>
+AuthorDate: %ad
+Commit: %cN <%cE>
+CommitDate: %cd
+"
+ "Format string used to insert headers in revision buffers.
+
+All headers in revision buffers are inserted by the section
+inserter `magit-insert-revision-headers'. Some of the headers
+are created by calling `git show --format=FORMAT' where FORMAT
+is the format specified here. Other headers are hard coded or
+subject to option `magit-revision-insert-related-refs'."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type 'string)
+
+(defcustom magit-revision-insert-related-refs t
+ "Whether to show related refs in revision buffers."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-revision
+ :type 'boolean)
+
+(defcustom magit-revision-show-gravatars nil
+ "Whether to show gravatar images in revision buffers.
+
+If non-nil, then the value has to be a cons-cell which specifies
+where the gravatar images for the author and/or the committer are
+inserted inside the text that was previously inserted according
+to `magit-revision-header-format'.
+
+Both cells are regular expressions. The car specifies where to
+insert the author gravatar image. The top halve of the image is
+inserted right after the matched text, the bottom halve on the
+next line at the same offset. The cdr specifies where to insert
+the committer image, accordingly. Either the car or the cdr may
+be nil."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type '(choice (const :tag "Don't show gravatars" nil)
+ (cons :tag "Show gravatars"
+ (regexp :tag "Author regexp" "^Author: ")
+ (regexp :tag "Committer regexp" "^Commit: "))))
+
+(defcustom magit-revision-use-gravatar-kludge nil
+ "Whether to work around a bug which affects display of gravatars.
+
+Gravatar images are spliced into two halves which are then
+displayed on separate lines. On OS X the splicing has a bug in
+some Emacs builds, which causes the top and bottom halves to be
+interchanged. Enabling this option works around this issue by
+interchanging the halves once more, which cancels out the effect
+of the bug.
+
+See https://github.com/magit/magit/issues/2265
+and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type 'boolean)
+
+;;; Faces
+
+(defface magit-diff-file-heading
+ '((t :weight bold))
+ "Face for diff file headings."
+ :group 'magit-faces)
+
+(defface magit-diff-file-heading-highlight
+ '((t :inherit (magit-section-highlight)))
+ "Face for current diff file headings."
+ :group 'magit-faces)
+
+(defface magit-diff-file-heading-selection
+ '((((class color) (background light))
+ :inherit magit-diff-file-heading-highlight
+ :foreground "salmon4")
+ (((class color) (background dark))
+ :inherit magit-diff-file-heading-highlight
+ :foreground "LightSalmon3"))
+ "Face for selected diff file headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-heading
+ '((((class color) (background light))
+ :background "grey80"
+ :foreground "grey30")
+ (((class color) (background dark))
+ :background "grey25"
+ :foreground "grey70"))
+ "Face for diff hunk headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-heading-highlight
+ '((((class color) (background light))
+ :background "grey75"
+ :foreground "grey30")
+ (((class color) (background dark))
+ :background "grey35"
+ :foreground "grey70"))
+ "Face for current diff hunk headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-heading-selection
+ '((((class color) (background light))
+ :inherit magit-diff-hunk-heading-highlight
+ :foreground "salmon4")
+ (((class color) (background dark))
+ :inherit magit-diff-hunk-heading-highlight
+ :foreground "LightSalmon3"))
+ "Face for selected diff hunk headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-region
+ '((t :inherit bold))
+ "Face used by `magit-diff-highlight-hunk-region-using-face'.
+
+This face is overlayed over text that uses other hunk faces,
+and those normally set the foreground and background colors.
+The `:foreground' and especially the `:background' properties
+should be avoided here. Setting the latter would cause the
+lose of information. Good properties to set here are `:weight'
+and `:slant'."
+ :group 'magit-faces)
+
+(defface magit-diff-lines-heading
+ '((((class color) (background light))
+ :inherit magit-diff-hunk-heading-highlight
+ :background "LightSalmon3")
+ (((class color) (background dark))
+ :inherit magit-diff-hunk-heading-highlight
+ :foreground "grey80"
+ :background "salmon4"))
+ "Face for diff hunk heading when lines are marked."
+ :group 'magit-faces)
+
+(defface magit-diff-lines-boundary
+ '((t :inherit magit-diff-lines-heading))
+ "Face for boundary of marked lines in diff hunk."
+ :group 'magit-faces)
+
+(defface magit-diff-conflict-heading
+ '((t :inherit magit-diff-hunk-heading))
+ "Face for conflict markers."
+ :group 'magit-faces)
+
+(defface magit-diff-added
+ '((((class color) (background light))
+ :background "#ddffdd"
+ :foreground "#22aa22")
+ (((class color) (background dark))
+ :background "#335533"
+ :foreground "#ddffdd"))
+ "Face for lines in a diff that have been added."
+ :group 'magit-faces)
+
+(defface magit-diff-removed
+ '((((class color) (background light))
+ :background "#ffdddd"
+ :foreground "#aa2222")
+ (((class color) (background dark))
+ :background "#553333"
+ :foreground "#ffdddd"))
+ "Face for lines in a diff that have been removed."
+ :group 'magit-faces)
+
+(defface magit-diff-our
+ '((t :inherit magit-diff-removed))
+ "Face for lines in a diff for our side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-base
+ '((((class color) (background light))
+ :background "#ffffcc"
+ :foreground "#aaaa11")
+ (((class color) (background dark))
+ :background "#555522"
+ :foreground "#ffffcc"))
+ "Face for lines in a diff for the base side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-their
+ '((t :inherit magit-diff-added))
+ "Face for lines in a diff for their side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-context
+ '((((class color) (background light)) :foreground "grey50")
+ (((class color) (background dark)) :foreground "grey70"))
+ "Face for lines in a diff that are unchanged."
+ :group 'magit-faces)
+
+(defface magit-diff-added-highlight
+ '((((class color) (background light))
+ :background "#cceecc"
+ :foreground "#22aa22")
+ (((class color) (background dark))
+ :background "#336633"
+ :foreground "#cceecc"))
+ "Face for lines in a diff that have been added."
+ :group 'magit-faces)
+
+(defface magit-diff-removed-highlight
+ '((((class color) (background light))
+ :background "#eecccc"
+ :foreground "#aa2222")
+ (((class color) (background dark))
+ :background "#663333"
+ :foreground "#eecccc"))
+ "Face for lines in a diff that have been removed."
+ :group 'magit-faces)
+
+(defface magit-diff-our-highlight
+ '((t :inherit magit-diff-removed-highlight))
+ "Face for lines in a diff for our side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-base-highlight
+ '((((class color) (background light))
+ :background "#eeeebb"
+ :foreground "#aaaa11")
+ (((class color) (background dark))
+ :background "#666622"
+ :foreground "#eeeebb"))
+ "Face for lines in a diff for the base side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-their-highlight
+ '((t :inherit magit-diff-added-highlight))
+ "Face for lines in a diff for their side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-context-highlight
+ '((((class color) (background light))
+ :background "grey95"
+ :foreground "grey50")
+ (((class color) (background dark))
+ :background "grey20"
+ :foreground "grey70"))
+ "Face for lines in a diff that have been removed."
+ :group 'magit-faces)
+
+(defface magit-diff-whitespace-warning
+ '((t :inherit trailing-whitespace))
+ "Face for highlighting whitespace errors added lines."
+ :group 'magit-faces)
+
+(defface magit-diffstat-added
+ '((((class color) (background light)) :foreground "#22aa22")
+ (((class color) (background dark)) :foreground "#448844"))
+ "Face for plus sign in diffstat."
+ :group 'magit-faces)
+
+(defface magit-diffstat-removed
+ '((((class color) (background light)) :foreground "#aa2222")
+ (((class color) (background dark)) :foreground "#aa4444"))
+ "Face for minus sign in diffstat."
+ :group 'magit-faces)
+
+;;; Commands
+;;;; Diff popups
+
+(defconst magit-diff-popup-common
+ '(:variable magit-diff-arguments
+ :man-page "git-diff"
+ :options ((?f "Limit to files" "-- " magit-read-files)
+ (?u "Context lines" "-U")
+ (?m "Detect renames" "-M")
+ (?c "Detect copies" "-C")
+ (?a "Diff algorithm" "--diff-algorithm="
+ magit-diff-select-algorithm))))
+
+(defvar magit-diff-popup
+ `(,@magit-diff-popup-common
+ :switches ((?f "Show surrounding functions" "--function-context")
+ (?b "Ignore whitespace changes" "--ignore-space-change")
+ (?w "Ignore all whitespace" "--ignore-all-space")
+ (?x "Disallow external diff drivers" "--no-ext-diff")
+ (?s "Show stats" "--stat"))
+ :actions ((?d "Dwim" magit-diff-dwim)
+ (?u "Diff unstaged" magit-diff-unstaged)
+ (?c "Show commit" magit-show-commit)
+ (?r "Diff range" magit-diff)
+ (?s "Diff staged" magit-diff-staged)
+ (?t "Show stash" magit-stash-show)
+ (?p "Diff paths" magit-diff-paths)
+ (?w "Diff worktree" magit-diff-working-tree))
+ :default-action magit-diff-dwim
+ :max-action-columns 3))
+
+(defvar magit-diff-refresh-popup
+ `(,@magit-diff-popup-common
+ :switches ((?f "Show surrounding functions" "--function-context")
+ (?b "Ignore whitespace changes" "--ignore-space-change")
+ (?w "Ignore all whitespace" "--ignore-all-space")
+ (?x "Disallow external diff drivers" "--no-ext-diff"))
+ :actions ((?g "Refresh" magit-diff-refresh)
+ (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
+ (?s "Set defaults" magit-diff-set-default-arguments) nil
+ (?w "Save defaults" magit-diff-save-default-arguments))
+ :max-action-columns 2))
+
+(defvar magit-diff-mode-refresh-popup
+ `(,@magit-diff-popup-common
+ :switches ((?f "Show surrounding functions" "--function-context")
+ (?b "Ignore whitespace changes" "--ignore-space-change")
+ (?w "Ignore all whitespace" "--ignore-all-space")
+ (?x "Disallow external diff drivers" "--no-ext-diff")
+ (?s "Show stats" "--stat"))
+ :actions ((?g "Refresh" magit-diff-refresh)
+ (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
+ (?s "Set defaults" magit-diff-set-default-arguments)
+ (?r "Switch range type" magit-diff-switch-range-type)
+ (?w "Save defaults" magit-diff-save-default-arguments)
+ (?f "Flip revisions" magit-diff-flip-revs))
+ :max-action-columns 2))
+
+(defvar magit-revision-mode-refresh-popup
+ `(,@magit-diff-popup-common
+ :switches ((?f "Show surrounding functions" "--function-context")
+ (?b "Ignore whitespace changes" "--ignore-space-change")
+ (?w "Ignore all whitespace" "--ignore-all-space")
+ (?x "Disallow external diff drivers" "--no-ext-diff")
+ (?s "Show stats" "--stat"))
+ :actions ((?g "Refresh" magit-diff-refresh)
+ (?t "Toggle hunk refinement" magit-diff-toggle-refine-hunk)
+ (?s "Set defaults" magit-diff-set-default-arguments) nil
+ (?w "Save defaults" magit-diff-save-default-arguments))
+ :max-action-columns 2))
+
+(magit-define-popup-keys-deferred 'magit-diff-popup)
+(magit-define-popup-keys-deferred 'magit-diff-refresh-popup)
+(magit-define-popup-keys-deferred 'magit-diff-mode-refresh-popup)
+(magit-define-popup-keys-deferred 'magit-revision-mode-refresh-popup)
+
+(defcustom magit-diff-arguments '("--stat" "--no-ext-diff")
+ "The diff arguments used in buffers whose mode derives from `magit-diff-mode'."
+ :group 'magit-diff
+ :group 'magit-commands
+ :type '(repeat (string :tag "Argument")))
+
+(defcustom magit-diff-section-arguments '("--no-ext-diff")
+ "The diff arguments used in buffers that show other things besides diffs."
+ :group 'magit-diff
+ :group 'magit-status
+ :type '(repeat (string :tag "Argument")))
+
+(defvar magit-diff-section-file-args nil)
+(put 'magit-diff-section-file-args 'permanent-local t)
+(put 'magit-diff-section-arguments 'permanent-local t)
+
+(defun magit-diff-arguments (&optional refresh)
+ (cond ((memq magit-current-popup '(magit-diff-popup magit-diff-refresh-popup))
+ (magit-popup-export-file-args magit-current-popup-args))
+ ((derived-mode-p 'magit-diff-mode)
+ (list (nth 2 magit-refresh-args)
+ (nth 3 magit-refresh-args)))
+ (refresh
+ (list magit-diff-section-arguments
+ magit-diff-section-file-args))
+ (t
+ (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
+ (with-current-buffer buffer
+ (list (nth 2 magit-refresh-args)
+ (nth 3 magit-refresh-args)))
+ (list (default-value 'magit-diff-arguments) nil)))))
+
+;;;###autoload
+(defun magit-diff-popup (arg)
+ "Popup console for diff commands."
+ (interactive "P")
+ (let ((magit-diff-arguments
+ ;; We cannot possibly know what suffix command the user is
+ ;; about to invoke, so we also don't know from which buffer
+ ;; we should get the current values. However it is much
+ ;; more likely that we will end up updating the diff buffer,
+ ;; and we therefore use the value from that buffer.
+ (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
+ (with-current-buffer buffer
+ (magit-popup-import-file-args (nth 2 magit-refresh-args)
+ (nth 3 magit-refresh-args)))
+ (default-value 'magit-diff-arguments))))
+ (magit-invoke-popup 'magit-diff-popup nil arg)))
+
+;;;###autoload
+(defun magit-diff-buffer-file-popup ()
+ "Popup console for diff commands.
+
+This is a variant of `magit-diff-popup' which shows the same popup
+but which limits the diff to the file being visited in the current
+buffer."
+ (interactive)
+ (-if-let (file (magit-file-relative-name))
+ (let ((magit-diff-arguments
+ (magit-popup-import-file-args
+ (-if-let (buffer (magit-mode-get-buffer 'magit-diff-mode))
+ (with-current-buffer buffer
+ (nth 3 magit-refresh-args))
+ (default-value 'magit-diff-arguments))
+ (list file))))
+ (magit-invoke-popup 'magit-diff-popup nil nil))
+ (user-error "Buffer isn't visiting a file")))
+
+(defun magit-diff-refresh-popup (arg)
+ "Popup console for changing diff arguments in the current buffer."
+ (interactive "P")
+ (let ((magit-diff-refresh-popup
+ (pcase major-mode
+ (`magit-revision-mode magit-revision-mode-refresh-popup)
+ (`magit-diff-mode magit-diff-mode-refresh-popup)
+ (_ magit-diff-refresh-popup)))
+ (magit-diff-arguments
+ (if (derived-mode-p 'magit-diff-mode)
+ (magit-popup-import-file-args (nth 2 magit-refresh-args)
+ (nth 3 magit-refresh-args))
+ (magit-popup-import-file-args magit-diff-section-arguments
+ magit-diff-section-file-args))))
+ (magit-invoke-popup 'magit-diff-refresh-popup nil arg)))
+
+(defun magit-diff-select-algorithm (&rest _ignore)
+ (magit-read-char-case nil t
+ (?d "[d]efault" "default")
+ (?m "[m]inimal" "minimal")
+ (?p "[p]atience" "patience")
+ (?h "[h]istogram" "histogram")))
+
+;;;; Diff commands
+
+;;;###autoload
+(defun magit-diff-dwim (&optional args files)
+ "Show changes for the thing at point."
+ (interactive (magit-diff-arguments))
+ (pcase (magit-diff--dwim)
+ (`unstaged (magit-diff-unstaged args files))
+ (`staged (magit-diff-staged nil args files))
+ (`(commit . ,value)
+ (magit-diff (format "%s^..%s" value value) args files))
+ (`(stash . ,value) (magit-stash-show value args))
+ ((and range (pred stringp))
+ (magit-diff range args files))
+ (_
+ (call-interactively #'magit-diff))))
+
+(defun magit-diff--dwim ()
+ "Return information for performing DWIM diff.
+
+The information can be in three forms:
+1. TYPE
+ A symbol describing a type of diff where no additional information
+ is needed to generate the diff. Currently, this includes `staged'
+ and `unstaged'.
+2. (TYPE . VALUE)
+ Like #1 but the diff requires additional information, which is
+ given by VALUE. Currently, this includes `commit' and `stash',
+ where VALUE is the given commit or stash, respectively.
+3. RANGE
+ A string indicating a diff range.
+
+If no DWIM context is found, nil is returned."
+ (cond
+ ((--when-let (magit-region-values 'commit 'branch)
+ (deactivate-mark)
+ (concat (car (last it)) ".." (car it))))
+ (magit-buffer-refname
+ (cons 'commit magit-buffer-refname))
+ ((derived-mode-p 'magit-stash-mode)
+ (cons 'commit
+ (magit-section-case
+ (commit (magit-section-value it))
+ (file (-> it
+ magit-section-parent
+ magit-section-value))
+ (hunk (-> it
+ magit-section-parent
+ magit-section-parent
+ magit-section-value)))))
+ ((derived-mode-p 'magit-revision-mode)
+ (cons 'commit (car magit-refresh-args)))
+ ((derived-mode-p 'magit-diff-mode)
+ (nth 0 magit-refresh-args))
+ (t
+ (magit-section-case
+ ([* unstaged] 'unstaged)
+ ([* staged] 'staged)
+ (unpushed (magit-section-value it))
+ (unpulled (magit-section-value it))
+ (branch (let ((current (magit-get-current-branch))
+ (atpoint (magit-section-value it)))
+ (if (equal atpoint current)
+ (--if-let (magit-get-upstream-branch)
+ (format "%s...%s" it current)
+ (if (magit-anything-modified-p)
+ current
+ (cons 'commit current)))
+ (format "%s...%s" current atpoint))))
+ (commit (cons 'commit (magit-section-value it)))
+ (stash (cons 'stash (magit-section-value it)))))))
+
+(defun magit-diff-read-range-or-commit (prompt &optional secondary-default mbase)
+ "Read range or revision with special diff range treatment.
+If MBASE is non-nil, prompt for which rev to place at the end of
+a \"revA...revB\" range. Otherwise, always construct
+\"revA..revB\" range."
+ (--if-let (magit-region-values 'commit 'branch)
+ (let ((revA (car (last it)))
+ (revB (car it)))
+ (deactivate-mark)
+ (if mbase
+ (let ((base (magit-git-string "merge-base" revA revB)))
+ (cond
+ ((string= (magit-rev-parse revA) base)
+ (format "%s..%s" revA revB))
+ ((string= (magit-rev-parse revB) base)
+ (format "%s..%s" revB revA))
+ (t
+ (let ((main (magit-completing-read "View changes along"
+ (list revA revB)
+ nil t nil nil revB)))
+ (format "%s...%s"
+ (if (string= main revB) revA revB) main)))))
+ (format "%s..%s" revA revB)))
+ (magit-read-range prompt
+ (or (pcase (magit-diff--dwim)
+ (`(commit . ,value)
+ (format "%s^..%s" value value))
+ ((and range (pred stringp))
+ range))
+ secondary-default
+ (magit-get-current-branch)))))
+
+(defun magit-diff-setup (rev-or-range const args files)
+ (require 'magit)
+ (magit-mode-setup #'magit-diff-mode rev-or-range const args files))
+
+;;;###autoload
+(defun magit-diff (rev-or-range &optional args files)
+ "Show differences between two commits.
+
+REV-OR-RANGE should be a range or a single revision. If it is a
+revision, then show changes in the working tree relative to that
+revision. If it is a range, but one side is omitted, then show
+changes relative to `HEAD'.
+
+If the region is active, use the revisions on the first and last
+line of the region as the two sides of the range. With a prefix
+argument, instead of diffing the revisions, choose a revision to
+view changes along, starting at the common ancestor of both
+revisions (i.e., use a \"...\" range)."
+ (interactive (cons (magit-diff-read-range-or-commit "Diff for range"
+ nil current-prefix-arg)
+ (magit-diff-arguments)))
+ (magit-diff-setup rev-or-range nil args files))
+
+;;;###autoload
+(defun magit-diff-working-tree (&optional rev args files)
+ "Show changes between the current working tree and the `HEAD' commit.
+With a prefix argument show changes between the working tree and
+a commit read from the minibuffer."
+ (interactive
+ (cons (and current-prefix-arg
+ (magit-read-branch-or-commit "Diff working tree and commit"))
+ (magit-diff-arguments)))
+ (magit-diff-setup (or rev "HEAD") nil args files))
+
+;;;###autoload
+(defun magit-diff-staged (&optional rev args files)
+ "Show changes between the index and the `HEAD' commit.
+With a prefix argument show changes between the index and
+a commit read from the minibuffer."
+ (interactive
+ (cons (and current-prefix-arg
+ (magit-read-branch-or-commit "Diff index and commit"))
+ (magit-diff-arguments)))
+ (magit-diff-setup rev (list "--cached") args files))
+
+;;;###autoload
+(defun magit-diff-unstaged (&optional args files)
+ "Show changes between the working tree and the index."
+ (interactive (magit-diff-arguments))
+ (magit-diff-setup nil nil args files))
+
+;;;###autoload
+(defun magit-diff-while-committing (&optional args files)
+ "While committing, show the changes that are about to be committed.
+While amending, invoking the command again toggles between
+showing just the new changes or all the changes that will
+be committed."
+ (interactive (magit-diff-arguments))
+ (let ((toplevel (magit-toplevel))
+ (diff-buf (magit-mode-get-buffer 'magit-diff-mode)))
+ (if (magit-commit-message-buffer)
+ (if (and (or ;; most likely an explicit amend
+ (not (magit-anything-staged-p))
+ ;; explicitly toggled from within diff
+ (and (eq (current-buffer) diff-buf)))
+ (or (not diff-buf)
+ (with-current-buffer diff-buf
+ (or ;; default to include last commit
+ (not (equal (magit-toplevel) toplevel))
+ ;; toggle to include last commit
+ (not (car magit-refresh-args))))))
+ (magit-diff-while-amending args files)
+ (magit-diff-staged nil args files))
+ (user-error "No commit in progress"))))
+
+(define-key git-commit-mode-map
+ (kbd "C-c C-d") 'magit-diff-while-committing)
+
+(defun magit-diff-while-amending (&optional args files)
+ (magit-diff-setup "HEAD^" (list "--cached") args files))
+
+;;;###autoload
+(defun magit-diff-buffer-file ()
+ "Show diff for the blob or file visited in the current buffer."
+ (interactive)
+ (require 'magit)
+ (-if-let (file (magit-file-relative-name))
+ (magit-mode-setup-internal #'magit-diff-mode
+ (list (or magit-buffer-refname
+ (magit-get-current-branch)
+ "HEAD")
+ nil
+ (cadr (magit-diff-arguments))
+ (list file))
+ magit-diff-buffer-file-locked)
+ (user-error "Buffer isn't visiting a file")))
+
+;;;###autoload
+(defun magit-diff-paths (a b)
+ "Show changes between any two files on disk."
+ (interactive (list (read-file-name "First file: " nil nil t)
+ (read-file-name "Second file: " nil nil t)))
+ (magit-diff-setup nil (list "--no-index")
+ nil (list (expand-file-name a)
+ (expand-file-name b))))
+
+;;;###autoload
+(defun magit-show-commit (rev &optional args files module)
+ "Show the revision at point.
+If there is no revision at point or with a prefix argument prompt
+for a revision."
+ (interactive
+ (let* ((mcommit (magit-section-when module-commit))
+ (atpoint (or (and (bound-and-true-p magit-blame-mode)
+ (magit-blame-chunk-get :hash))
+ mcommit
+ magit-buffer-refname
+ (magit-branch-or-commit-at-point)
+ (magit-tag-at-point))))
+ (nconc (cons (or (and (not current-prefix-arg) atpoint)
+ (magit-read-branch-or-commit "Show commit" atpoint))
+ (magit-diff-arguments))
+ (and mcommit (list (magit-section-parent-value
+ (magit-current-section)))))))
+ (require 'magit)
+ (magit-with-toplevel
+ (when module
+ (setq default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (unless (magit-rev-verify-commit rev)
+ (user-error "%s is not a commit" rev))
+ (-when-let (buffer (magit-mode-get-buffer 'magit-revision-mode))
+ (with-current-buffer buffer
+ (let ((prev (car magit-refresh-args)))
+ (unless (equal rev prev)
+ (dolist (child (cdr (magit-section-children magit-root-section)))
+ (when (eq (magit-section-type child) 'file)
+ (magit-section-cache-visibility child)))))))
+ (magit-mode-setup #'magit-revision-mode rev nil args files)))
+
+;;;; Setting commands
+
+(defun magit-diff-refresh (args files)
+ "Set the local diff arguments for the current buffer."
+ (interactive (magit-diff-arguments t))
+ (cond ((derived-mode-p 'magit-diff-mode)
+ (setcdr (cdr magit-refresh-args) (list args files)))
+ (t
+ (setq-local magit-diff-section-arguments args)
+ (setq-local magit-diff-section-file-args files)))
+ (magit-refresh))
+
+(defun magit-diff-set-default-arguments (args files)
+ "Set the global diff arguments for the current buffer."
+ (interactive (magit-diff-arguments t))
+ (cond ((derived-mode-p 'magit-diff-mode)
+ (customize-set-variable 'magit-diff-arguments args)
+ (setcdr (cdr magit-refresh-args) (list args files)))
+ (t
+ (customize-set-variable 'magit-diff-section-arguments args)
+ (kill-local-variable 'magit-diff-section-arguments)
+ (kill-local-variable 'magit-diff-section-file-args)))
+ (magit-refresh))
+
+(defun magit-diff-save-default-arguments (args files)
+ "Set and save the global diff arguments for the current buffer."
+ (interactive (magit-diff-arguments t))
+ (cond ((derived-mode-p 'magit-diff-mode)
+ (customize-save-variable 'magit-diff-arguments args)
+ (setcdr (cdr magit-refresh-args) (list args files)))
+ (t
+ (customize-save-variable 'magit-diff-section-arguments args)
+ (kill-local-variable 'magit-diff-section-arguments)
+ (kill-local-variable 'magit-diff-section-file-args)))
+ (magit-refresh))
+
+(defun magit-diff-switch-range-type ()
+ "Convert diff range type.
+Change \"revA..revB\" to \"revB...revA\", or vice versa."
+ (interactive)
+ (let ((range (car magit-refresh-args)))
+ (if (and range
+ (derived-mode-p 'magit-diff-mode)
+ (string-match magit-range-re range))
+ (progn
+ (setcar magit-refresh-args
+ (concat (match-string 1 range)
+ (if (string= (match-string 2 range) "..")
+ "..."
+ "..")
+ (match-string 3 range)))
+ (magit-refresh))
+ (user-error "No range to change"))))
+
+(defun magit-diff-flip-revs ()
+ "Swap revisions in diff range.
+Change \"revA..revB\" to \"revB..revA\"."
+ (interactive)
+ (let ((range (car magit-refresh-args)))
+ (if (and range
+ (derived-mode-p 'magit-diff-mode)
+ (string-match magit-range-re range))
+ (progn
+ (setcar magit-refresh-args
+ (concat (match-string 3 range)
+ (match-string 2 range)
+ (match-string 1 range)))
+ (magit-refresh))
+ (user-error "No range to swap"))))
+
+(defun magit-diff-less-context (&optional count)
+ "Decrease the context for diff hunks by COUNT lines."
+ (interactive "p")
+ (magit-diff-set-context `(lambda (cur) (max 0 (- (or cur 0) ,count)))))
+
+(defun magit-diff-more-context (&optional count)
+ "Increase the context for diff hunks by COUNT lines."
+ (interactive "p")
+ (magit-diff-set-context `(lambda (cur) (+ (or cur 0) ,count))))
+
+(defun magit-diff-default-context ()
+ "Reset context for diff hunks to the default height."
+ (interactive)
+ (magit-diff-set-context #'ignore))
+
+(defun magit-diff-set-context (fn)
+ (let* ((def (--if-let (magit-get "diff.context") (string-to-number it) 3))
+ (val (car (magit-diff-arguments t)))
+ (arg (--first (string-match "^-U\\([0-9]+\\)?$" it) val))
+ (num (--if-let (and arg (match-string 1 arg)) (string-to-number it) def))
+ (val (delete arg val))
+ (num (funcall fn num))
+ (arg (and num (not (= num def)) (format "-U%i" num)))
+ (val (if arg (cons arg val) val)))
+ (if (derived-mode-p 'magit-diff-mode)
+ (setcar (cddr magit-refresh-args) val)
+ (setq magit-diff-section-arguments val)))
+ (magit-refresh))
+
+(defun magit-diff-context-p ()
+ (--if-let (--first (string-match "^-U\\([0-9]+\\)$" it)
+ (car (magit-diff-arguments t)))
+ (not (equal "-U0" it))
+ t))
+
+(defun magit-diff-toggle-refine-hunk (&optional style)
+ "Turn diff-hunk refining on or off.
+
+If hunk refining is currently on, then hunk refining is turned off.
+If hunk refining is off, then hunk refining is turned on, in
+`selected' mode (only the currently selected hunk is refined).
+
+With a prefix argument, the \"third choice\" is used instead:
+If hunk refining is currently on, then refining is kept on, but
+the refining mode (`selected' or `all') is switched.
+If hunk refining is off, then hunk refining is turned on, in
+`all' mode (all hunks refined).
+
+Customize variable `magit-diff-refine-hunk' to change the default mode."
+ (interactive "P")
+ (setq-local magit-diff-refine-hunk
+ (if style
+ (if (eq magit-diff-refine-hunk 'all) t 'all)
+ (not magit-diff-refine-hunk)))
+ (magit-diff-update-hunk-refinement))
+
+;;;; Visit commands
+
+(defun magit-diff-visit-file (file &optional other-window force-worktree)
+ "From a diff, visit the corresponding file at the appropriate position.
+
+If the diff shows changes in the worktree, the index, or `HEAD',
+then visit the actual file. Otherwise, when the diff is about an
+older commit or a range, then visit the appropriate blob.
+
+If point is on a removed line, then visit the blob for the first
+parent of the commit which removed that line, i.e. the last
+commit where that line still existed. Otherwise visit the blob
+for the commit whose changes are being shown.
+
+When the file or blob to be displayed is already being displayed
+in another window of the same frame, then just select that window
+and adjust point. Otherwise, or with a prefix argument, display
+the buffer in another window."
+ (interactive (list (--if-let (magit-file-at-point)
+ (expand-file-name it)
+ (user-error "No file at point"))
+ current-prefix-arg))
+ (if (magit-file-accessible-directory-p file)
+ (magit-diff-visit-directory file other-window)
+ (let* ((hunk (magit-diff-visit--hunk))
+ (line (and hunk (magit-diff-hunk-line hunk)))
+ (col (and hunk (magit-diff-hunk-column hunk)))
+ (rev (if (and magit-diff-visit-previous-blob
+ (magit-section-match 'hunk)
+ (save-excursion
+ (goto-char (line-beginning-position))
+ (looking-at "-")))
+ (magit-diff-visit--range-beginning)
+ (magit-diff-visit--range-end)))
+ (buf (if (and (not force-worktree)
+ (stringp rev))
+ (magit-find-file-noselect rev file)
+ (or (get-file-buffer file)
+ (find-file-noselect file)))))
+ (magit-display-file-buffer buf)
+ (with-current-buffer buf
+ (when line
+ (setq line
+ (cond ((eq rev 'staged)
+ (apply 'magit-diff-visit--offset file nil line))
+ ((and force-worktree
+ (stringp rev))
+ (apply 'magit-diff-visit--offset file rev line))
+ (t
+ (apply '+ line))))
+ (let ((pos (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (move-to-column col)
+ (point))))
+ (unless (<= (point-min) pos (point-max))
+ (widen)
+ (goto-char pos))))
+ (when (magit-anything-unmerged-p file)
+ (smerge-start-session))
+ (run-hooks 'magit-diff-visit-file-hook)))))
+
+(defvar magit-display-file-buffer-function
+ 'magit-display-file-buffer-traditional
+ "The function used by `magit-diff-visit-file' to display blob buffers.
+
+Other commands such as `magit-find-file' do not use this
+function. Instead they use high-level functions to select the
+window to be used to display the buffer. This variable and the
+related functions are an experimental feature and should be
+treated as such.")
+
+(defun magit-display-file-buffer (buffer)
+ (funcall magit-display-file-buffer-function buffer))
+
+(defun magit-display-file-buffer-traditional (buffer)
+ (if (or current-prefix-arg (get-buffer-window buffer))
+ (pop-to-buffer buffer)
+ (switch-to-buffer buffer)))
+
+(defun magit-diff-visit-file-worktree (file &optional other-window)
+ "From a diff, visit the corresponding file at the appropriate position.
+
+When the file is already being displayed in another window of the
+same frame, then just select that window and adjust point. With
+a prefix argument also display in another window.
+
+The actual file in the worktree is visited. The positions in the
+hunk headers get less useful the \"older\" the changes are, and
+as a result, jumping to the appropriate position gets less
+reliable.
+
+Also see `magit-diff-visit-file' which visits the respective
+blob, unless the diff shows changes in the worktree, the index,
+or `HEAD'."
+ (interactive (list (or (magit-file-at-point)
+ (user-error "No file at point"))
+ current-prefix-arg))
+ (magit-diff-visit-file file other-window t))
+
+(defun magit-diff-visit--range-end ()
+ (let ((rev (magit-diff--dwim)))
+ (if (symbolp rev)
+ rev
+ (setq rev (if (consp rev)
+ (cdr rev)
+ (car (magit-split-range rev))))
+ (if (magit-rev-head-p rev)
+ 'unstaged
+ rev))))
+
+(defun magit-diff-visit--range-beginning ()
+ (let ((rev (magit-diff--dwim)))
+ (cond ((consp rev)
+ (concat (cdr rev) "^"))
+ ((stringp rev)
+ (cdr (magit-split-range rev)))
+ (t
+ rev))))
+
+(defun magit-diff-visit--hunk ()
+ (-when-let (scope (magit-diff-scope))
+ (let ((section (magit-current-section)))
+ (cl-case scope
+ ((file files)
+ (setq section (car (magit-section-children section))))
+ (list
+ (setq section (car (magit-section-children section)))
+ (when section
+ (setq section (car (magit-section-children section))))))
+ (and
+ ;; Unmerged files appear in the list of staged changes
+ ;; but unlike in the list of unstaged changes no diffs
+ ;; are shown here. In that case `section' is nil.
+ section
+ ;; Currently the `hunk' type is also abused for file
+ ;; mode changes, which we are not interested in here.
+ ;; Such sections have no value.
+ (magit-section-value section)
+ section))))
+
+(defun magit-diff-visit--offset (file rev hunk-start line-offset)
+ (let ((offset 0))
+ (with-temp-buffer
+ (save-excursion
+ (magit-with-toplevel
+ (magit-git-insert "diff" rev "--" file)))
+ (catch 'found
+ (while (re-search-forward
+ "^@@ -\\([0-9]+\\),\\([0-9]+\\) \\+\\([0-9]+\\),\\([0-9]+\\) @@"
+ nil t)
+ (let* ((abeg (string-to-number (match-string 1)))
+ (alen (string-to-number (match-string 2)))
+ (bbeg (string-to-number (match-string 3)))
+ (blen (string-to-number (match-string 4)))
+ (aend (+ abeg alen))
+ (bend (+ bbeg blen))
+ (hend (+ hunk-start line-offset)))
+ (if (<= abeg hunk-start)
+ (if (or (>= aend hend)
+ (>= bend hend))
+ (let ((line 0))
+ (while (<= line alen)
+ (forward-line 1)
+ (cl-incf line)
+ (cond ((looking-at "^\\+") (cl-incf offset))
+ ((looking-at "^-") (cl-decf offset)))))
+ (cl-incf offset (- blen alen)))
+ (throw 'found nil))))))
+ (+ hunk-start line-offset offset)))
+
+(defun magit-diff-hunk-line (section)
+ (let* ((value (magit-section-value section))
+ (prefix (- (length value) 2))
+ (cpos (marker-position (magit-section-content section)))
+ (stop (line-number-at-pos))
+ (cstart (save-excursion (goto-char cpos)
+ (line-number-at-pos)))
+ (prior (and (= (length value) 3)
+ (save-excursion (goto-char (line-beginning-position))
+ (looking-at "-"))))
+ (offset 0)
+ (line (if prior
+ (cadr value)
+ (car (last value)))))
+ (string-match (format "^%s\\([0-9]+\\)" (if prior "-" "\\+")) line)
+ (setq line (string-to-number (match-string 1 line)))
+ (when (> cstart stop)
+ (save-excursion
+ (goto-char cpos)
+ (re-search-forward "^[-+]")
+ (setq stop (line-number-at-pos))))
+ (save-excursion
+ (goto-char cpos)
+ (while (< (line-number-at-pos) stop)
+ (unless (string-match-p
+ (if prior "\\+" "-")
+ (buffer-substring (point) (+ (point) prefix)))
+ (cl-incf offset))
+ (forward-line)))
+ (list line offset)))
+
+(defun magit-diff-hunk-column (section)
+ (if (or (< (point) (magit-section-content section))
+ (save-excursion (beginning-of-line) (looking-at-p "-")))
+ 0
+ (max 0 (- (+ (current-column) 2)
+ (length (magit-section-value section))))))
+
+(defun magit-diff-visit-directory (directory &optional other-window)
+ (if (equal (magit-toplevel directory)
+ (magit-toplevel))
+ (dired-jump other-window (concat directory "/."))
+ (let ((display-buffer-overriding-action
+ (if other-window
+ '(nil (inhibit-same-window t))
+ '(display-buffer-same-window))))
+ (magit-status-internal directory))))
+
+;;;; Scroll commands
+
+(defun magit-diff-show-or-scroll-up ()
+ "Update the commit or diff buffer for the thing at point.
+
+Either show the commit or stash at point in the appropriate
+buffer, or if that buffer is already being displayed in the
+current frame and contains information about that commit or
+stash, then instead scroll the buffer up. If there is no
+commit or stash at point, then prompt for a commit."
+ (interactive)
+ (magit-diff-show-or-scroll 'scroll-up))
+
+(defun magit-diff-show-or-scroll-down ()
+ "Update the commit or diff buffer for the thing at point.
+
+Either show the commit or stash at point in the appropriate
+buffer, or if that buffer is already being displayed in the
+current frame and contains information about that commit or
+stash, then instead scroll the buffer down. If there is no
+commit or stash at point, then prompt for a commit."
+ (interactive)
+ (magit-diff-show-or-scroll 'scroll-down))
+
+(defun magit-diff-show-or-scroll (fn)
+ (let (rev cmd buf win)
+ (cond
+ (magit-blame-mode
+ (setq rev (magit-blame-chunk-get :hash)
+ cmd 'magit-show-commit
+ buf (magit-mode-get-buffer 'magit-revision-mode)))
+ ((derived-mode-p 'git-rebase-mode)
+ (save-excursion
+ (goto-char (line-beginning-position))
+ (--if-let (and git-rebase-line
+ (looking-at git-rebase-line)
+ (match-string 2))
+ (setq rev it
+ cmd 'magit-show-commit
+ buf (magit-mode-get-buffer 'magit-revision-mode))
+ (user-error "No commit on this line"))))
+ (t
+ (magit-section-case
+ ((commit branch)
+ (setq rev (magit-section-value it)
+ cmd 'magit-show-commit
+ buf (magit-mode-get-buffer 'magit-revision-mode)))
+ (stash
+ (setq rev (magit-section-value it)
+ cmd 'magit-stash-show
+ buf (magit-mode-get-buffer 'magit-stash-mode))))))
+ (if rev
+ (if (and buf
+ (setq win (get-buffer-window buf))
+ (with-current-buffer buf
+ (equal rev (car magit-refresh-args))))
+ (with-selected-window win
+ (condition-case nil
+ (funcall fn)
+ (error
+ (goto-char (pcase fn
+ (`scroll-up (point-min))
+ (`scroll-down (point-max)))))))
+ (let ((magit-display-buffer-noselect t))
+ (if (eq cmd 'magit-show-commit)
+ (apply #'magit-show-commit rev (magit-diff-arguments))
+ (funcall cmd rev))))
+ (call-interactively #'magit-show-commit))))
+
+;;; Diff Mode
+
+(defvar magit-diff-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "\C-c\C-d" 'magit-diff-while-committing)
+ (define-key map "\C-c\C-b" 'magit-go-backward)
+ (define-key map "\C-c\C-f" 'magit-go-forward)
+ (define-key map "\s" 'scroll-up)
+ (define-key map "\d" 'scroll-down)
+ (define-key map "j" 'magit-jump-to-diffstat-or-diff)
+ map)
+ "Keymap for `magit-diff-mode'.")
+
+(define-derived-mode magit-diff-mode magit-mode "Magit Diff"
+ "Mode for looking at a Git diff.
+
+This mode is documented in info node `(magit)Diff buffer'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-section-toggle] to expand or hide the section at point.
+Type \\[magit-visit-thing] to visit the hunk or file at point.
+
+Staging and applying changes is documented in info node
+`(magit)Staging and unstaging' and info node `(magit)Applying'.
+
+\\<magit-hunk-section-map>Type \
+\\[magit-apply] to apply the change at point, \
+\\[magit-stage] to stage,
+\\[magit-unstage] to unstage, \
+\\[magit-discard] to discard, or \
+\\[magit-reverse] to reverse it.
+
+\\{magit-diff-mode-map}"
+ :group 'magit-diff
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-diff-refresh-buffer (rev-or-range const _args files)
+ "Refresh the current `magit-diff-mode' buffer.
+
+In such buffers the buffer-local value of `magit-refresh-args'
+has the same form as the arguments of this function. The value
+is set in `magit-mode-setup'."
+ (setq header-line-format
+ (propertize
+ (if (member "--no-index" const)
+ (apply #'format " Differences between %s and %s" files)
+ (concat (if rev-or-range
+ (if (string-match-p "\\.\\." rev-or-range)
+ (format " Changes in %s" rev-or-range)
+ (format " Changes from %s to working tree" rev-or-range))
+ (if (member "--cached" const)
+ " Staged changes"
+ " Unstaged changes"))
+ (pcase (length files)
+ (0)
+ (1 (concat " in file " (car files)))
+ (_ (concat " in files "
+ (mapconcat #'identity files ", "))))))
+ 'face 'magit-header-line))
+ (magit-insert-section (diffbuf)
+ (run-hook-with-args 'magit-diff-sections-hook rev-or-range)))
+
+(defun magit-insert-diff (rev-or-range)
+ "Insert the diff into this `magit-diff-mode' buffer."
+ (let ((magit-git-global-arguments
+ (remove "--literal-pathspecs" magit-git-global-arguments)))
+ (magit-git-wash #'magit-diff-wash-diffs
+ "diff" rev-or-range "-p" "--no-prefix"
+ (and (member "--stat" (nth 2 magit-refresh-args)) "--numstat")
+ (nth 1 magit-refresh-args)
+ (nth 2 magit-refresh-args) "--"
+ (nth 3 magit-refresh-args))))
+
+(defvar magit-file-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [C-return] 'magit-diff-visit-file-worktree)
+ (define-key map "\C-j" 'magit-diff-visit-file-worktree)
+ (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map [remap magit-revert-no-commit] 'magit-reverse)
+ (define-key map "a" 'magit-apply)
+ (define-key map "C" 'magit-commit-add-log)
+ (define-key map "K" 'magit-file-untrack)
+ (define-key map "R" 'magit-file-rename)
+ (define-key map "s" 'magit-stage)
+ (define-key map "u" 'magit-unstage)
+ map)
+ "Keymap for `file' sections.")
+
+(defvar magit-hunk-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [C-return] 'magit-diff-visit-file-worktree)
+ (define-key map "\C-j" 'magit-diff-visit-file-worktree)
+ (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map [remap magit-revert-no-commit] 'magit-reverse)
+ (define-key map "a" 'magit-apply)
+ (define-key map "C" 'magit-commit-add-log)
+ (define-key map "s" 'magit-stage)
+ (define-key map "u" 'magit-unstage)
+ map)
+ "Keymap for `hunk' sections.")
+
+(defconst magit-diff-headline-re
+ (concat "^\\(@@@?\\|diff\\|Submodule\\|"
+ "\\* Unmerged path\\|merged\\|changed in both\\|"
+ "added in remote\\|removed in remote\\)"))
+
+(defconst magit-diff-statline-re
+ (concat "^ ?"
+ "\\(.*\\)" ; file
+ "\\( +| +\\)" ; separator
+ "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?"
+ "\\(\\+*\\)" ; add
+ "\\(-*\\)$")) ; del
+
+(defun magit-diff-wash-diffs (args &optional limit)
+ (when (member "--stat" args)
+ (magit-diff-wash-diffstat))
+ (when (re-search-forward magit-diff-headline-re limit t)
+ (goto-char (line-beginning-position))
+ (magit-wash-sequence (apply-partially 'magit-diff-wash-diff args))
+ (insert ?\n)))
+
+(defun magit-jump-to-diffstat-or-diff ()
+ "Jump to the diffstat or diff.
+When point is on a file inside the diffstat section, then jump
+to the respective diff section, otherwise jump to the diffstat
+section or a child thereof."
+ (interactive)
+ (--if-let (magit-get-section
+ (append (magit-section-case
+ ([file diffstat] `((file . ,(magit-section-value it))))
+ (file `((file . ,(magit-section-value it)) (diffstat)))
+ (t '((diffstat))))
+ (magit-section-ident magit-root-section)))
+ (magit-section-goto it)
+ (user-error "No diffstat in this buffer")))
+
+(defun magit-diff-wash-diffstat ()
+ (let (heading (beg (point)))
+ (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t)
+ (setq heading (match-string 1))
+ (magit-delete-match)
+ (goto-char beg)
+ (magit-insert-section it (diffstat)
+ (insert (propertize heading 'face 'magit-diff-file-heading))
+ (magit-insert-heading)
+ (let (files)
+ (while (looking-at "^[-0-9]+\t[-0-9]+\t\\(.+\\)$")
+ (push (magit-decode-git-path (match-string 1)) files)
+ (magit-delete-line))
+ (setq files (nreverse files))
+ (while (looking-at magit-diff-statline-re)
+ (magit-bind-match-strings (file sep cnt add del) nil
+ (magit-delete-line)
+ (when (string-match " +$" file)
+ (setq sep (concat (match-string 0 file) sep))
+ (setq file (substring file 0 (match-beginning 0))))
+ (let ((le (length file)) ld)
+ (setq file (magit-decode-git-path file))
+ (setq ld (length file))
+ (when (> le ld)
+ (setq sep (concat (make-string (- le ld) ?\s) sep))))
+ (magit-insert-section (file (pop files))
+ (insert (propertize file 'face 'magit-filename) sep cnt " ")
+ (when add
+ (insert (propertize add 'face 'magit-diffstat-added)))
+ (when del
+ (insert (propertize del 'face 'magit-diffstat-removed)))
+ (insert "\n")))))
+ (if (looking-at "^$") (forward-line) (insert "\n"))))))
+
+(defun magit-diff-wash-diff (args)
+ (cond
+ ((looking-at "^Submodule")
+ (magit-diff-wash-submodule))
+ ((looking-at "^\\* Unmerged path \\(.*\\)")
+ (let ((file (magit-decode-git-path (match-string 1))))
+ (magit-delete-line)
+ (unless (and (derived-mode-p 'magit-status-mode)
+ (not (member "--cached" args)))
+ (magit-insert-section (file file)
+ (insert (propertize
+ (format "unmerged %s%s" file
+ (pcase (cddr (car (magit-file-status file)))
+ (`(?D ?D) " (both deleted)")
+ (`(?D ?U) " (deleted by us)")
+ (`(?U ?D) " (deleted by them)")
+ (`(?A ?A) " (both added)")
+ (`(?A ?U) " (added by us)")
+ (`(?U ?A) " (added by them)")
+ (`(?U ?U) "")))
+ 'face 'magit-diff-file-heading))
+ (insert ?\n))))
+ t)
+ ((looking-at (concat "^\\(merged\\|changed in both\\|"
+ "added in remote\\|removed in remote\\)"))
+ (let ((status (pcase (match-string 1)
+ ("merged" "merged")
+ ("changed in both" "conflict")
+ ("added in remote" "new file")
+ ("removed in remote" "deleted")))
+ file orig base modes)
+ (magit-delete-line)
+ (while (looking-at
+ "^ \\([^ ]+\\) +[0-9]\\{6\\} \\([a-z0-9]\\{40\\}\\) \\(.+\\)$")
+ (magit-bind-match-strings (side _blob name) nil
+ (pcase side
+ ("result" (setq file name))
+ ("our" (setq orig name))
+ ("their" (setq file name))
+ ("base" (setq base name))))
+ (magit-delete-line))
+ (when orig (setq orig (magit-decode-git-path orig)))
+ (when file (setq file (magit-decode-git-path file)))
+ (magit-diff-insert-file-section (or file base) orig status modes nil)))
+ ((looking-at
+ "^diff --\\(?:\\(git\\) \\(?:\\(.+?\\) \\2\\)?\\|\\(cc\\|combined\\) \\(.+\\)\\)")
+ (let ((status (cond ((equal (match-string 1) "git") "modified")
+ ((derived-mode-p 'magit-revision-mode) "resolved")
+ (t "unmerged")))
+ (file (or (match-string 2) (match-string 4)))
+ (beg (point))
+ orig header modes)
+ (save-excursion
+ (forward-line 1)
+ (setq header (buffer-substring
+ beg (if (re-search-forward magit-diff-headline-re nil t)
+ (match-beginning 0)
+ (point-max)))))
+ (magit-delete-line)
+ (while (not (or (eobp) (looking-at magit-diff-headline-re)))
+ (if (looking-at "^old mode \\([^\n]+\\)\nnew mode \\([^\n]+\\)\n")
+ (progn (setq modes (match-string 0))
+ (magit-delete-match))
+ (cond
+ ((looking-at "^--- \\([^/].*?\\)\t?$") ; i.e. not /dev/null
+ (setq orig (match-string 1)))
+ ((looking-at "^\\+\\+\\+ \\([^/].*?\\)\t?$")
+ (setq file (match-string 1)))
+ ((looking-at "^\\(copy\\|rename\\) from \\(.+\\)$")
+ (setq orig (match-string 2)))
+ ((looking-at "^\\(copy\\|rename\\) to \\(.+\\)$")
+ (setq file (match-string 2))
+ (setq status (if (equal (match-string 1) "copy") "new file" "renamed")))
+ ((looking-at "^\\(new file\\|deleted\\)")
+ (setq status (match-string 1))))
+ (magit-delete-line)))
+ (when orig
+ (setq orig (magit-decode-git-path orig)))
+ (setq file (magit-decode-git-path file))
+ ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used.
+ (when (and (derived-mode-p 'magit-log-mode)
+ (--first (string-match-p "\\`-L" it)
+ (nth 1 magit-refresh-args)))
+ (setq file (substring file 2))
+ (when orig
+ (setq orig (substring orig 2))))
+ (magit-diff-insert-file-section file orig status modes header)))))
+
+(defun magit-diff-insert-file-section (file orig status modes header)
+ (magit-insert-section section
+ (file file (or (equal status "deleted")
+ (derived-mode-p 'magit-status-mode)))
+ (insert (propertize (format "%-10s %s\n" status
+ (if (or (not orig) (equal orig file))
+ file
+ (format "%s -> %s" orig file)))
+ 'face 'magit-diff-file-heading))
+ (magit-insert-heading)
+ (unless (equal orig file)
+ (setf (magit-section-source section) orig))
+ (setf (magit-section-diff-header section) header)
+ (when modes
+ (magit-insert-section (hunk)
+ (insert modes)))
+ (magit-wash-sequence #'magit-diff-wash-hunk)))
+
+(defun magit-diff-wash-submodule ()
+ ;; See `show_submodule_summary' in submodule.c and "this" commit.
+ (when (looking-at "^Submodule \\([^ ]+\\)")
+ (let ((module (match-string 1))
+ untracked modified)
+ (when (looking-at "^Submodule [^ ]+ contains untracked content$")
+ (magit-delete-line)
+ (setq untracked t))
+ (when (looking-at "^Submodule [^ ]+ contains modified content$")
+ (magit-delete-line)
+ (setq modified t))
+ (cond
+ ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ :]+\\)\\( (rewind)\\)?:$")
+ (equal (match-string 1) module))
+ (magit-bind-match-strings (_module range rewind) nil
+ (magit-delete-line)
+ (while (looking-at "^ \\([<>]\\) \\(.+\\)$")
+ (magit-delete-line))
+ (when rewind
+ (setq range (replace-regexp-in-string "[^.]\\(\\.\\.\\)[^.]"
+ "..." range t t 1)))
+ (magit-insert-section (file module t)
+ (magit-insert-heading
+ (concat (propertize (concat "modified " module)
+ 'face 'magit-diff-file-heading)
+ " ("
+ (cond (rewind "rewind")
+ ((string-match-p "\\.\\.\\." range) "non-ff")
+ (t "new commits"))
+ (and (or modified untracked)
+ (concat ", "
+ (and modified "modified")
+ (and modified untracked " and ")
+ (and untracked "untracked")
+ " content"))
+ ")"))
+ (let ((default-directory
+ (file-name-as-directory
+ (expand-file-name module (magit-toplevel)))))
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'module)
+ "log" "--oneline" "--left-right" range)
+ (delete-char -1)))))
+ ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ ]+\\) (\\([^)]+\\))$")
+ (equal (match-string 1) module))
+ (magit-bind-match-strings (_module _range msg) nil
+ (magit-delete-line)
+ (magit-insert-section (file module)
+ (magit-insert-heading
+ (concat (propertize (concat "submodule " module)
+ 'face 'magit-diff-file-heading)
+ " (" msg ")")))))
+ (t
+ (magit-insert-section (file module)
+ (magit-insert-heading
+ (concat (propertize (concat "modified " module)
+ 'face 'magit-diff-file-heading)
+ " ("
+ (and modified "modified")
+ (and modified untracked " and ")
+ (and untracked "untracked")
+ " content)"))))))))
+
+(defun magit-diff-wash-hunk ()
+ (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?")
+ (let ((heading (match-string 0))
+ (value (cons (match-string 2) (split-string (match-string 1)))))
+ (magit-delete-line)
+ (magit-insert-section it (hunk value)
+ (insert (propertize (concat heading "\n") 'face 'magit-diff-hunk-heading))
+ (magit-insert-heading)
+ (while (not (or (eobp) (looking-at "^[^-+\s\\]")))
+ (forward-line))
+ (setf (magit-section-end it) (point))
+ (setf (magit-section-washer it) #'magit-diff-paint-hunk)))
+ t))
+
+(defun magit-diff-expansion-threshold (section)
+ "Keep new diff sections collapsed if washing takes too long."
+ (and (memq (magit-section-type section) '(file))
+ (> (float-time (time-subtract (current-time) magit-refresh-start-time))
+ magit-diff-expansion-threshold)
+ 'hide))
+
+;;; Revision Mode
+
+(define-derived-mode magit-revision-mode magit-diff-mode "Magit Rev"
+ "Mode for looking at a Git commit.
+
+This mode is documented in info node `(magit)Revision buffer'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-section-toggle] to expand or hide the section at point.
+Type \\[magit-visit-thing] to visit the hunk or file at point.
+
+Staging and applying changes is documented in info node
+`(magit)Staging and unstaging' and info node `(magit)Applying'.
+
+\\<magit-hunk-section-map>Type \
+\\[magit-apply] to apply the change at point, \
+\\[magit-stage] to stage,
+\\[magit-unstage] to unstage, \
+\\[magit-discard] to discard, or \
+\\[magit-reverse] to reverse it.
+
+\\{magit-revision-mode-map}"
+ :group 'magit-revision
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-revision-refresh-buffer (rev __const _args files)
+ (setq header-line-format
+ (propertize (concat " " (capitalize (magit-object-type rev))
+ " " rev
+ (pcase (length files)
+ (0)
+ (1 (concat " in file " (car files)))
+ (_ (concat " in files "
+ (mapconcat #'identity files ", ")))))
+ 'face 'magit-header-line))
+ (magit-insert-section (commitbuf)
+ (run-hook-with-args 'magit-revision-sections-hook rev)))
+
+(defun magit-insert-revision-diff (rev)
+ "Insert the diff into this `magit-revision-mode' buffer."
+ (let ((magit-git-global-arguments
+ (remove "--literal-pathspecs" magit-git-global-arguments)))
+ ;; Before v2.2.0, "--format=" did not mean "no output".
+ ;; Instead the default format was used. So use "--format=%n"
+ ;; and then delete the empty lines.
+ (magit-git-wash (lambda (args)
+ (delete-region (point) (progn (forward-line 3) (point)))
+ (magit-diff-wash-diffs args))
+ "show" "-p" "--cc" "--format=%n" "--no-prefix"
+ (and (member "--stat" (nth 2 magit-refresh-args)) "--numstat")
+ (nth 2 magit-refresh-args) (concat rev "^{commit}") "--"
+ (nth 3 magit-refresh-args))))
+
+(defun magit-insert-revision-tag (rev)
+ "Insert tag message and headers into a revision buffer.
+This function only inserts anything when `magit-show-commit' is
+called with a tag as argument, when that is called with a commit
+or a ref which is not a branch, then it inserts nothing."
+ (when (equal (magit-object-type rev) "tag")
+ (magit-insert-section (taginfo)
+ (let ((beg (point)))
+ (magit-git-insert "cat-file" "tag" rev)
+ (goto-char beg)
+ (forward-line 3)
+ (delete-region beg (point)))
+ (looking-at "^tagger \\([^<]+\\) <\\([^>]+\\)")
+ (let ((heading (format "Tagger: %s <%s>"
+ (match-string 1)
+ (match-string 2))))
+ (magit-delete-line)
+ (insert (propertize heading 'face 'magit-section-secondary-heading)))
+ (magit-insert-heading)
+ (goto-char (point-max))
+ (insert ?\n))))
+
+(defun magit-insert-revision-message (rev)
+ "Insert the commit message into a revision buffer."
+ (magit-insert-section (message)
+ (let ((beg (point)))
+ (magit-rev-insert-format "%B" rev)
+ (if (= (point) (+ beg 2))
+ (progn (backward-delete-char 2)
+ (insert "(no message)\n"))
+ (goto-char beg)
+ (while (search-forward "\r\n" nil t) ; Remove trailing CRs.
+ (delete-region (match-beginning 0) (1+ (match-beginning 0))))
+ (goto-char beg)
+ (forward-line)
+ (put-text-property beg (point) 'face 'magit-section-secondary-heading)
+ (magit-insert-heading)
+ (goto-char (point-max))))))
+
+(defun magit-insert-revision-notes (rev)
+ "Insert commit notes into a revision buffer."
+ (magit-insert-section (notes)
+ (let ((beg (point)))
+ (magit-git-insert "notes" "show" rev)
+ (if (= (point) beg)
+ (magit-cancel-section)
+ (goto-char beg)
+ (forward-line)
+ (put-text-property beg (point) 'face 'magit-section-secondary-heading)
+ (magit-insert-heading)
+ (goto-char (point-max))
+ (insert ?\n)))))
+
+(defun magit-insert-revision-headers (rev)
+ "Insert headers about the commit into a revision buffer."
+ (magit-insert-section (headers)
+ ;; Before v2.2.0, "%D" was not supported.
+ (--when-let (magit-rev-format "%d" rev "--decorate=full")
+ (insert (magit-format-ref-labels (substring it 2 -1)) ?\s))
+ (insert (propertize (magit-rev-parse (concat rev "^{commit}"))
+ 'face 'magit-hash))
+ (magit-insert-heading)
+ (let ((beg (point)))
+ (magit-rev-insert-format magit-revision-headers-format rev)
+ (magit-insert-revision-gravatars rev beg))
+ (when magit-revision-insert-related-refs
+ (dolist (parent (magit-commit-parents rev))
+ (magit-insert-section (commit parent)
+ (let ((line (magit-rev-format "%h %s" parent)))
+ (string-match "^\\([^ ]+\\) \\(.*\\)" line)
+ (magit-bind-match-strings (hash msg) line
+ (insert "Parent: ")
+ (insert (propertize hash 'face 'magit-hash))
+ (insert " " msg "\n")))))
+ (-when-let (merged (magit-list-merged-branches rev))
+ (insert "Merged: ")
+ (let (branch)
+ (while (and (< (+ (- (point) (line-beginning-position))
+ (length (car merged)) 9)
+ (window-width))
+ (setq branch (pop merged)))
+ (insert ?\s)
+ (magit-insert-section (branch branch)
+ (insert (propertize branch 'face 'magit-branch-local)))))
+ (when merged
+ (insert (format " (%s more)" (length merged))))
+ (insert ?\n))
+ (-when-let (containing (magit-list-containing-branches rev))
+ (insert "Containing:")
+ (let (branch)
+ (while (and (< (+ (- (point) (line-beginning-position))
+ (length (car containing)) 9)
+ (window-width))
+ (setq branch (pop containing)))
+ (insert ?\s)
+ (magit-insert-section (branch branch)
+ (insert (propertize branch 'face 'magit-branch-local)))))
+ (when containing
+ (insert (format " (%s more)" (length containing))))
+ (insert ?\n))
+ (-when-let (follows (magit-get-current-tag rev t))
+ (let ((tag (car follows))
+ (cnt (cadr follows)))
+ (magit-insert-section (tag tag)
+ (insert (format "Follows: %s (%s)\n"
+ (propertize tag 'face 'magit-tag)
+ (propertize (number-to-string cnt)
+ 'face 'magit-branch-local))))))
+ (-when-let (precedes (magit-get-next-tag rev t))
+ (let ((tag (car precedes))
+ (cnt (cadr precedes)))
+ (magit-insert-section (tag tag)
+ (insert (format "Precedes: %s (%s)\n"
+ (propertize tag 'face 'magit-tag)
+ (propertize (number-to-string cnt)
+ 'face 'magit-tag))))))
+ (insert ?\n))))
+
+(defun magit-insert-revision-gravatars (rev beg)
+ (when (and magit-revision-show-gravatars (window-system))
+ (require 'gravatar)
+ (magit-insert-revision-gravatar beg (magit-rev-format "%aE" rev)
+ (car magit-revision-show-gravatars))
+ (magit-insert-revision-gravatar beg (magit-rev-format "%cE" rev)
+ (cdr magit-revision-show-gravatars))
+ (goto-char (point-max))))
+
+(defun magit-insert-revision-gravatar (beg email regexp)
+ (when (and email (goto-char beg) (re-search-forward regexp nil t))
+ (ignore-errors
+ (let* ((offset (length (match-string 0)))
+ (font-obj (query-font (font-at (point) (get-buffer-window))))
+ (size (* 2 (+ (aref font-obj 4) (aref font-obj 5))))
+ (align-to (+ offset (ceiling (/ size (aref font-obj 7) 1.0))))
+ (gravatar-size (- size 2))
+ (slice1 '(slice .0 .0 1.0 0.5))
+ (slice2 '(slice .0 .5 1.0 1.0)))
+ (gravatar-retrieve
+ email
+ (lambda (image offset align-to slice1 slice2)
+ (unless (eq image 'error)
+ (insert (propertize " " 'display `((,@image :ascent center :relief 1)
+ ,slice1)))
+ (insert (propertize " " 'display `((space :align-to ,align-to))))
+ (forward-line)
+ (forward-char offset)
+ (insert (propertize " " 'display `((,@image :ascent center :relief 1)
+ ,slice2)))
+ (insert (propertize " " 'display `((space :align-to ,align-to))))))
+ (list offset align-to
+ (if magit-revision-use-gravatar-kludge slice2 slice1)
+ (if magit-revision-use-gravatar-kludge slice1 slice2)))))))
+
+;;; Diff Sections
+
+(defvar magit-unstaged-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-unstaged)
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map "s" 'magit-stage)
+ (define-key map "u" 'magit-unstage)
+ map)
+ "Keymap for the `unstaged' section.")
+
+(magit-define-section-jumper magit-jump-to-unstaged "Unstaged changes" unstaged)
+
+(defun magit-insert-unstaged-changes ()
+ "Insert section showing unstaged changes."
+ (magit-insert-section (unstaged)
+ (magit-insert-heading "Unstaged changes:")
+ (magit-git-wash #'magit-diff-wash-diffs
+ "diff" magit-diff-section-arguments "--no-prefix"
+ "--" magit-diff-section-file-args)))
+
+(defvar magit-staged-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-staged)
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map [remap magit-revert-no-commit] 'magit-reverse)
+ (define-key map "s" 'magit-stage)
+ (define-key map "u" 'magit-unstage)
+ map)
+ "Keymap for the `staged' section.")
+
+(magit-define-section-jumper magit-jump-to-staged "Staged changes" staged)
+
+(defun magit-insert-staged-changes ()
+ "Insert section showing staged changes."
+ (magit-insert-section (staged)
+ (magit-insert-heading "Staged changes:")
+ (magit-git-wash #'magit-diff-wash-diffs
+ "diff" "--cached" magit-diff-section-arguments "--no-prefix"
+ "--" magit-diff-section-file-args)))
+
+;;; Diff Type
+
+(defun magit-diff-type (&optional section)
+ "Return the diff type of SECTION.
+
+The returned type is one of the symbols `staged', `unstaged',
+`committed', or `undefined'. This type serves a similar purpose
+as the general type common to all sections (which is stored in
+the `type' slot of the corresponding `magit-section' struct) but
+takes additional information into account. When the SECTION
+isn't related to diffs and the buffer containing it also isn't
+a diff-only buffer, then return nil.
+
+Currently the type can also be one of `tracked' and `untracked'
+but these values are not handled explicitly everywhere they
+should be and a possible fix could be to just return nil here.
+
+The section has to be a `diff' or `hunk' section, or a section
+whose children are of type `diff'. If optional SECTION is nil,
+return the diff type for the current section. In buffers whose
+major mode is `magit-diff-mode' SECTION is ignored and the type
+is determined using other means. In `magit-revision-mode'
+buffers the type is always `committed'.
+
+Do not confuse this with `magit-diff-scope' (which see)."
+ (--when-let (or section (magit-current-section))
+ (cond ((derived-mode-p 'magit-revision-mode 'magit-stash-mode) 'committed)
+ ((derived-mode-p 'magit-diff-mode)
+ (let ((range (nth 0 magit-refresh-args))
+ (const (nth 1 magit-refresh-args)))
+ (cond ((member "--no-index" const) 'undefined)
+ ((not range)
+ (if (member "--cached" const)
+ 'staged
+ 'unstaged))
+ ((member "--cached" const)
+ (if (magit-rev-head-p range)
+ 'staged
+ 'undefined)) ; i.e. committed and staged
+ (t 'committed))))
+ ((derived-mode-p 'magit-status-mode)
+ (let ((stype (magit-section-type it)))
+ (if (memq stype '(staged unstaged tracked untracked))
+ stype
+ (pcase stype
+ (`file (let* ((parent (magit-section-parent it))
+ (type (magit-section-type parent)))
+ (if (eq type 'file)
+ (magit-diff-type parent)
+ type)))
+ (`hunk (-> it magit-section-parent magit-section-parent
+ magit-section-type))))))
+ ((derived-mode-p 'magit-log-mode)
+ (if (or (and (magit-section-match 'commit section)
+ (magit-section-children section))
+ (magit-section-match [* file commit] section))
+ 'committed
+ 'undefined))
+ (t 'undefined))))
+
+(cl-defun magit-diff-scope (&optional (section nil ssection) strict)
+ "Return the diff scope of SECTION or the selected section(s).
+
+A diff's \"scope\" describes what part of a diff is selected, it is
+a symbol, one of `region', `hunk', `hunks', `file', `files', or
+`list'. Do not confuse this with the diff \"type\", as returned by
+`magit-diff-type'.
+
+If optional SECTION is non-nil, then return the scope of that,
+ignoring the sections selected by the region. Otherwise return
+the scope of the current section, or if the region is active and
+selects a valid group of diff related sections, the type of these
+sections, i.e. `hunks' or `files'. If SECTION, or if that is nil
+the current section, is a `hunk' section; and the region region
+starts and ends inside the body of a that section, then the type
+is `region'. If the region is empty after a mouse click, then
+`hunk' is returned instead of `region'.
+
+If optional STRICT is non-nil then return nil if the diff type of
+the section at point is `untracked' or the section at point is not
+actually a `diff' but a `diffstat' section."
+ (let ((siblings (and (not ssection) (magit-region-sections))))
+ (setq section (or section (car siblings) (magit-current-section)))
+ (when (and section
+ (or (not strict)
+ (and (not (eq (magit-diff-type section) 'untracked))
+ (not (eq (--when-let (magit-section-parent section)
+ (magit-section-type it))
+ 'diffstat)))))
+ (pcase (list (magit-section-type section)
+ (and siblings t)
+ (magit-diff-use-hunk-region-p)
+ ssection)
+ (`(hunk nil t ,_)
+ (if (magit-section-internal-region-p section) 'region 'hunk))
+ (`(hunk t t nil) 'hunks)
+ (`(hunk ,_ ,_ ,_) 'hunk)
+ (`(file t t nil) 'files)
+ (`(file ,_ ,_ ,_) 'file)
+ (`(,(or `staged `unstaged `untracked)
+ nil ,_ ,_) 'list)))))
+
+(defun magit-diff-use-hunk-region-p ()
+ (and (region-active-p)
+ (not (and (if (version< emacs-version "25.1")
+ (eq this-command 'mouse-drag-region)
+ ;; TODO implement this from first principals
+ ;; currently it's trial-and-error
+ (or (eq this-command 'mouse-drag-region)
+ (eq last-command 'mouse-drag-region)
+ ;; When another window was previously
+ ;; selected then the last-command is
+ ;; some byte-code function.
+ (byte-code-function-p last-command)))
+ (eq (region-end) (region-beginning))))))
+
+;;; Diff Highlight
+
+(defun magit-diff-unhighlight (section selection)
+ "Remove the highlighting of the diff-related SECTION."
+ (when (eq (magit-section-type section) 'hunk)
+ (magit-diff-paint-hunk section selection nil)
+ t))
+
+(defun magit-diff-highlight (section selection)
+ "Highlight the diff-related SECTION and return t.
+If SECTION is not a diff-related section, then do nothing and
+return nil. If SELECTION is non-nil then it is a list of sections
+selected by the region, including SECTION. All of these sections
+are highlighted."
+ (if (and (magit-section-match 'commit section)
+ (magit-section-children section))
+ (progn (if selection
+ (dolist (section selection)
+ (magit-diff-highlight-list section selection))
+ (magit-diff-highlight-list section))
+ t)
+ (-when-let (scope (magit-diff-scope section t))
+ (cond ((eq scope 'region)
+ (magit-diff-paint-hunk section selection t))
+ (selection
+ (dolist (section selection)
+ (magit-diff-highlight-recursive section selection)))
+ (t
+ (magit-diff-highlight-recursive section)))
+ t)))
+
+(defun magit-diff-highlight-recursive (section &optional selection)
+ (pcase (magit-diff-scope section)
+ (`list (magit-diff-highlight-list section selection))
+ (`file (magit-diff-highlight-file section selection))
+ (`hunk (magit-diff-highlight-heading section selection)
+ (magit-diff-paint-hunk section selection t))
+ (_ (magit-section-highlight section nil))))
+
+(defun magit-diff-highlight-list (section &optional selection)
+ (let ((beg (magit-section-start section))
+ (cnt (magit-section-content section))
+ (end (magit-section-end section)))
+ (unless (and (region-active-p)
+ (= end (1+ (region-end))))
+ (magit-section-make-overlay beg cnt 'magit-section-highlight)
+ (unless (magit-section-hidden section)
+ (dolist (child (magit-section-children section))
+ (magit-diff-highlight-recursive child selection))))
+ (when magit-diff-highlight-hunk-body
+ (magit-section-make-overlay (1- end) end 'magit-section-highlight))))
+
+(defun magit-diff-highlight-file (section &optional selection)
+ (magit-diff-highlight-heading section selection)
+ (unless (magit-section-hidden section)
+ (dolist (child (magit-section-children section))
+ (magit-diff-highlight-recursive child selection))))
+
+(defun magit-diff-highlight-heading (section &optional selection)
+ (magit-section-make-overlay
+ (magit-section-start section)
+ (or (magit-section-content section)
+ (magit-section-end section))
+ (pcase (list (magit-section-type section)
+ (and (member section selection) t))
+ (`(file t) 'magit-diff-file-heading-selection)
+ (`(file nil) 'magit-diff-file-heading-highlight)
+ (`(hunk t) 'magit-diff-hunk-heading-selection)
+ (`(hunk nil) 'magit-diff-hunk-heading-highlight))))
+
+;;; Hunk Paint
+
+(cl-defun magit-diff-paint-hunk
+ (section &optional selection
+ (highlight (magit-section-selected-p section selection)))
+ (let (paint)
+ (unless magit-diff-highlight-hunk-body
+ (setq highlight nil))
+ (cond (highlight
+ (unless (magit-section-hidden section)
+ (add-to-list 'magit-section-highlighted-sections section)
+ (cond ((memq section magit-section-unhighlight-sections)
+ (setq magit-section-unhighlight-sections
+ (delq section magit-section-unhighlight-sections)))
+ (magit-diff-highlight-hunk-body
+ (setq paint t)))))
+ (t
+ (cond ((and (magit-section-hidden section)
+ (memq section magit-section-unhighlight-sections))
+ (add-to-list 'magit-section-highlighted-sections section)
+ (setq magit-section-unhighlight-sections
+ (delq section magit-section-unhighlight-sections)))
+ (t
+ (setq paint t)))))
+ (when paint
+ (save-excursion
+ (goto-char (magit-section-start section))
+ (let ((end (magit-section-end section))
+ (merging (looking-at "@@@"))
+ (stage nil))
+ (forward-line)
+ (while (< (point) end)
+ (when (and magit-diff-hide-trailing-cr-characters
+ (char-equal ?\r (char-before (line-end-position))))
+ (put-text-property (1- (line-end-position)) (line-end-position)
+ 'invisible t))
+ (put-text-property
+ (point) (1+ (line-end-position)) 'face
+ (cond
+ ((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}")
+ (setq stage (pcase (list (match-string 1) highlight)
+ (`("<" nil) 'magit-diff-our)
+ (`("<" t) 'magit-diff-our-highlight)
+ (`("|" nil) 'magit-diff-base)
+ (`("|" t) 'magit-diff-base-highlight)
+ (`("=" nil) 'magit-diff-their)
+ (`("=" t) 'magit-diff-their-highlight)
+ (`(">" nil) nil)))
+ 'magit-diff-conflict-heading)
+ ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+"))
+ (magit-diff-paint-whitespace merging)
+ (or stage
+ (if highlight 'magit-diff-added-highlight 'magit-diff-added)))
+ ((looking-at (if merging "^\\(-\\| -\\)" "^-"))
+ (if highlight 'magit-diff-removed-highlight 'magit-diff-removed))
+ (t
+ (if highlight 'magit-diff-context-highlight 'magit-diff-context))))
+ (forward-line))))))
+ (magit-diff-update-hunk-refinement section))
+
+(defun magit-diff-paint-whitespace (merging)
+ (when (and magit-diff-paint-whitespace
+ (or (derived-mode-p 'magit-status-mode)
+ (not (eq magit-diff-paint-whitespace 'status))))
+ (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+]"))
+ (indent
+ (if (local-variable-p 'magit-diff-highlight-indentation)
+ magit-diff-highlight-indentation
+ (setq-local
+ magit-diff-highlight-indentation
+ (cdr (--first (string-match-p (car it) default-directory)
+ (nreverse
+ (default-value
+ 'magit-diff-highlight-indentation))))))))
+ (when (and magit-diff-highlight-trailing
+ (looking-at (concat prefix ".*?\\([ \t]+\\)$")))
+ (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
+ (overlay-put ov 'face 'magit-diff-whitespace-warning)
+ (overlay-put ov 'evaporate t)))
+ (when (or (and (eq indent 'tabs)
+ (looking-at (concat prefix "\\( *\t[ \t]*\\)")))
+ (and (integerp indent)
+ (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)"
+ prefix indent))))
+ (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
+ (overlay-put ov 'face 'magit-diff-whitespace-warning)
+ (overlay-put ov 'evaporate t))))))
+
+(defun magit-diff-update-hunk-refinement (&optional section)
+ (if section
+ (unless (magit-section-hidden section)
+ (pcase (list magit-diff-refine-hunk
+ (magit-section-refined section)
+ (eq section (magit-current-section)))
+ ((or `(all nil ,_) `(t nil t))
+ (setf (magit-section-refined section) t)
+ (save-excursion
+ (goto-char (magit-section-start section))
+ ;; `diff-refine-hunk' does not handle combined diffs.
+ (unless (looking-at "@@@")
+ ;; Avoid fsyncing many small temp files
+ (let ((write-region-inhibit-fsync t))
+ (diff-refine-hunk)))))
+ ((or `(nil t ,_) `(t t nil))
+ (setf (magit-section-refined section) nil)
+ (remove-overlays (magit-section-start section)
+ (magit-section-end section)
+ 'diff-mode 'fine))))
+ (cl-labels ((recurse (section)
+ (if (magit-section-match 'hunk section)
+ (magit-diff-update-hunk-refinement section)
+ (--each (magit-section-children section)
+ (recurse it)))))
+ (recurse magit-root-section))))
+
+
+;;; Hunk Region
+
+(defun magit-diff-hunk-region-beginning ()
+ (save-excursion (goto-char (region-beginning))
+ (line-beginning-position)))
+
+(defun magit-diff-hunk-region-end ()
+ (save-excursion (goto-char (region-end))
+ (line-end-position)))
+
+(defun magit-diff-update-hunk-region (section)
+ (when (eq (magit-diff-scope section t) 'region)
+ (magit-diff--make-hunk-overlay
+ (magit-section-start section)
+ (1- (magit-section-content section))
+ 'face 'magit-diff-lines-heading
+ 'display (magit-diff-hunk-region-header section)
+ 'after-string (magit-diff--hunk-after-string 'magit-diff-lines-heading))
+ (run-hook-with-args 'magit-diff-highlight-hunk-region-functions section)
+ t))
+
+(defun magit-diff-highlight-hunk-region-dim-outside (section)
+ "Dim the parts of the hunk that are outside the hunk-internal region.
+This is done by using the same foreground and background color
+for added and removed lines as for context lines."
+ (let ((face (if magit-diff-highlight-hunk-body
+ 'magit-diff-context-highlight
+ 'magit-diff-context)))
+ (when magit-diff-unmarked-lines-keep-foreground
+ (setq face (list :background (face-attribute face :background))))
+ (magit-diff--make-hunk-overlay (magit-section-content section)
+ (magit-diff-hunk-region-beginning)
+ 'face face
+ 'priority 2)
+ (magit-diff--make-hunk-overlay (1+ (magit-diff-hunk-region-end))
+ (magit-section-end section)
+ 'face face
+ 'priority 2)))
+
+(defun magit-diff-highlight-hunk-region-using-face (_section)
+ "Highlight the hunk-internal region by making it bold.
+Or rather highlight using the face `magit-diff-hunk-region', though
+changing only the `:weight' and/or `:slant' is recommended for that
+face."
+ (magit-diff--make-hunk-overlay (magit-diff-hunk-region-beginning)
+ (1+ (magit-diff-hunk-region-end))
+ 'face 'magit-diff-hunk-region))
+
+(defun magit-diff-highlight-hunk-region-using-overlays (section)
+ "Emphasize the hunk-internal region using delimiting horizontal lines.
+This is implemented as single-pixel newlines places inside overlays.
+Although creating overlays containing newlines is discouraged,
+this version turns out to be less glitchy on Emacs 24 than the
+other method."
+ (if (window-system)
+ (let ((beg (magit-diff-hunk-region-beginning))
+ (end (magit-diff-hunk-region-end))
+ (str (propertize
+ (concat (propertize "\s" 'display '(space :height (1)))
+ (propertize "\n" 'line-height t))
+ 'face 'magit-diff-lines-boundary)))
+ (magit-diff--make-hunk-overlay beg (1+ beg) 'before-string str)
+ (magit-diff--make-hunk-overlay end (1+ end) 'after-string str))
+ (magit-diff-highlight-hunk-region-using-face section)))
+
+(defun magit-diff-highlight-hunk-region-using-underline (section)
+ "Emphasize the hunk-internal region using delimiting horizontal lines.
+This is implemented by overlining and underlining the first and
+last (visual) lines of the region. In Emacs 24, using this
+method causes `move-end-of-line' to jump to the next line, so
+we only use it in Emacs 25 where that glitch was fixed (see
+https://github.com/magit/magit/pull/2293 for more details)."
+ (if (window-system)
+ (let* ((beg (magit-diff-hunk-region-beginning))
+ (end (magit-diff-hunk-region-end))
+ (beg-eol (save-excursion (goto-char beg)
+ (end-of-visual-line)
+ (point)))
+ (end-bol (save-excursion (goto-char end)
+ (beginning-of-visual-line)
+ (point)))
+ (color (face-background 'magit-diff-lines-boundary nil t)))
+ (cl-flet ((ln (b e &rest face)
+ (magit-diff--make-hunk-overlay
+ b e 'face face 'after-string
+ (magit-diff--hunk-after-string face))))
+ (if (= beg end-bol)
+ (ln beg beg-eol :overline color :underline color)
+ (ln beg beg-eol :overline color)
+ (ln end-bol end :underline color))))
+ (magit-diff-highlight-hunk-region-using-face section)))
+
+(defun magit-diff--make-hunk-overlay (start end &rest args)
+ (let ((ov (make-overlay start end nil t)))
+ (overlay-put ov 'evaporate t)
+ (while args (overlay-put ov (pop args) (pop args)))
+ (push ov magit-region-overlays)
+ ov))
+
+(defun magit-diff--hunk-after-string (face)
+ (propertize "\s"
+ 'face face
+ 'display (list 'space :align-to
+ `(+ (0 . right)
+ ,(min (window-hscroll)
+ (- (line-end-position)
+ (line-beginning-position)))))
+ ;; This prevents the cursor from being rendered at the
+ ;; edge of the window.
+ 'cursor t))
+
+;;; Diff Extract
+
+(defun magit-diff-file-header (section)
+ (when (eq (magit-section-type section) 'hunk)
+ (setq section (magit-section-parent section)))
+ (when (eq (magit-section-type section) 'file)
+ (magit-section-diff-header section)))
+
+(defun magit-diff-hunk-region-header (section)
+ (let ((patch (magit-diff-hunk-region-patch section)))
+ (string-match "\n" patch)
+ (substring patch 0 (1- (match-end 0)))))
+
+(defun magit-diff-hunk-region-patch (section &optional args)
+ (let ((op (if (member "--reverse" args) "+" "-"))
+ (sbeg (magit-section-start section))
+ (rbeg (magit-diff-hunk-region-beginning))
+ (rend (region-end))
+ (send (magit-section-end section))
+ (patch nil))
+ (save-excursion
+ (goto-char sbeg)
+ (while (< (point) send)
+ (looking-at "\\(.\\)\\([^\n]*\n\\)")
+ (cond ((or (string-match-p "[@ ]" (match-string-no-properties 1))
+ (and (>= (point) rbeg)
+ (<= (point) rend)))
+ (push (match-string-no-properties 0) patch))
+ ((equal op (match-string-no-properties 1))
+ (push (concat " " (match-string-no-properties 2)) patch)))
+ (forward-line)))
+ (with-temp-buffer
+ (insert (mapconcat 'identity (reverse patch) ""))
+ (diff-fixup-modifs (point-min) (point-max))
+ (setq patch (buffer-string)))
+ patch))
+
+;;; magit-diff.el ends soon
+
+(make-obsolete-variable 'magit-diff-show-lines-boundary
+ 'magit-diff-highlight-hunk-region-functions
+ "Magit 2.9.0")
+
+(provide 'magit-diff)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-diff.el ends here
--- /dev/null
+;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library provides basic support for Ediff.
+
+;;; Code:
+
+(require 'magit)
+
+(require 'ediff)
+(require 'smerge-mode)
+
+(defvar smerge-ediff-buf)
+(defvar smerge-ediff-windows)
+
+(defgroup magit-ediff nil
+ "Ediff support for Magit."
+ :group 'magit-extensions)
+
+(unless (find-lisp-object-file-name 'magit-ediff-quit-hook 'defvar)
+ (add-hook 'magit-ediff-quit-hook 'magit-ediff-restore-previous-winconf)
+ (add-hook 'magit-ediff-quit-hook 'magit-ediff-cleanup-auxiliary-buffers))
+(defcustom magit-ediff-quit-hook
+ '(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.
+The `ediff-quit-hook' is ignored by Ediff sessions which were
+invoked using Magit."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-ediff
+ :type 'hook
+ :options '(magit-ediff-cleanup-auxiliary-buffers
+ magit-ediff-restore-previous-winconf))
+
+(defcustom magit-ediff-dwim-show-on-hunks nil
+ "Whether `magit-ediff-dwim' runs show variants on hunks.
+If non-nil, `magit-ediff-show-staged' or
+`magit-ediff-show-unstaged' are called based on what section the
+hunk is in. Otherwise, `magit-ediff-dwim' runs
+`magit-ediff-stage' when point is on an uncommitted hunk."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-ediff
+ :type 'boolean)
+
+(defcustom magit-ediff-show-stash-with-index t
+ "Whether `magit-ediff-show-stash' shows the state of the index.
+
+If non-nil, use a third Ediff buffer to distinguish which changes
+in the stash were staged. In cases where the stash contains no
+staged changes, fall back to a two-buffer Ediff.
+
+More specificaly, a stash is a merge commit, stash@{N}, with
+potentially three parents.
+
+* stash@{N}^1 represents the HEAD commit at the time the stash
+ was created.
+
+* stash@{N}^2 records any changes that were staged when the stash
+ was made.
+
+* stash@{N}^3, if it exists, contains files that were untracked
+ when stashing.
+
+If this option is non-nil, `magit-ediff-show-stash' will run
+Ediff on a file using three buffers: one for stash@{N}, another
+for stash@{N}^1, and a third for stash@{N}^2.
+
+Otherwise, Ediff uses two buffers, comparing
+stash@{N}^1..stash@{N}. Along with any unstaged changes, changes
+in the index commit, stash@{N}^2, will be shown in this
+comparison unless they conflicted with changes in the working
+tree at the time of stashing."
+ :package-version '(magit . "2.6.0")
+ :group 'magit-ediff
+ :type 'boolean)
+
+(defvar magit-ediff-previous-winconf nil)
+
+;;;###autoload (autoload 'magit-ediff-popup "magit-ediff" nil t)
+(magit-define-popup magit-ediff-popup
+ "Popup console for ediff commands."
+ 'magit-diff nil nil
+ :actions '((?E "Dwim" magit-ediff-dwim)
+ (?u "Show unstaged" magit-ediff-show-unstaged)
+ (?s "Stage" magit-ediff-stage)
+ (?i "Show staged" magit-ediff-show-staged)
+ (?m "Resolve" magit-ediff-resolve)
+ (?w "Show worktree" magit-ediff-show-working-tree)
+ (?r "Diff range" magit-ediff-compare)
+ (?c "Show commit" magit-ediff-show-commit) nil
+ (?z "Show stash" magit-ediff-show-stash))
+ :max-action-columns 2)
+
+;;;###autoload
+(defun magit-ediff-resolve (file)
+ "Resolve outstanding conflicts in FILE using Ediff.
+FILE has to be relative to the top directory of the repository.
+
+In the rare event that you want to manually resolve all
+conflicts, including those already resolved by Git, use
+`ediff-merge-revisions-with-ancestor'."
+ (interactive
+ (let ((current (magit-current-file))
+ (unmerged (magit-unmerged-files)))
+ (unless unmerged
+ (user-error "There are no unresolved conflicts"))
+ (list (magit-completing-read "Resolve file" unmerged nil t nil nil
+ (car (member current unmerged))))))
+ (magit-with-toplevel
+ (with-current-buffer (find-file-noselect file)
+ (smerge-ediff)
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ (let ((bufC ediff-buffer-C)
+ (bufS smerge-ediff-buf))
+ (with-current-buffer bufS
+ (when (yes-or-no-p (format "Conflict resolution finished; save %s?"
+ buffer-file-name))
+ (erase-buffer)
+ (insert-buffer-substring bufC)
+ (save-buffer))))
+ (when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A))
+ (when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B))
+ (when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C))
+ (when (buffer-live-p ediff-ancestor-buffer)
+ (kill-buffer ediff-ancestor-buffer))
+ (let ((magit-ediff-previous-winconf smerge-ediff-windows))
+ (run-hooks 'magit-ediff-quit-hook)))))))
+
+;;;###autoload
+(defun magit-ediff-stage (file)
+ "Stage and unstage changes to FILE using Ediff.
+FILE has to be relative to the top directory of the repository."
+ (interactive
+ (list (magit-completing-read "Selectively stage file" nil
+ (magit-tracked-files) nil nil nil
+ (magit-current-file))))
+ (magit-with-toplevel
+ (let* ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer "HEAD" file))
+ (bufB (get-buffer (concat file ".~{index}~")))
+ (bufBrw (and bufB (with-current-buffer bufB (not buffer-read-only))))
+ (bufC (get-file-buffer file))
+ (fileBufC (or bufC (find-file-noselect file)))
+ (coding-system-for-read
+ (with-current-buffer fileBufC buffer-file-coding-system)))
+ (ediff-buffers3
+ (or bufA (magit-find-file-noselect "HEAD" file))
+ (with-current-buffer (magit-find-file-index-noselect file t)
+ (setq buffer-read-only nil)
+ (current-buffer))
+ fileBufC
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ (and (buffer-live-p ediff-buffer-B)
+ (buffer-modified-p ediff-buffer-B)
+ (with-current-buffer ediff-buffer-B
+ (magit-update-index)))
+ (and (buffer-live-p ediff-buffer-C)
+ (buffer-modified-p ediff-buffer-C)
+ (with-current-buffer ediff-buffer-C
+ (when (y-or-n-p
+ (format "Save file %s? " buffer-file-name))
+ (save-buffer))))
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(if bufB
+ (unless bufBrw '((with-current-buffer ediff-buffer-B
+ (setq buffer-read-only t))))
+ '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ ,@(unless bufC '((ediff-kill-buffer-carefully ediff-buffer-C)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers3))))
+
+;;;###autoload
+(defun magit-ediff-compare (revA revB fileA fileB)
+ "Compare REVA:FILEA with REVB:FILEB using Ediff.
+
+FILEA and FILEB have to be relative to the top directory of the
+repository. If REVA or REVB is nil then this stands for the
+working tree state.
+
+If the region is active, use the revisions on the first and last
+line of the region. With a prefix argument, instead of diffing
+the revisions, choose a revision to view changes along, starting
+at the common ancestor of both revisions (i.e., use a \"...\"
+range)."
+ (interactive (-let [(revA revB) (magit-ediff-compare--read-revisions
+ nil current-prefix-arg)]
+ (nconc (list revA revB)
+ (magit-ediff-read-files revA revB))))
+ (magit-with-toplevel
+ (let ((conf (current-window-configuration))
+ (bufA (if revA
+ (magit-get-revision-buffer revA fileA)
+ (get-file-buffer fileA)))
+ (bufB (if revB
+ (magit-get-revision-buffer revB fileB)
+ (get-file-buffer fileB))))
+ (ediff-buffers
+ (or bufA (if revA
+ (magit-find-file-noselect revA fileA)
+ (find-file-noselect fileA)))
+ (or bufB (if revB
+ (magit-find-file-noselect revB fileB)
+ (find-file-noselect fileB)))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-revision))))
+
+(defun magit-ediff-compare--read-revisions (&optional arg mbase)
+ (let ((input (or arg (magit-diff-read-range-or-commit
+ "Compare range or commit"
+ nil mbase))))
+ (--if-let (magit-split-range input)
+ (-cons-to-list it)
+ (list input nil))))
+
+(defun magit-ediff-read-files (revA revB &optional fileB)
+ "Read file in REVB, return it and the corresponding file in REVA.
+When FILEB is non-nil, use this as REVB's file instead of
+prompting for it."
+ (unless fileB
+ (setq fileB (magit-read-file-choice
+ (format "File to compare between %s and %s"
+ revA (or revB "the working tree"))
+ (magit-changed-files revA revB)
+ (format "No changed files between %s and %s"
+ revA (or revB "the working tree")))))
+ (list (or (car (member fileB (magit-revision-files revA)))
+ (cdr (assoc fileB (magit-renamed-files revB revA)))
+ (magit-read-file-choice
+ (format "File in %s to compare with %s in %s"
+ revA fileB (or revB "the working tree"))
+ (magit-changed-files revB revA)
+ (format "No files have changed between %s and %s"
+ revA revB)))
+ fileB))
+
+;;;###autoload
+(defun magit-ediff-dwim ()
+ "Compare, stage, or resolve using Ediff.
+This command tries to guess what file, and what commit or range
+the user wants to compare, stage, or resolve using Ediff. It
+might only be able to guess either the file, or range or commit,
+in which case the user is asked about the other. It might not
+always guess right, in which case the appropriate `magit-ediff-*'
+command has to be used explicitly. If it cannot read the user's
+mind at all, then it asks the user for a command to run."
+ (interactive)
+ (magit-section-case
+ (hunk (save-excursion
+ (goto-char (magit-section-start (magit-section-parent it)))
+ (magit-ediff-dwim)))
+ (t
+ (let ((range (magit-diff--dwim))
+ (file (magit-current-file))
+ command revA revB)
+ (pcase range
+ ((and (guard (not magit-ediff-dwim-show-on-hunks))
+ (or `unstaged `staged))
+ (setq command (if (magit-anything-unmerged-p)
+ #'magit-ediff-resolve
+ #'magit-ediff-stage)))
+ (`unstaged (setq command #'magit-ediff-show-unstaged))
+ (`staged (setq command #'magit-ediff-show-staged))
+ (`(commit . ,value)
+ (setq command #'magit-ediff-show-commit
+ revB value))
+ (`(stash . ,value)
+ (setq command #'magit-ediff-show-stash
+ revB value))
+ ((pred stringp)
+ (-let [(a b) (magit-ediff-compare--read-revisions range)]
+ (setq command #'magit-ediff-compare
+ revA a
+ revB b)))
+ (_
+ (when (derived-mode-p 'magit-diff-mode)
+ (pcase (magit-diff-type)
+ (`committed (-let [(a b) (magit-ediff-compare--read-revisions
+ (car magit-refresh-args))]
+ (setq revA a revB b)))
+ ((guard (not magit-ediff-dwim-show-on-hunks))
+ (setq command #'magit-ediff-stage))
+ (`unstaged (setq command #'magit-ediff-show-unstaged))
+ (`staged (setq command #'magit-ediff-show-staged))
+ (`undefined (setq command nil))
+ (_ (setq command nil))))))
+ (cond ((not command)
+ (call-interactively
+ (magit-read-char-case
+ "Failed to read your mind; do you want to " t
+ (?c "[c]ommit" 'magit-ediff-show-commit)
+ (?r "[r]ange" 'magit-ediff-compare)
+ (?s "[s]tage" 'magit-ediff-stage)
+ (?v "resol[v]e" 'magit-ediff-resolve))))
+ ((eq command 'magit-ediff-compare)
+ (apply 'magit-ediff-compare revA revB
+ (magit-ediff-read-files revA revB file)))
+ ((eq command 'magit-ediff-show-commit)
+ (magit-ediff-show-commit revB))
+ ((eq command 'magit-ediff-show-stash)
+ (magit-ediff-show-stash revB))
+ (file
+ (funcall command file))
+ (t
+ (call-interactively command)))))))
+
+;;;###autoload
+(defun magit-ediff-show-staged (file)
+ "Show staged changes using Ediff.
+
+This only allows looking at the changes; to stage, unstage,
+and discard changes using Ediff, use `magit-ediff-stage'.
+
+FILE must be relative to the top directory of the repository."
+ (interactive
+ (list (magit-read-file-choice "Show staged changes for file"
+ (magit-staged-files)
+ "No staged files")))
+ (let ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer "HEAD" file))
+ (bufB (get-buffer (concat file ".~{index}~"))))
+ (ediff-buffers
+ (or bufA (magit-find-file-noselect "HEAD" file))
+ (or bufB (magit-find-file-index-noselect file t))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers)))
+
+;;;###autoload
+(defun magit-ediff-show-unstaged (file)
+ "Show unstaged changes using Ediff.
+
+This only allows looking at the changes; to stage, unstage,
+and discard changes using Ediff, use `magit-ediff-stage'.
+
+FILE must be relative to the top directory of the repository."
+ (interactive
+ (list (magit-read-file-choice "Show unstaged changes for file"
+ (magit-modified-files)
+ "No unstaged files")))
+ (magit-with-toplevel
+ (let ((conf (current-window-configuration))
+ (bufA (get-buffer (concat file ".~{index}~")))
+ (bufB (get-file-buffer file)))
+ (ediff-buffers
+ (or bufA (magit-find-file-index-noselect file t))
+ (or bufB (find-file-noselect file))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers))))
+
+;;;###autoload
+(defun magit-ediff-show-working-tree (file)
+ "Show changes between HEAD and working tree using Ediff.
+FILE must be relative to the top directory of the repository."
+ (interactive
+ (list (magit-read-file-choice "Show changes in file"
+ (magit-changed-files "HEAD")
+ "No changed files")))
+ (magit-with-toplevel
+ (let ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer "HEAD" file))
+ (bufB (get-file-buffer file)))
+ (ediff-buffers
+ (or bufA (magit-find-file-noselect "HEAD" file))
+ (or bufB (find-file-noselect file))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers))))
+
+;;;###autoload
+(defun magit-ediff-show-commit (commit)
+ "Show changes introduced by COMMIT using Ediff."
+ (interactive (list (magit-read-branch-or-commit "Revision")))
+ (let ((revA (concat commit "^"))
+ (revB commit))
+ (apply #'magit-ediff-compare
+ revA revB
+ (magit-ediff-read-files revA revB (magit-current-file)))))
+
+;;;###autoload
+(defun magit-ediff-show-stash (stash)
+ "Show changes introduced by STASH using Ediff.
+`magit-ediff-show-stash-with-index' controls whether a
+three-buffer Ediff is used in order to distinguish changes in the
+stash that were staged."
+ (interactive (list (magit-read-stash "Stash")))
+ (-let* ((revA (concat stash "^1"))
+ (revB (concat stash "^2"))
+ (revC stash)
+ ((fileA fileC) (magit-ediff-read-files revA revC))
+ (fileB fileC))
+ (if (and magit-ediff-show-stash-with-index
+ (member fileA (magit-changed-files revB revA)))
+ (let ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer revA fileA))
+ (bufB (magit-get-revision-buffer revB fileB))
+ (bufC (magit-get-revision-buffer revC fileC)))
+ (ediff-buffers3
+ (or bufA (magit-find-file-noselect revA fileA))
+ (or bufB (magit-find-file-noselect revB fileB))
+ (or bufC (magit-find-file-noselect revC fileC))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA
+ '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB
+ '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ ,@(unless bufC
+ '((ediff-kill-buffer-carefully ediff-buffer-C)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers3))
+ (magit-ediff-compare revA revC fileA fileC))))
+
+(defun magit-ediff-cleanup-auxiliary-buffers ()
+ (let* ((ctl-buf ediff-control-buffer)
+ (ctl-win (ediff-get-visible-buffer-window ctl-buf))
+ (ctl-frm ediff-control-frame)
+ (main-frame (cond ((window-live-p ediff-window-A)
+ (window-frame ediff-window-A))
+ ((window-live-p ediff-window-B)
+ (window-frame ediff-window-B)))))
+ (ediff-kill-buffer-carefully ediff-diff-buffer)
+ (ediff-kill-buffer-carefully ediff-custom-diff-buffer)
+ (ediff-kill-buffer-carefully ediff-fine-diff-buffer)
+ (ediff-kill-buffer-carefully ediff-tmp-buffer)
+ (ediff-kill-buffer-carefully ediff-error-buffer)
+ (ediff-kill-buffer-carefully ediff-msg-buffer)
+ (ediff-kill-buffer-carefully ediff-debug-buffer)
+ (when (boundp 'ediff-patch-diagnostics)
+ (ediff-kill-buffer-carefully ediff-patch-diagnostics))
+ (cond ((and (ediff-window-display-p)
+ (frame-live-p ctl-frm))
+ (delete-frame ctl-frm))
+ ((window-live-p ctl-win)
+ (delete-window ctl-win)))
+ (unless (ediff-multiframe-setup-p)
+ (ediff-kill-bottom-toolbar))
+ (ediff-kill-buffer-carefully ctl-buf)
+ (when (frame-live-p main-frame)
+ (select-frame main-frame))))
+
+(defun magit-ediff-restore-previous-winconf ()
+ (set-window-configuration magit-ediff-previous-winconf))
+
+;;; magit-ediff.el ends soon
+(provide 'magit-ediff)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-ediff.el ends here
--- /dev/null
+;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Additional functionality for Magit.
+
+;;; Code:
+
+(require 'magit)
+
+(defgroup magit-extras nil
+ "Additional functionality for Magit."
+ :group 'magit-extensions)
+
+;;; External Tools
+
+(defcustom magit-gitk-executable
+ (or (and (eq system-type 'windows-nt)
+ (let ((exe (expand-file-name
+ "gitk" (file-name-nondirectory magit-git-executable))))
+ (and (file-executable-p exe) exe)))
+ (executable-find "gitk") "gitk")
+ "The Gitk executable."
+ :group 'magit-extras
+ :set-after '(magit-git-executable)
+ :type 'string)
+
+;;;###autoload
+(defun magit-run-git-gui ()
+ "Run `git gui' for the current git repository."
+ (interactive)
+ (magit-with-toplevel
+ (call-process magit-git-executable nil 0 nil "gui")))
+
+;;;###autoload
+(defun magit-run-git-gui-blame (commit filename &optional linenum)
+ "Run `git gui blame' on the given FILENAME and COMMIT.
+Interactively run it for the current file and the HEAD, with a
+prefix or when the current file cannot be determined let the user
+choose. When the current buffer is visiting FILENAME instruct
+blame to center around the line point is on."
+ (interactive
+ (let (revision filename)
+ (when (or current-prefix-arg
+ (not (setq revision "HEAD"
+ filename (magit-file-relative-name nil 'tracked))))
+ (setq revision (magit-read-branch-or-commit "Blame from revision")
+ filename (magit-read-file-from-rev revision "Blame file")))
+ (list revision filename
+ (and (equal filename
+ (ignore-errors
+ (magit-file-relative-name buffer-file-name)))
+ (line-number-at-pos)))))
+ (magit-with-toplevel
+ (apply #'call-process magit-git-executable nil 0 nil "gui" "blame"
+ `(,@(and linenum (list (format "--line=%d" linenum)))
+ ,commit
+ ,filename))))
+
+;;;###autoload
+(defun magit-run-gitk ()
+ "Run `gitk' in the current repository."
+ (interactive)
+ (call-process magit-gitk-executable nil 0))
+
+;;;###autoload
+(defun magit-run-gitk-branches ()
+ "Run `gitk --branches' in the current repository."
+ (interactive)
+ (call-process magit-gitk-executable nil 0 nil "--branches"))
+
+;;;###autoload
+(defun magit-run-gitk-all ()
+ "Run `gitk --all' in the current repository."
+ (interactive)
+ (call-process magit-gitk-executable nil 0 nil "--all"))
+
+;;; Clean
+
+;;;###autoload
+(defun magit-clean (&optional arg)
+ "Remove untracked files from the working tree.
+With a prefix argument also remove ignored files,
+with two prefix arguments remove ignored files only.
+\n(git clean -f -d [-x|-X])"
+ (interactive "p")
+ (when (yes-or-no-p (format "Remove %s files? "
+ (pcase arg
+ (1 "untracked")
+ (4 "untracked and ignored")
+ (_ "ignored"))))
+ (magit-wip-commit-before-change)
+ (magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X")))))
+
+(put 'magit-clean 'disabled t)
+
+;;; Gitignore
+
+;;;###autoload
+(defun magit-gitignore (file-or-pattern &optional local)
+ "Instruct Git to ignore FILE-OR-PATTERN.
+With a prefix argument only ignore locally."
+ (interactive (list (magit-gitignore-read-pattern current-prefix-arg)
+ current-prefix-arg))
+ (let ((gitignore
+ (if local
+ (magit-git-dir (convert-standard-filename "info/exclude"))
+ (expand-file-name ".gitignore" (magit-toplevel)))))
+ (make-directory (file-name-directory gitignore) t)
+ (with-temp-buffer
+ (when (file-exists-p gitignore)
+ (insert-file-contents gitignore))
+ (goto-char (point-max))
+ (unless (bolp)
+ (insert "\n"))
+ (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" file-or-pattern))
+ (insert "\n")
+ (write-region nil nil gitignore))
+ (if local
+ (magit-refresh)
+ (magit-run-git "add" ".gitignore"))))
+
+;;;###autoload
+(defun magit-gitignore-locally (file-or-pattern)
+ "Instruct Git to locally ignore FILE-OR-PATTERN."
+ (interactive (list (magit-gitignore-read-pattern t)))
+ (magit-gitignore file-or-pattern t))
+
+(defun magit-gitignore-read-pattern (local)
+ (let* ((default (magit-current-file))
+ (choices
+ (delete-dups
+ (--mapcat
+ (cons (concat "/" it)
+ (-when-let (ext (file-name-extension it))
+ (list (concat "/" (file-name-directory "foo") "*." ext)
+ (concat "*." ext))))
+ (magit-untracked-files)))))
+ (when default
+ (setq default (concat "/" default))
+ (unless (member default choices)
+ (setq default (concat "*." (file-name-extension default)))
+ (unless (member default choices)
+ (setq default nil))))
+ (magit-completing-read (concat "File or pattern to ignore"
+ (and local " locally"))
+ choices nil nil nil nil default)))
+
+;;; ChangeLog
+
+;;;###autoload
+(defun magit-add-change-log-entry (&optional whoami file-name other-window)
+ "Find change log file and add date entry and item for current change.
+This differs from `add-change-log-entry' (which see) in that
+it acts on the current hunk in a Magit buffer instead of on
+a position in a file-visiting buffer."
+ (interactive (list current-prefix-arg
+ (prompt-for-change-log-name)))
+ (let (buf pos)
+ (save-window-excursion
+ (call-interactively #'magit-diff-visit-file)
+ (setq buf (current-buffer)
+ pos (point)))
+ (save-excursion
+ (with-current-buffer buf
+ (goto-char pos)
+ (add-change-log-entry whoami file-name other-window)))))
+
+;;;###autoload
+(defun magit-add-change-log-entry-other-window (&optional whoami file-name)
+ "Find change log file in other window and add entry and item.
+This differs from `add-change-log-entry-other-window' (which see)
+in that it acts on the current hunk in a Magit buffer instead of
+on a position in a file-visiting buffer."
+ (interactive (and current-prefix-arg
+ (list current-prefix-arg
+ (prompt-for-change-log-name))))
+ (magit-add-change-log-entry whoami file-name t))
+
+;;; magit-extras.el ends soon
+(provide 'magit-extras)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-extras.el ends here
--- /dev/null
+;;; magit-git.el --- Git functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements wrappers for various Git plumbing commands.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+
+(require 'magit-utils)
+(require 'magit-section)
+
+(declare-function magit-process-buffer 'magit-process)
+(declare-function magit-process-file 'magit-process)
+(declare-function magit-process-insert-section 'magit-process)
+(defvar magit-process-error-message-re)
+(defvar magit-refresh-args) ; from `magit-mode' for `magit-current-file'
+(defvar magit-branch-prefer-remote-upstream)
+
+(defvar magit-tramp-process-environment nil)
+
+(require 'crm)
+
+;;; Options
+
+;; For now this is shared between `magit-process' and `magit-git'.
+(defgroup magit-process nil
+ "Git and other external processes used by Magit."
+ :group 'magit)
+
+(defvar magit-git-environment
+ (list (format "INSIDE_EMACS=%s,magit" emacs-version))
+ "Prepended to `process-environment' while running git.")
+
+(defcustom magit-git-executable
+ ;; Git might be installed in a different location on a remote, so
+ ;; it is better not to use the full path to the executable, except
+ ;; on Window were we would otherwise end up using one one of the
+ ;; wrappers "cmd/git.exe" or "cmd/git.cmd", which are much slower
+ ;; than using "bin/git.exe" directly.
+ (or (and (eq system-type 'windows-nt)
+ (--when-let (executable-find "git")
+ (or (ignore-errors
+ ;; Git for Windows 2.x provides cygpath so we can
+ ;; ask it for native paths. Using an upper case
+ ;; alias makes this fail on 1.x (which is good,
+ ;; because we would not want to end up using some
+ ;; other cygpath).
+ (prog1 (car
+ (process-lines
+ it "-c"
+ "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
+ "X" "git"))
+ (setq magit-git-environment
+ (cons (concat "PATH="
+ (car (process-lines
+ it "-c"
+ "alias.P=!cygpath -wp \"$PATH\""
+ "P")))
+ magit-git-environment))))
+ ;; For 1.x, we search for bin/ next to cmd/.
+ (let ((alt (directory-file-name (file-name-directory it))))
+ (if (and (equal (file-name-nondirectory alt) "cmd")
+ (setq alt (expand-file-name
+ (convert-standard-filename "bin/git.exe")
+ (file-name-directory alt)))
+ (file-executable-p alt))
+ alt
+ it)))))
+ "git")
+ "The Git executable used by Magit."
+ :group 'magit-process
+ :type 'string)
+
+(defcustom magit-git-global-arguments
+ `("--no-pager" "--literal-pathspecs" "-c" "core.preloadindex=true"
+ ,@(and (eq system-type 'windows-nt)
+ (list "-c" "i18n.logOutputEncoding=UTF-8")))
+ "Global git arguments.
+
+The arguments set here are used every time the git executable is
+run as a subprocess. They are placed right after the executable
+itself and before the git command - as in `git HERE... COMMAND
+REST'. See the manpage `git(1)' for valid arguments.
+
+Be careful what you add here, especially if you are using Tramp
+to connect to servers with ancient Git versions. Never remove
+anything that is part of the default value, unless you really
+know what you are doing. And think very hard before adding
+something; it will be used every time Magit runs Git for any
+purpose."
+ :package-version '(magit . "2.9.0")
+ :group 'magit
+ :group 'magit-process
+ :type '(repeat string))
+
+(defcustom magit-git-debug nil
+ "Whether to enable additional reporting of git errors.
+
+Magit basically calls git for one of these two reasons: for
+side-effects or to do something with its standard output.
+
+When git is run for side-effects then its output, including error
+messages, go into the process buffer which is shown when using \
+\\<magit-status-mode-map>\\[magit-process].
+
+When git's output is consumed in some way, then it would be too
+expensive to also insert it into this buffer, but when this
+option is non-nil and git returns with a non-zero exit status,
+then at least its standard error is inserted into this buffer.
+
+This is only intended for debugging purposes. Do not enable this
+permanently, that would negatively affect performance"
+ :group 'magit
+ :group 'magit-process
+ :type 'boolean)
+
+(defcustom magit-ref-namespaces
+ '(("^@$" magit-head nil)
+ ("^refs/tags/\\(.+\\)" magit-tag nil)
+ ("^refs/heads/\\(.+\\)" magit-branch-local nil)
+ ("^refs/remotes/\\(.+\\)" magit-branch-remote nil)
+ ("^refs/bisect/\\(bad\\)" magit-bisect-bad nil)
+ ("^refs/bisect/\\(skip.*\\)" magit-bisect-skip nil)
+ ("^refs/bisect/\\(good.*\\)" magit-bisect-good nil)
+ ("^refs/stash$" magit-refname-stash nil)
+ ("^refs/wip/\\(.+\\)" magit-refname-wip nil)
+ ("^\\(bad\\):" magit-bisect-bad nil)
+ ("^\\(skip\\):" magit-bisect-skip nil)
+ ("^\\(good\\):" magit-bisect-good nil)
+ ("\\(.+\\)" magit-refname nil))
+ "How refs are formatted for display.
+
+Each entry controls how a certain type of ref is displayed, and
+has the form (REGEXP FACE FORMATTER). REGEXP is a regular
+expression used to match full refs. The first entry whose REGEXP
+matches the reference is used. The first regexp submatch becomes
+the \"label\" that represents the ref and is propertized with
+font FONT. If FORMATTER is non-nil it should be a function that
+takes two arguments, the full ref and the face. It is supposed
+to return a propertized label that represents the ref."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-modes
+ :type '(repeat
+ (list regexp
+ face
+ (choice (const :tag "first submatch is label" nil)
+ (function :tag "format using function")))))
+
+(defcustom magit-prefer-remote-upstream nil
+ "Whether to favor remote branches when reading the upstream branch.
+
+This controls whether commands that read a branch from the user
+and then set it as the upstream branch, offer a local or a remote
+branch as default completion candidate, when they have the choice.
+
+This affects all commands that use `magit-read-upstream-branch'
+or `magit-read-starting-point', which includes all commands that
+change the upstream and many which create new branches."
+ :package-version '(magit . "2.4.2")
+ :group 'magit-commands
+ :type 'boolean)
+
+;;; Git
+
+(defvar magit--refresh-cache nil)
+
+(defmacro magit--with-refresh-cache (key &rest body)
+ (declare (indent 1) (debug (form body)))
+ (let ((k (cl-gensym)))
+ `(if magit--refresh-cache
+ (let ((,k ,key))
+ (--if-let (assoc ,k (cdr magit--refresh-cache))
+ (progn (cl-incf (caar magit--refresh-cache))
+ (cdr it))
+ (cl-incf (cdar magit--refresh-cache))
+ (let ((value ,(macroexp-progn body)))
+ (push (cons ,k value)
+ (cdr magit--refresh-cache))
+ value)))
+ ,@body)))
+
+(defmacro magit-with-editor (&rest body)
+ "Like `with-editor' but let-bind some more variables."
+ (declare (indent 0) (debug (body)))
+ `(let ((magit-process-popup-time -1)
+ ;; The user may have customized `shell-file-name' to
+ ;; something which results in `w32-shell-dos-semantics' nil
+ ;; (which changes the quoting style used by
+ ;; `shell-quote-argument'), but Git for Windows expects shell
+ ;; quoting in the dos style.
+ (shell-file-name (if (and (eq system-type 'windows-nt)
+ ;; If we have Cygwin mount points
+ ;; the git flavor is cygwin, so dos
+ ;; shell quoting is probably wrong.
+ (not magit-cygwin-mount-points))
+ "cmdproxy"
+ shell-file-name)))
+ (with-editor "GIT_EDITOR"
+ ,@body)))
+
+(defun magit-process-git-arguments (args)
+ "Prepare ARGS for a function that invokes Git.
+
+Magit has many specialized functions for running Git; they all
+pass arguments through this function before handing them to Git,
+to do the following.
+
+* Flatten ARGS, removing nil arguments.
+* Prepend `magit-git-global-arguments' to ARGS."
+ (append magit-git-global-arguments (-flatten args)))
+
+(defun magit-git-exit-code (&rest args)
+ "Execute Git with ARGS, returning its exit code."
+ (apply #'magit-process-file magit-git-executable nil nil nil
+ (magit-process-git-arguments args)))
+
+(defun magit-git-success (&rest args)
+ "Execute Git with ARGS, returning t if its exit code is 0."
+ (= (magit-git-exit-code args) 0))
+
+(defun magit-git-failure (&rest args)
+ "Execute Git with ARGS, returning t if its exit code is 1."
+ (= (magit-git-exit-code args) 1))
+
+(defun magit-git-str (&rest args)
+ "Execute Git with ARGS, returning the first line of its output.
+If there is no output return nil. If the output begins with a
+newline return an empty string. Like `magit-git-string' but
+ignore `magit-git-debug'."
+ (setq args (-flatten args))
+ (magit--with-refresh-cache (cons default-directory args)
+ (with-temp-buffer
+ (apply #'magit-process-file magit-git-executable nil (list t nil) nil
+ (magit-process-git-arguments args))
+ (unless (bobp)
+ (goto-char (point-min))
+ (buffer-substring-no-properties (point) (line-end-position))))))
+
+(defun magit-git-true (&rest args)
+ "Execute Git with ARGS, returning t if it prints \"true\".
+Return t if the first (and usually only) output line is the
+string \"true\", otherwise return nil."
+ (equal (magit-git-str args) "true"))
+
+(defun magit-git-false (&rest args)
+ "Execute Git with ARGS, returning t if it prints \"false\".
+Return t if the first (and usually only) output line is the
+string \"false\", otherwise return nil."
+ (equal (magit-git-str args) "false"))
+
+(defun magit-git-insert (&rest args)
+ "Execute Git with ARGS, inserting its output at point.
+If Git exits with a non-zero exit status, then show a message and
+add a section in the respective process buffer."
+ (setq args (magit-process-git-arguments args))
+ (if magit-git-debug
+ (let (log)
+ (unwind-protect
+ (progn
+ (setq log (make-temp-file "magit-stderr"))
+ (delete-file log)
+ (let ((exit (apply #'magit-process-file magit-git-executable
+ nil (list t log) nil args)))
+ (when (> exit 0)
+ (let ((msg "Git failed"))
+ (when (file-exists-p log)
+ (setq msg (with-temp-buffer
+ (insert-file-contents log)
+ (goto-char (point-max))
+ (and (re-search-backward
+ magit-process-error-message-re nil t)
+ (match-string 1))))
+ (let ((magit-git-debug nil))
+ (with-current-buffer (magit-process-buffer t)
+ (magit-process-insert-section default-directory
+ magit-git-executable
+ args exit log))))
+ (message "%s" msg)))
+ exit))
+ (ignore-errors (delete-file log))))
+ (apply #'magit-process-file magit-git-executable
+ nil (list t nil) nil args)))
+
+(defun magit-git-string (&rest args)
+ "Execute Git with ARGS, returning the first line of its output.
+If there is no output return nil. If the output begins with a
+newline return an empty string."
+ (setq args (-flatten args))
+ (magit--with-refresh-cache (cons default-directory args)
+ (with-temp-buffer
+ (apply #'magit-git-insert args)
+ (unless (bobp)
+ (goto-char (point-min))
+ (buffer-substring-no-properties (point) (line-end-position))))))
+
+(defun magit-git-lines (&rest args)
+ "Execute Git with ARGS, returning its output as a list of lines.
+Empty lines anywhere in the output are omitted.
+
+If Git exits with a non-zero exit status, then report show a
+message and add a section in the respective process buffer."
+ (with-temp-buffer
+ (apply #'magit-git-insert args)
+ (split-string (buffer-string) "\n" t)))
+
+(defun magit-git-items (&rest args)
+ "Execute Git with ARGS, returning its null-separated output as a list.
+Empty items anywhere in the output are omitted.
+
+If Git exits with a non-zero exit status, then report show a
+message and add a section in the respective process buffer."
+ (with-temp-buffer
+ (apply #'magit-git-insert args)
+ (split-string (buffer-string) "\0" t)))
+
+(defun magit-git-wash (washer &rest args)
+ "Execute Git with ARGS, inserting washed output at point.
+Actually first insert the raw output at point. If there is no
+output call `magit-cancel-section'. Otherwise temporarily narrow
+the buffer to the inserted text, move to its beginning, and then
+call function WASHER with no argument."
+ (declare (indent 1))
+ (let ((beg (point)))
+ (setq args (-flatten args))
+ (magit-git-insert args)
+ (if (= (point) beg)
+ (magit-cancel-section)
+ (unless (bolp)
+ (insert "\n"))
+ (save-restriction
+ (narrow-to-region beg (point))
+ (goto-char beg)
+ (funcall washer args))
+ (when (or (= (point) beg)
+ (= (point) (1+ beg)))
+ (magit-cancel-section)))))
+
+(defun magit-git-version (&optional raw)
+ (--when-let (let (magit-git-global-arguments)
+ (ignore-errors (substring (magit-git-string "version") 12)))
+ (if raw it (and (string-match "^\\([0-9]+\\.[0-9]+\\.[0-9]+\\)" it)
+ (match-string 1 it)))))
+
+;;; Files
+
+(defun magit--safe-default-directory (&optional file)
+ (catch 'unsafe-default-dir
+ (let ((dir (file-name-as-directory
+ (expand-file-name (or file default-directory))))
+ (previous nil))
+ (while (not (magit-file-accessible-directory-p dir))
+ (setq dir (file-name-directory (directory-file-name dir)))
+ (when (equal dir previous)
+ (throw 'unsafe-default-dir nil))
+ (setq previous dir))
+ dir)))
+
+(defmacro magit--with-safe-default-directory (file &rest body)
+ (declare (indent 1) (debug (form body)))
+ `(-when-let (default-directory (magit--safe-default-directory ,file))
+ ,@body))
+
+(defun magit-git-dir (&optional path)
+ "Return absolute path to the control directory of the current repository.
+
+All symlinks are followed. If optional PATH is non-nil, then
+it has to be a path relative to the control directory and its
+absolute path is returned."
+ (magit--with-refresh-cache (list default-directory 'magit-git-dir path)
+ (magit--with-safe-default-directory nil
+ (--when-let (magit-rev-parse-safe "--git-dir")
+ (setq it (file-name-as-directory (magit-expand-git-file-name it)))
+ (if path (expand-file-name (convert-standard-filename path) it) it)))))
+
+(defun magit-toplevel (&optional directory)
+ "Return the absolute path to the toplevel of the current repository.
+
+From within the working tree or control directory of a repository
+return the absolute path to the toplevel directory of the working
+tree. As a special case, from within a bare repository return
+the control directory instead. When called outside a repository
+then return nil.
+
+When optional DIRECTORY is non-nil then return the toplevel for
+that directory instead of the one for `default-directory'.
+
+Try to respect the option `find-file-visit-truename', i.e. when
+the value of that option is nil, then avoid needlessly returning
+the truename. When a symlink to a sub-directory of the working
+tree is involved, or when called from within a sub-directory of
+the gitdir or from the toplevel of a gitdir, which itself is not
+located within the working tree, then it is not possible to avoid
+returning the truename."
+ (magit--with-refresh-cache
+ (cons (or directory default-directory) 'magit-toplevel)
+ (magit--with-safe-default-directory directory
+ (-if-let (topdir (magit-rev-parse-safe "--show-toplevel"))
+ (let (updir)
+ (setq topdir (magit-expand-git-file-name topdir))
+ (if (and
+ ;; Always honor these settings.
+ (not find-file-visit-truename)
+ (not (getenv "GIT_WORK_TREE"))
+ ;; `--show-cdup' is the relative path to the toplevel
+ ;; from `(file-truename default-directory)'. Here we
+ ;; pretend it is relative to `default-directory', and
+ ;; go to that directory. Then we check whether
+ ;; `--show-toplevel' still returns the same value and
+ ;; whether `--show-cdup' now is the empty string. If
+ ;; both is the case, then we are at the toplevel of
+ ;; the same working tree, but also avoided needlessly
+ ;; following any symlinks.
+ (progn
+ (setq updir (file-name-as-directory
+ (magit-rev-parse-safe "--show-cdup")))
+ (setq updir (if (file-name-absolute-p updir)
+ (concat (file-remote-p default-directory) updir)
+ (expand-file-name updir)))
+ (let ((default-directory updir))
+ (and (string-equal (magit-rev-parse-safe "--show-cdup") "")
+ (--when-let (magit-rev-parse-safe "--show-toplevel")
+ (string-equal (magit-expand-git-file-name it)
+ topdir))))))
+ updir
+ (concat (file-remote-p default-directory)
+ (file-name-as-directory topdir))))
+ (-when-let (gitdir (magit-rev-parse-safe "--git-dir"))
+ (setq gitdir (file-name-as-directory
+ (if (file-name-absolute-p gitdir)
+ ;; We might have followed a symlink.
+ (concat (file-remote-p default-directory)
+ (magit-expand-git-file-name gitdir))
+ (expand-file-name gitdir))))
+ (if (magit-bare-repo-p)
+ gitdir
+ (let* ((link (expand-file-name "gitdir" gitdir))
+ (wtree (and (file-exists-p link)
+ (magit-file-line link))))
+ (if (and wtree
+ ;; Ignore .git/gitdir files that result from a
+ ;; Git bug. See #2364.
+ (not (equal wtree ".git")))
+ ;; Return the linked working tree.
+ (file-name-directory wtree)
+ ;; Step outside the control directory to enter the working tree.
+ (file-name-directory (directory-file-name gitdir))))))))))
+
+(defmacro magit-with-toplevel (&rest body)
+ (declare (indent defun) (debug (body)))
+ (let ((toplevel (cl-gensym "toplevel")))
+ `(let ((,toplevel (magit-toplevel)))
+ (if ,toplevel
+ (let ((default-directory ,toplevel))
+ ,@body)
+ (error "Not inside a Git repository: %s" default-directory)))))
+
+(defun magit-inside-gitdir-p ()
+ "Return t if `default-directory' is below a repository directory."
+ ;; This does not work if the gitdir is not located inside the
+ ;; working tree: (magit-rev-parse-p "--is-inside-git-dir").
+ (-when-let (gitdir (magit-git-dir))
+ (file-in-directory-p default-directory gitdir)))
+
+(defun magit-inside-worktree-p ()
+ "Return t if `default-directory' is below the work tree of a repository."
+ (magit-rev-parse-p "--is-inside-work-tree"))
+
+(defun magit-bare-repo-p ()
+ "Return t if the current repository is bare."
+ (magit-rev-parse-p "--is-bare-repository"))
+
+(defun magit-git-repo-p (directory &optional non-bare)
+ "Return t if DIRECTORY is a Git repository.
+When optional NON-BARE is non-nil also return nil if DIRECTORY is
+a bare repositories."
+ (or (file-regular-p (expand-file-name ".git" directory))
+ (file-directory-p (expand-file-name ".git" directory))
+ (and (not non-bare)
+ (file-regular-p (expand-file-name "HEAD" directory))
+ (file-directory-p (expand-file-name "refs" directory))
+ (file-directory-p (expand-file-name "objects" directory)))))
+
+(defvar-local magit-buffer-revision nil)
+(defvar-local magit-buffer-refname nil)
+(defvar-local magit-buffer-file-name nil)
+(put 'magit-buffer-revision 'permanent-local t)
+(put 'magit-buffer-refname 'permanent-local t)
+(put 'magit-buffer-file-name 'permanent-local t)
+
+(defun magit-file-relative-name (&optional file tracked)
+ "Return the path of FILE relative to the repository root.
+
+If optional FILE is nil or omitted return the relative path of
+the file being visited in the current buffer, if any, else nil.
+If the file is not inside a Git repository then return nil.
+
+If TRACKED is non-nil, return the path only if it matches a
+tracked file."
+ (unless file
+ (with-current-buffer (or (buffer-base-buffer)
+ (current-buffer))
+ (setq file (or magit-buffer-file-name buffer-file-name))))
+ (when (and file (or (not tracked)
+ (magit-file-tracked-p (file-relative-name file))))
+ (--when-let (magit-toplevel
+ (magit--safe-default-directory
+ (directory-file-name (file-name-directory file))))
+ (file-relative-name file it))))
+
+(defun magit-file-tracked-p (file)
+ (magit-git-success "ls-files" "--error-unmatch" file))
+
+(defun magit-list-files (&rest args)
+ (apply #'magit-git-items "ls-files" "-z" "--full-name" args))
+
+(defun magit-tracked-files ()
+ (magit-list-files "--cached"))
+
+(defun magit-untracked-files (&optional all files)
+ (magit-list-files "--other" (unless all "--exclude-standard") "--" files))
+
+(defun magit-modified-files (&optional nomodules)
+ (magit-git-items "diff-files" "-z" "--name-only"
+ (and nomodules "--ignore-submodules")))
+
+(defun magit-staged-files (&optional nomodules files)
+ (magit-git-items "diff-index" "-z" "--name-only" "--cached"
+ (and nomodules "--ignore-submodules")
+ (magit-headish) "--" files))
+
+(defun magit-unstaged-files (&optional nomodules files)
+ (magit-git-items "diff-index" "-z" "--name-only"
+ (and nomodules "--ignore-submodules")
+ (magit-headish) "--" files))
+
+(defun magit-staged-binary-files ()
+ (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it)
+ (list (match-string 1 it)))
+ (magit-git-items "diff" "-z" "--cached"
+ "--numstat" "--ignore-submodules")))
+
+(defun magit-unmerged-files ()
+ (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U"))
+
+(defun magit-revision-files (rev)
+ (magit-with-toplevel
+ (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev)))
+
+(defun magit-changed-files (rev-or-range &optional other-rev)
+ "Return list of files the have changed between two revisions.
+If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a
+range. Otherwise, it can be any revision or range accepted by
+\"git diff\" (i.e., <rev>, <revA>..<revB>, or <revA>...<revB>)."
+ (magit-with-toplevel
+ (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev)))
+
+(defun magit-renamed-files (revA revB)
+ (--map (cons (nth 1 it) (nth 2 it))
+ (-partition 3 (magit-git-items
+ "diff-tree" "-r" "--diff-filter=R" "-z" "-M"
+ revA revB))))
+
+(defun magit-file-status (&rest args)
+ (with-temp-buffer
+ (save-excursion (magit-git-insert "status" "-z" args))
+ (let ((pos (point)) status)
+ (while (> (skip-chars-forward "[:print:]") 0)
+ (let ((x (char-after pos))
+ (y (char-after (1+ pos)))
+ (file (buffer-substring (+ pos 3) (point))))
+ (forward-char)
+ (if (memq x '(?R ?C))
+ (progn
+ (setq pos (point))
+ (skip-chars-forward "[:print:]")
+ (push (list file (buffer-substring pos (point)) x y) status)
+ (forward-char))
+ (push (list file nil x y) status)))
+ (setq pos (point)))
+ status)))
+
+(defcustom magit-cygwin-mount-points
+ (when (eq system-type 'windows-nt)
+ (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it)
+ (cons (file-name-as-directory (match-string 2 it))
+ (file-name-as-directory (match-string 1 it)))
+ (lwarn '(magit) :error
+ "Failed to parse Cygwin mount: %S" it))
+ ;; If --exec-path is not a native Windows path,
+ ;; then we probably have a cygwin git.
+ (let ((process-environment
+ (append magit-git-environment process-environment)))
+ (and (not (string-match-p
+ "\\`[a-zA-Z]:"
+ (car (process-lines
+ magit-git-executable "--exec-path"))))
+ (ignore-errors (process-lines "mount")))))
+ #'> :key (-lambda ((cyg . _win)) (length cyg))))
+ "Alist of (CYGWIN . WIN32) directory names.
+Sorted from longest to shortest CYGWIN name."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-process
+ :type '(alist :key-type string :value-type directory))
+
+(defun magit-expand-git-file-name (filename)
+ (unless (file-name-absolute-p filename)
+ (setq filename (expand-file-name filename)))
+ (-if-let ((cyg . win)
+ (cl-assoc filename magit-cygwin-mount-points
+ :test (lambda (f cyg) (string-prefix-p cyg f))))
+ (concat win (substring filename (length cyg)))
+ filename))
+
+(defun magit-convert-filename-for-git (filename)
+ "Convert FILENAME so that it can be passed to git.
+1. If it's a remote filename, then remove the remote part.
+2. Expand \"~/\", git isn't a shell and does not understand it.
+3. Deal with an `windows-nt' Emacs vs. Cygwin Git incompatibility."
+ (if (file-name-absolute-p filename)
+ (-if-let ((cyg . win)
+ (cl-rassoc filename magit-cygwin-mount-points
+ :test (lambda (f win) (string-prefix-p win f))))
+ (concat cyg (substring filename (length win)))
+ (or (file-remote-p filename 'localname)
+ filename))
+ filename))
+
+(defun magit-decode-git-path (path)
+ (if (eq (aref path 0) ?\")
+ (string-as-multibyte (read path))
+ path))
+
+(defun magit-file-at-point ()
+ (magit-section-case
+ (file (magit-section-value it))
+ (hunk (magit-section-parent-value it))))
+
+(defun magit-current-file ()
+ (or (magit-file-relative-name)
+ (magit-file-at-point)
+ (and (derived-mode-p 'magit-log-mode)
+ (car (nth 2 magit-refresh-args)))))
+
+;;; Predicates
+
+(defun magit-no-commit-p ()
+ "Return t if there is no commit in the current Git repository."
+ (not (magit-rev-verify "HEAD")))
+
+(defun magit-anything-staged-p (&optional ignore-submodules &rest files)
+ "Return t if there are any staged changes.
+If optional FILES is non-nil, then only changes to those files
+are considered."
+ (magit-git-failure "diff" "--quiet" "--cached"
+ (and ignore-submodules "--ignore-submodules")
+ "--" files))
+
+(defun magit-anything-unstaged-p (&optional ignore-submodules &rest files)
+ "Return t if there are any unstaged changes.
+If optional FILES is non-nil, then only changes to those files
+are considered."
+ (magit-git-failure "diff" "--quiet"
+ (and ignore-submodules "--ignore-submodules")
+ "--" files))
+
+(defun magit-anything-modified-p (&optional ignore-submodules &rest files)
+ "Return t if there are any staged or unstaged changes.
+If optional FILES is non-nil, then only changes to those files
+are considered."
+ (or (apply 'magit-anything-staged-p ignore-submodules files)
+ (apply 'magit-anything-unstaged-p ignore-submodules files)))
+
+(defun magit-anything-unmerged-p (&rest files)
+ "Return t if there are any merge conflicts.
+If optional FILES is non-nil, then only conflicts in those files
+are considered."
+ (and (magit-git-string "ls-files" "--unmerged" files) t))
+
+;;; Revisions and References
+
+(defun magit-rev-parse (&rest args)
+ "Execute `git rev-parse ARGS', returning first line of output.
+If there is no output return nil."
+ (apply #'magit-git-string "rev-parse" args))
+
+(defun magit-rev-parse-safe (&rest args)
+ "Execute `git rev-parse ARGS', returning first line of output.
+If there is no output return nil. Like `magit-rev-parse' but
+ignore `magit-git-debug'."
+ (apply #'magit-git-str "rev-parse" args))
+
+(defun magit-rev-parse-p (&rest args)
+ "Execute `git rev-parse ARGS', returning t if it prints \"true\".
+Return t if the first (and usually only) output line is the
+string \"true\", otherwise return nil."
+ (magit-git-true "rev-parse" args))
+
+(defun magit-rev-verify (rev)
+ (magit-rev-parse-safe "--verify" rev))
+
+(defun magit-rev-verify-commit (rev)
+ "Return full hash for REV if it names an existing commit."
+ (magit-rev-verify (concat rev "^{commit}")))
+
+(defun magit-rev-equal (a b)
+ (magit-git-success "diff" "--quiet" a b))
+
+(defun magit-rev-eq (a b)
+ (equal (magit-rev-verify a)
+ (magit-rev-verify b)))
+
+(defun magit-rev-ancestor-p (a b)
+ "Return non-nil if commit A is an ancestor of commit B."
+ (magit-git-success "merge-base" "--is-ancestor" a b))
+
+(defun magit-rev-head-p (rev)
+ (or (equal rev "HEAD")
+ (and rev
+ (not (string-match-p "\\.\\." rev))
+ (equal (magit-rev-parse rev)
+ (magit-rev-parse "HEAD")))))
+
+(defun magit-rev-name (rev &optional pattern)
+ (magit-git-string "name-rev" "--name-only" "--no-undefined"
+ (and pattern (concat "--refs=" pattern))
+ rev))
+
+(defun magit-rev-branch (rev)
+ (--when-let (magit-rev-name rev "refs/heads/*")
+ (unless (string-match-p "~" it) it)))
+
+(defun magit-get-shortname (rev)
+ (let ((fn (apply-partially 'magit-git-string "name-rev"
+ "--name-only" "--no-undefined" rev)))
+ (setq rev (or (funcall fn "--refs=refs/tags/*")
+ (funcall fn "--refs=refs/heads/*")
+ (funcall fn "--refs=refs/remotes/*" "--always")))
+ (if (and (string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" rev)
+ (magit-ref-fullname (match-string 1 rev)))
+ (match-string 1 rev)
+ rev)))
+
+(defun magit-name-branch (rev &optional lax)
+ (or (magit-name-local-branch rev)
+ (magit-name-remote-branch rev)
+ (and lax (or (magit-name-local-branch rev t)
+ (magit-name-remote-branch rev t)))))
+
+(defun magit-name-local-branch (rev &optional lax)
+ (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
+ "--refs=refs/heads/*" rev)
+ (and (or lax (not (string-match-p "[~^]" it))) it)))
+
+(defun magit-name-remote-branch (rev &optional lax)
+ (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
+ "--refs=refs/remotes/*" rev)
+ (and (or lax (not (string-match-p "[~^]" it)))
+ (substring it 8))))
+
+(defun magit-name-tag (rev &optional lax)
+ (--when-let (magit-git-string "name-rev" "--name-only" "--no-undefined"
+ "--refs=refs/tags/*" rev)
+ (and (or lax (not (string-match-p "[~^]" it)))
+ (substring it 5))))
+
+(defun magit-ref-fullname (name)
+ (magit-rev-parse "--symbolic-full-name" name))
+
+(defun magit-ref-exists-p (ref)
+ (magit-git-success "show-ref" "--verify" ref))
+
+(defun magit-headish ()
+ "Return \"HEAD\" or if that doesn't exist the hash of the empty tree."
+ (if (magit-no-commit-p)
+ (magit-git-string "mktree")
+ "HEAD"))
+
+(defun magit-branch-at-point ()
+ (magit-section-case
+ (branch (magit-section-value it))
+ (commit (magit-name-branch (magit-section-value it)))))
+
+(defun magit-local-branch-at-point ()
+ (magit-section-case
+ (branch (let ((branch (magit-section-value it)))
+ (when (member branch (magit-list-local-branch-names))
+ branch)))
+ (commit (magit-name-local-branch (magit-section-value it)))))
+
+(defun magit-remote-branch-at-point ()
+ (magit-section-case
+ (branch (let ((branch (magit-section-value it)))
+ (when (member branch (magit-list-remote-branch-names))
+ branch)))
+ (commit (magit-name-remote-branch (magit-section-value it)))))
+
+(defun magit-commit-at-point ()
+ (or (magit-section-when commit)
+ (and (derived-mode-p 'magit-revision-mode)
+ (car magit-refresh-args))))
+
+(defun magit-branch-or-commit-at-point ()
+ (or (magit-section-case
+ (branch (magit-section-value it))
+ (commit (let ((rev (magit-section-value it)))
+ (or (magit-get-shortname rev) rev)))
+ (tag (magit-section-value it)))
+ (and (derived-mode-p 'magit-revision-mode)
+ (car magit-refresh-args))))
+
+(defun magit-tag-at-point ()
+ (magit-section-case
+ (tag (magit-section-value it))
+ (commit (magit-name-tag (magit-section-value it)))))
+
+(defun magit-stash-at-point ()
+ (magit-section-when stash))
+
+(defun magit-remote-at-point ()
+ (magit-section-case
+ (remote (magit-section-value it))
+ (branch (magit-section-parent-value it))))
+
+(defun magit-get-current-branch ()
+ "Return the refname of the currently checked out branch.
+Return nil if no branch is currently checked out."
+ (magit-git-string "symbolic-ref" "--short" "HEAD"))
+
+(defun magit-get-previous-branch ()
+ "Return the refname of the previously checked out branch.
+Return nil if no branch can be found in the `HEAD' reflog
+which is different from the current branch and still exists."
+ (let ((current (magit-get-current-branch))
+ (i 1) prev)
+ (while (and (setq prev (magit-rev-verify (format "@{-%i}" i)))
+ (or (not (setq prev (magit-rev-branch prev)))
+ (equal prev current)))
+ (cl-incf i))
+ prev))
+
+(cl-defun magit-get-upstream-ref
+ (&optional (branch (magit-get-current-branch)))
+ (when branch
+ (let ((remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge")))
+ (when (and remote merge)
+ (cond ((string-equal remote ".") merge)
+ ((string-prefix-p "refs/heads/" merge)
+ (concat "refs/remotes/" remote "/" (substring merge 11))))))))
+
+(cl-defun magit-get-upstream-branch
+ (&optional (branch (magit-get-current-branch)))
+ (when branch
+ (let ((remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge")))
+ (when (and remote merge (string-prefix-p "refs/heads/" merge))
+ (setq merge (substring merge 11))
+ (if (string-equal remote ".")
+ (propertize merge 'face 'magit-branch-local)
+ (propertize (concat remote "/" merge) 'face 'magit-branch-remote))))))
+
+(defun magit-get-indirect-upstream-branch (branch &optional force)
+ (let ((remote (magit-get "branch" branch "remote")))
+ (and remote (not (equal remote "."))
+ ;; The user has opted in...
+ (or force
+ (--any (if (magit-git-success "check-ref-format" "--branch" it)
+ (equal it branch)
+ (string-match-p it branch))
+ magit-branch-prefer-remote-upstream))
+ ;; and local BRANCH tracks a remote branch...
+ (let ((upstream (magit-get-upstream-branch branch)))
+ ;; whose upstream...
+ (and upstream
+ ;; has the same name as BRANCH and...
+ (equal (substring upstream (1+ (length remote))) branch)
+ ;; and can be fast-forwarded to BRANCH.
+ (magit-rev-ancestor-p upstream branch)
+ upstream)))))
+
+(cl-defun magit-get-upstream-remote
+ (&optional (branch (magit-get-current-branch)))
+ (when branch
+ (magit-get "branch" branch "remote")))
+
+(cl-defun magit-get-push-remote
+ (&optional (branch (magit-get-current-branch)))
+ (or (and branch (magit-get "branch" branch "pushRemote"))
+ (magit-get "remote.pushDefault")))
+
+(cl-defun magit-get-push-branch
+ (&optional (branch (magit-get-current-branch)))
+ (-when-let (remote (and branch (magit-get-push-remote branch)))
+ (concat remote "/" branch)))
+
+(defun magit-get-@{push}-branch (&optional branch)
+ (let ((ref (magit-rev-parse "--symbolic-full-name"
+ (concat branch "@{push}"))))
+ (when (and ref (string-prefix-p "refs/remotes/" ref))
+ (substring ref 13))))
+
+(defun magit-get-remote (&optional branch)
+ (when (or branch (setq branch (magit-get-current-branch)))
+ (let ((remote (magit-get "branch" branch "remote")))
+ (unless (equal remote ".")
+ remote))))
+
+(defun magit-split-branch-name (branch)
+ (cond ((member branch (magit-list-local-branch-names))
+ (cons "." branch))
+ ((string-match "/" branch)
+ (let ((remote (substring branch 0 (match-beginning 0))))
+ (if (save-match-data (member remote (magit-list-remotes)))
+ (cons remote (substring branch (match-end 0)))
+ (error "Invalid branch name %s" branch))))))
+
+(defun magit-get-current-tag (&optional rev with-distance)
+ "Return the closest tag reachable from REV.
+
+If optional REV is nil then default to \"HEAD\".
+If optional WITH-DISTANCE is non-nil then return (TAG COMMITS),
+if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number
+of commits in \"HEAD\" but not in TAG and DIRTY is t if there are
+uncommitted changes, nil otherwise."
+ (--when-let (magit-git-str "describe" "--long" "--tags"
+ (and (eq with-distance 'dirty) "--dirty") rev)
+ (save-match-data
+ (string-match
+ "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" it)
+ (if with-distance
+ `(,(match-string 1 it)
+ ,(string-to-number (or (match-string 2 it) "0"))
+ ,@(and (match-string 3 it) (list t)))
+ (match-string 1 it)))))
+
+(defun magit-get-next-tag (&optional rev with-distance)
+ "Return the closest tag from which REV is reachable.
+
+If optional REV is nil then default to \"HEAD\".
+If no such tag can be found or if the distance is 0 (in which
+case it is the current tag, not the next) return nil instead.
+If optional WITH-DISTANCE is non-nil then return (TAG COMMITS)
+where COMMITS is the number of commits in TAG but not in REV."
+ (--when-let (magit-git-str "describe" "--contains" (or rev "HEAD"))
+ (save-match-data
+ (when (string-match "^[^^~]+" it)
+ (setq it (match-string 0 it))
+ (unless (equal it (magit-get-current-tag rev))
+ (if with-distance
+ (list it (car (magit-rev-diff-count it rev)))
+ it))))))
+
+(defvar magit-list-refs-namespaces
+ '("refs/heads" "refs/remotes" "refs/tags" "refs/pull"))
+
+(defun magit-list-refs (&rest args)
+ (magit-git-lines "for-each-ref" "--format=%(refname)"
+ (or args magit-list-refs-namespaces)))
+
+(defun magit-list-branches ()
+ (magit-list-refs "refs/heads" "refs/remotes"))
+
+(defun magit-list-local-branches ()
+ (magit-list-refs "refs/heads"))
+
+(defun magit-list-remote-branches (&optional remote)
+ (magit-list-refs (concat "refs/remotes/" remote)))
+
+(defun magit-list-containing-branches (&optional commit)
+ (--filter (not (string-match-p "\\`(HEAD" it))
+ (--map (substring it 2)
+ (magit-git-lines "branch" "--contains" commit))))
+
+(defun magit-list-merged-branches (&optional commit)
+ (--filter (not (string-match-p "\\`(HEAD" it))
+ (--map (substring it 2)
+ (magit-git-lines "branch" "--merged" commit))))
+
+(defun magit-list-unmerged-branches (&optional commit)
+ (--filter (not (string-match-p "\\`(HEAD" it))
+ (--map (substring it 2)
+ (magit-git-lines "branch" "--no-merged" commit))))
+
+(defun magit-list-unmerged-to-upstream-branches ()
+ (--filter (-when-let (upstream (magit-get-upstream-branch it))
+ (member it (magit-list-unmerged-branches upstream)))
+ (magit-list-local-branch-names)))
+
+(defun magit-list-refnames (&rest args)
+ (magit-git-lines "for-each-ref" "--format=%(refname:short)"
+ (or args magit-list-refs-namespaces)))
+
+(defun magit-list-branch-names ()
+ (magit-list-refnames "refs/heads" "refs/remotes"))
+
+(defun magit-list-local-branch-names ()
+ (magit-list-refnames "refs/heads"))
+
+(defun magit-list-remote-branch-names (&optional remote relative)
+ (if (and remote relative)
+ (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote)))
+ (--mapcat (when (string-match regexp it)
+ (list (match-string 1 it)))
+ (magit-list-remote-branches remote)))
+ (magit-list-refnames (concat "refs/remotes/" remote))))
+
+(defun magit-format-refs (format &rest args)
+ (let ((lines (magit-git-lines
+ "for-each-ref" (concat "--format=" format)
+ (or args (list "refs/heads" "refs/remotes" "refs/tags")))))
+ (if (string-match-p "\f" format)
+ (--map (split-string it "\f") lines)
+ lines)))
+
+(defun magit-list-remotes ()
+ (magit-git-lines "remote"))
+
+(defun magit-list-tags ()
+ (magit-git-lines "tag"))
+
+(defun magit-list-notes-refnames ()
+ (--map (substring it 6) (magit-list-refnames "refs/notes")))
+
+(defun magit-remote-list-tags (remote)
+ (--keep (and (not (string-match-p "\\^{}$" it))
+ (substring it 51))
+ (magit-git-lines "ls-remote" "--tags" remote)))
+
+(defun magit-remote-list-branches (remote)
+ (--keep (and (not (string-match-p "\\^{}$" it))
+ (substring it 52))
+ (magit-git-lines "ls-remote" "--heads" remote)))
+
+(defun magit-remote-list-refs (remote)
+ (--keep (and (not (string-match-p "\\^{}$" it))
+ (substring it 41))
+ (magit-git-lines "ls-remote" remote)))
+
+(defun magit-get-submodules ()
+ (--mapcat (and (string-match "^160000 [0-9a-z]\\{40\\} 0\t\\(.+\\)$" it)
+ (list (match-string 1 it)))
+ (magit-git-items "ls-files" "-z" "--stage")))
+
+(defun magit-list-worktrees ()
+ (let (worktrees worktree)
+ (dolist (line (let ((magit-git-global-arguments
+ ;; KLUDGE At least in v2.8.3 this triggers a segfault.
+ (remove "--no-pager" magit-git-global-arguments)))
+ (magit-git-lines "worktree" "list" "--porcelain")))
+ (cond ((string-prefix-p "worktree" line)
+ (push (setq worktree (list (substring line 9) nil nil nil))
+ worktrees))
+ ((string-equal line "bare")
+ (let* ((default-directory (car worktree))
+ (wt (and (not (magit-get-boolean "core.bare"))
+ (magit-get "core.worktree"))))
+ (if (and wt (file-exists-p (expand-file-name wt)))
+ (progn (setf (nth 0 worktree) (expand-file-name wt))
+ (setf (nth 2 worktree) (magit-rev-parse "HEAD"))
+ (setf (nth 3 worktree) (magit-get-current-branch)))
+ (setf (nth 1 worktree) t))))
+ ((string-prefix-p "HEAD" line)
+ (setf (nth 2 worktree) (substring line 5)))
+ ((string-prefix-p "branch" line)
+ (setf (nth 3 worktree) (substring line 18)))
+ ((string-equal line "detached"))))
+ (nreverse worktrees)))
+
+(defun magit-ref-p (rev)
+ (or (car (member rev (magit-list-refs)))
+ (car (member rev (magit-list-refnames)))))
+
+(defun magit-branch-p (rev)
+ (or (car (member rev (magit-list-branches)))
+ (car (member rev (magit-list-branch-names)))))
+
+(defun magit-local-branch-p (rev)
+ (or (car (member rev (magit-list-local-branches)))
+ (car (member rev (magit-list-local-branch-names)))))
+
+(defun magit-remote-branch-p (rev)
+ (or (car (member rev (magit-list-remote-branches)))
+ (car (member rev (magit-list-remote-branch-names)))))
+
+(defun magit-branch-set-face (branch)
+ (propertize branch 'face (if (magit-local-branch-p branch)
+ 'magit-branch-local
+ 'magit-branch-remote)))
+
+(defun magit-tag-p (rev)
+ (car (member rev (magit-list-tags))))
+
+(defun magit-remote-p (string)
+ (car (member string (magit-list-remotes))))
+
+(defun magit-rev-diff-count (a b)
+ "Return the commits in A but not B and vice versa.
+Return a list of two integers: (A>B B>A)."
+ (mapcar 'string-to-number
+ (split-string (magit-git-string "rev-list"
+ "--count" "--left-right"
+ (concat a "..." b))
+ "\t")))
+
+(defun magit-abbrev-length ()
+ (string-to-number (or (magit-get "core.abbrev") "7")))
+
+(defun magit-abbrev-arg (&optional arg)
+ (format "--%s=%d" (or arg "abbrev") (magit-abbrev-length)))
+
+(defun magit-rev-abbrev (rev)
+ (magit-rev-parse (magit-abbrev-arg "short") rev))
+
+(defun magit-commit-children (commit &optional args)
+ (-map #'car
+ (--filter (member commit (cdr it))
+ (--map (split-string it " ")
+ (magit-git-lines
+ "log" "--format=%H %P"
+ (or args (list "--branches" "--tags" "--remotes"))
+ "--not" commit)))))
+
+(defun magit-commit-parents (commit)
+ (--when-let (magit-git-string "rev-list" "-1" "--parents" commit)
+ (cdr (split-string it))))
+
+(defun magit-assert-one-parent (commit command)
+ (when (> (length (magit-commit-parents commit)) 1)
+ (user-error "Cannot %s a merge commit" command)))
+
+(defun magit-patch-id (rev)
+ (with-temp-buffer
+ (magit-process-file
+ shell-file-name nil '(t nil) nil shell-command-switch
+ (let ((exec (shell-quote-argument magit-git-executable)))
+ (format "%s diff-tree -u %s | %s patch-id" exec rev exec)))
+ (car (split-string (buffer-string)))))
+
+(defun magit-rev-format (format &optional rev args)
+ (let ((str (magit-git-string "show" "--no-patch"
+ (concat "--format=" format) args
+ (if rev (concat rev "^{commit}") "HEAD") "--")))
+ (unless (string-equal str "")
+ str)))
+
+(defun magit-rev-insert-format (format &optional rev args)
+ (magit-git-insert "show" "--no-patch"
+ (concat "--format=" format) args
+ (if rev (concat rev "^{commit}") "HEAD") "--"))
+
+(defun magit-format-rev-summary (rev)
+ (--when-let (magit-rev-format "%h %s" rev)
+ (string-match " " it)
+ (put-text-property 0 (match-beginning 0) 'face 'magit-hash it)
+ it))
+
+(defun magit-format-ref-label (ref &optional head)
+ (-let [(_re face fn)
+ (--first (string-match (car it) ref) magit-ref-namespaces)]
+ (if fn
+ (funcall fn ref face)
+ (propertize (or (match-string 1 ref) ref)
+ 'face (if (equal ref head) 'magit-branch-current face)))))
+
+(defun magit-format-ref-labels (string)
+ (save-match-data
+ (let ((regexp "\\(, \\|tag: \\| -> \\|[()]\\)") head names)
+ (if (and (derived-mode-p 'magit-log-mode)
+ (member "--simplify-by-decoration" (cadr magit-refresh-args)))
+ (let ((branches (magit-list-local-branch-names))
+ (re (format "^%s/.+" (regexp-opt (magit-list-remotes)))))
+ (setq names
+ (--map (cond ((string-equal it "HEAD") it)
+ ((string-prefix-p "refs/" it) it)
+ ((member it branches) (concat "refs/heads/" it))
+ ((string-match re it) (concat "refs/remotes/" it))
+ (t (concat "refs/" it)))
+ (split-string
+ (replace-regexp-in-string "tag: " "refs/tags/" string)
+ regexp t))))
+ (setq names (split-string string regexp t)))
+ (when (member "HEAD" names)
+ (setq head (magit-git-string "symbolic-ref" "HEAD")
+ names (cons (or head "@") (delete head (delete "HEAD" names)))))
+ (mapconcat (lambda (it) (magit-format-ref-label it head)) names " "))))
+
+(defun magit-object-type (object)
+ (magit-git-string "cat-file" "-t" object))
+
+(defmacro magit-with-blob (commit file &rest body)
+ (declare (indent 2)
+ (debug (form form body)))
+ `(with-temp-buffer
+ (let ((buffer-file-name ,file))
+ (save-excursion
+ (magit-git-insert "cat-file" "-p"
+ (concat ,commit ":" buffer-file-name)))
+ (decode-coding-inserted-region
+ (point-min) (point-max) buffer-file-name t nil nil t)
+ ,@body)))
+
+(defmacro magit-with-temp-index (tree arg &rest body)
+ (declare (indent 2) (debug (form form body)))
+ (let ((file (cl-gensym "file")))
+ `(let ((,file (magit-convert-filename-for-git
+ (make-temp-name (magit-git-dir "index.magit.")))))
+ (unwind-protect
+ (progn (--when-let ,tree
+ (or (magit-git-success "read-tree" ,arg it
+ (concat "--index-output=" ,file))
+ (error "Cannot read tree %s" it)))
+ (if (file-remote-p default-directory)
+ (let ((magit-tramp-process-environment
+ (cons (concat "GIT_INDEX_FILE=" ,file)
+ magit-tramp-process-environment)))
+ ,@body)
+ (let ((process-environment
+ (cons (concat "GIT_INDEX_FILE=" ,file)
+ process-environment)))
+ ,@body)))
+ (ignore-errors
+ (delete-file (concat (file-remote-p default-directory) ,file)))))))
+
+(defun magit-commit-tree (message &optional tree &rest parents)
+ (magit-git-string "commit-tree" "--no-gpg-sign" "-m" message
+ (--mapcat (list "-p" it) (delq nil parents))
+ (or tree (magit-git-string "write-tree"))))
+
+(defun magit-commit-worktree (message &optional arg &rest other-parents)
+ (magit-with-temp-index "HEAD" arg
+ (and (magit-update-files (magit-modified-files))
+ (apply #'magit-commit-tree message nil "HEAD" other-parents))))
+
+(defun magit-update-files (files)
+ (magit-git-success "update-index" "--add" "--remove" "--" files))
+
+(defun magit-update-ref (ref message rev &optional stashish)
+ (or (if (not (version< (magit-git-version) "2.6.0"))
+ (magit-git-success "update-ref" "--create-reflog"
+ "-m" message ref rev
+ (or (magit-rev-verify ref) ""))
+ ;; `--create-reflog' didn't exist before v2.6.0
+ (let ((oldrev (magit-rev-verify ref))
+ (logfile (magit-git-dir (concat "logs/" ref))))
+ (unless (file-exists-p logfile)
+ (when oldrev
+ (magit-git-success "update-ref" "-d" ref oldrev))
+ (make-directory (file-name-directory logfile) t)
+ (with-temp-file logfile)
+ (when (and oldrev (not stashish))
+ (magit-git-success "update-ref" "-m" "enable reflog"
+ ref oldrev ""))))
+ (magit-git-success "update-ref" "-m" message ref rev
+ (or (magit-rev-verify ref) "")))
+ (error "Cannot update %s with %s" ref rev)))
+
+(defconst magit-range-re
+ (concat "\\`\\([^ \t]*[^.]\\)?" ; revA
+ "\\(\\.\\.\\.?\\)" ; range marker
+ "\\([^.][^ \t]*\\)?\\'")) ; revB
+
+(defun magit-split-range (range)
+ (when (string-match magit-range-re range)
+ (let ((beg (or (match-string 1 range) "HEAD"))
+ (end (or (match-string 3 range) "HEAD")))
+ (cons (if (string-equal (match-string 2) "...")
+ (magit-git-string "merge-base" beg end)
+ beg)
+ end))))
+
+;;; Completion
+
+(defvar magit-revision-history nil)
+
+(defun magit-read-branch (prompt &optional default)
+ (magit-completing-read prompt (magit-list-branch-names)
+ nil t nil 'magit-revision-history
+ (or (magit-branch-at-point)
+ default (magit-get-current-branch))))
+
+(defun magit-read-branch-or-commit (prompt &optional secondary-default)
+ (or (magit-completing-read prompt (cons "HEAD" (magit-list-refnames))
+ nil nil nil 'magit-revision-history
+ (or (magit-branch-or-commit-at-point)
+ secondary-default
+ (magit-get-current-branch)))
+ (user-error "Nothing selected")))
+
+(defun magit-read-range-or-commit (prompt &optional secondary-default)
+ (magit-read-range
+ prompt
+ (or (--when-let (magit-region-values 'commit 'branch)
+ (deactivate-mark)
+ (concat (car (last it)) ".." (car it)))
+ (magit-branch-or-commit-at-point)
+ secondary-default
+ (magit-get-current-branch))))
+
+(defun magit-read-range (prompt &optional default)
+ (let* ((choose-completion-string-functions
+ '(crm--choose-completion-string))
+ (minibuffer-completion-table #'crm--collection-fn)
+ (minibuffer-completion-confirm t)
+ (crm-completion-table (magit-list-refnames))
+ (crm-separator "\\.\\.\\.?")
+ (input (read-from-minibuffer
+ (concat prompt (and default (format " (%s)" default)) ": ")
+ nil crm-local-completion-map
+ nil 'magit-revision-history
+ default)))
+ (when (string-equal input "")
+ (or (setq input default)
+ (user-error "Nothing selected")))
+ input))
+
+(defun magit-read-remote-branch
+ (prompt &optional remote default local-branch require-match)
+ (let ((choice (magit-completing-read
+ prompt
+ (-union (and local-branch
+ (if remote
+ (concat remote "/" local-branch)
+ (--map (concat it "/" local-branch)
+ (magit-list-remotes))))
+ (magit-list-remote-branch-names remote t))
+ nil require-match nil 'magit-revision-history default)))
+ (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice))
+ choice
+ (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice))))
+
+(defun magit-read-refspec (prompt remote)
+ (magit-completing-read prompt
+ (prog2 (message "Determining available refs...")
+ (magit-remote-list-refs remote)
+ (message "Determining available refs...done"))))
+
+(defun magit-read-local-branch (prompt &optional secondary-default)
+ (magit-completing-read prompt (magit-list-local-branch-names)
+ nil t nil 'magit-revision-history
+ (or (magit-local-branch-at-point)
+ secondary-default
+ (magit-get-current-branch))))
+
+(defun magit-read-local-branch-or-commit (prompt)
+ (let ((branches (magit-list-local-branch-names))
+ (commit (magit-commit-at-point)))
+ (or (magit-completing-read prompt
+ (if commit (cons commit branches) branches)
+ nil nil nil 'magit-revision-history
+ (or (magit-local-branch-at-point) commit))
+ (user-error "Nothing selected"))))
+
+(defun magit-read-local-branch-or-ref (prompt &optional secondary-default)
+ (magit-completing-read prompt (nconc (magit-list-local-branch-names)
+ (magit-list-refs "refs/"))
+ nil t nil 'magit-revision-history
+ (or (magit-local-branch-at-point)
+ secondary-default
+ (magit-get-current-branch))))
+
+(defun magit-read-other-branch
+ (prompt &optional exclude secondary-default no-require-match)
+ (let* ((current (magit-get-current-branch))
+ (atpoint (magit-branch-at-point))
+ (exclude (or exclude current))
+ (default (or (and (not (equal atpoint exclude)) atpoint)
+ (and (not (equal current exclude)) current)
+ secondary-default
+ (magit-get-previous-branch))))
+ (magit-completing-read prompt (delete exclude (magit-list-branch-names))
+ nil (not no-require-match)
+ nil 'magit-revision-history default)))
+
+(defun magit-read-other-branch-or-commit
+ (prompt &optional exclude secondary-default)
+ (let* ((current (magit-get-current-branch))
+ (atpoint (magit-branch-or-commit-at-point))
+ (exclude (or exclude current))
+ (default (or (and (not (equal atpoint exclude)) atpoint)
+ (and (not (equal current exclude)) current)
+ secondary-default
+ (magit-get-previous-branch))))
+ (or (magit-completing-read prompt (delete exclude (magit-list-refnames))
+ nil nil nil 'magit-revision-history default)
+ (user-error "Nothing selected"))))
+
+(cl-defun magit-read-upstream-branch
+ (&optional (branch (magit-get-current-branch)) prompt)
+ (magit-completing-read
+ (or prompt (format "Change upstream of %s to" branch))
+ (-union (--map (concat it "/" branch)
+ (magit-list-remotes))
+ (delete branch (magit-list-branch-names)))
+ nil nil nil 'magit-revision-history
+ (or (let ((r (magit-remote-branch-at-point))
+ (l (magit-branch-at-point)))
+ (when (and l (equal l branch))
+ (setq l nil))
+ (if magit-prefer-remote-upstream (or r l) (or l r)))
+ (let ((r (magit-branch-p "origin/master"))
+ (l (and (not (equal branch "master"))
+ (magit-branch-p "master"))))
+ (if magit-prefer-remote-upstream (or r l) (or l r)))
+ (let ((previous (magit-get-previous-branch)))
+ (and (not (equal previous branch)) previous)))))
+
+(defun magit-read-starting-point (prompt)
+ (or (magit-completing-read (concat prompt " starting at")
+ (cons "HEAD" (magit-list-refnames))
+ nil nil nil 'magit-revision-history
+ (magit--default-starting-point))
+ (user-error "Nothing selected")))
+
+(defun magit--default-starting-point ()
+ (or (let ((r (magit-remote-branch-at-point))
+ (l (magit-local-branch-at-point)))
+ (if magit-prefer-remote-upstream (or r l) (or l r)))
+ (magit-commit-at-point)
+ (magit-stash-at-point)
+ (magit-get-current-branch)))
+
+(defun magit-read-tag (prompt &optional require-match)
+ (magit-completing-read prompt (magit-list-tags) nil
+ require-match nil 'magit-revision-history
+ (magit-tag-at-point)))
+
+(defun magit-read-stash (prompt &optional use-at-point)
+ (let ((atpoint (magit-stash-at-point)))
+ (or (and use-at-point atpoint)
+ (let ((stashes (magit-git-lines "stash" "list" "--format=%gd")))
+ (magit-completing-read prompt stashes nil t nil nil
+ (or atpoint (car stashes)))))))
+
+(defun magit-read-remote (prompt &optional default use-only)
+ (let ((remotes (magit-list-remotes)))
+ (if (and use-only (= (length remotes) 1))
+ (car remotes)
+ (magit-completing-read prompt remotes
+ nil t nil nil
+ (or default
+ (magit-remote-at-point)
+ (magit-get-remote))))))
+
+(defun magit-read-remote-or-url (prompt &optional default)
+ (magit-completing-read prompt
+ (nconc (magit-list-remotes)
+ (list "https://" "git://" "git@"))
+ nil nil nil nil
+ (or default
+ (magit-remote-at-point)
+ (magit-get-remote))))
+
+(defun magit-read-module-path (prompt)
+ (magit-completing-read prompt (magit-get-submodules)))
+
+;;; Variables
+
+(defun magit-config-get-from-cached-list (key)
+ (gethash
+ ;; `git config --list' downcases first and last components of the key.
+ (--> key
+ (replace-regexp-in-string "\\`[^.]+" #'downcase it t t)
+ (replace-regexp-in-string "[^.]+\\'" #'downcase it t t))
+ (magit--with-refresh-cache (list 'config (magit-toplevel))
+ (let ((configs (make-hash-table :test 'equal)))
+ (dolist (conf (magit-git-items "config" "--list" "-z"))
+ (let* ((nl-pos (cl-position ?\n conf))
+ (key (substring conf 0 nl-pos))
+ (val (if nl-pos (substring conf (1+ nl-pos)) "")))
+ (puthash key (nconc (gethash key configs) (list val)) configs)))
+ configs))))
+
+(defun magit-get (&rest keys)
+ "Return the value of Git config entry specified by KEYS."
+ (car (last (apply 'magit-get-all keys))))
+
+(defun magit-get-all (&rest keys)
+ "Return all values of the Git config entry specified by KEYS."
+ (let ((magit-git-debug nil)
+ (key (mapconcat 'identity keys ".")))
+ (if magit--refresh-cache
+ (magit-config-get-from-cached-list key)
+ (magit-git-items "config" "-z" "--get-all" key))))
+
+(defun magit-get-boolean (&rest keys)
+ "Return the boolean value of Git config entry specified by KEYS."
+ (let ((key (mapconcat 'identity keys ".")))
+ (if magit--refresh-cache
+ (equal "true" (car (magit-config-get-from-cached-list key)))
+ (magit-git-true "config" "--bool" key))))
+
+(defun magit-set (val &rest keys)
+ "Set Git config settings specified by KEYS to VAL."
+ (let ((key (mapconcat 'identity keys ".")))
+ (if val
+ (magit-git-success "config" key val)
+ (magit-git-success "config" "--unset" key))
+ val))
+
+(gv-define-setter magit-get (val &rest keys)
+ `(magit-set ,val ,@keys))
+
+;;; magit-git.el ends soon
+
+(define-obsolete-variable-alias 'magit-git-standard-options
+ 'magit-git-global-arguments "Magit 2.1.0")
+(define-obsolete-function-alias 'magit-get-tracked-ref
+ 'magit-get-upstream-ref "Magit 2.4.0")
+(define-obsolete-function-alias 'magit-get-tracked-branch
+ 'magit-get-upstream-branch "Magit 2.4.0")
+(define-obsolete-function-alias 'magit-get-tracked-remote
+ 'magit-get-upstream-remote "Magit 2.4.0")
+
+(provide 'magit-git)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-git.el ends here
--- /dev/null
+;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for looking at Git logs, including
+;; special logs like reflogs and cherry-logs, as well as for selecting
+;; a commit from a log.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-diff)
+
+(declare-function magit-blob-visit 'magit)
+(declare-function magit-insert-head-branch-header 'magit)
+(declare-function magit-insert-upstream-branch-header 'magit)
+(declare-function magit-read-file-from-rev 'magit)
+(declare-function magit-show-commit 'magit)
+(defvar magit-refs-indent-cherry-lines)
+(defvar magit-refs-show-commit-count)
+(defvar magit-status-sections-hook)
+
+(require 'ansi-color)
+(require 'crm)
+
+;;; Options
+;;;; Log Mode
+
+(defgroup magit-log nil
+ "Inspect and manipulate Git history."
+ :group 'magit-modes)
+
+(defcustom magit-log-mode-hook nil
+ "Hook run after entering Magit-Log mode."
+ :group 'magit-log
+ :type 'hook)
+
+(defcustom magit-log-arguments '("-n256" "--graph" "--decorate")
+ "The log arguments used in `magit-log-mode' buffers."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-log
+ :group 'magit-commands
+ :type '(repeat (string :tag "Argument")))
+
+(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L")
+ "The log arguments that cause the `--graph' argument to be dropped."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-log
+ :type '(repeat (string :tag "Argument"))
+ :options '("--follow" "--grep" "-G" "-S" "-L"))
+
+(defcustom magit-log-revision-headers-format "\
+%+b
+Author: %aN <%aE>
+Committer: %cN <%cE>"
+ "Additional format string used with the `++header' argument."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-log
+ :type 'string)
+
+(defcustom magit-log-auto-more nil
+ "Insert more log entries automatically when moving past the last entry.
+Only considered when moving past the last entry with
+`magit-goto-*-section' commands."
+ :group 'magit-log
+ :type 'boolean)
+
+(defcustom magit-log-show-margin t
+ "Whether to initially show the margin in log buffers.
+
+When non-nil the author name and date are initially displayed in
+the margin of log buffers. The margin can be shown or hidden in
+the current buffer using the command `magit-toggle-margin'. In
+status buffers this option is ignored but it is possible to show
+the margin using the mentioned command."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :type 'boolean)
+
+(defcustom magit-duration-spec
+ `((?Y "year" "years" ,(round (* 60 60 24 365.2425)))
+ (?M "month" "months" ,(round (* 60 60 24 30.436875)))
+ (?w "week" "weeks" ,(* 60 60 24 7))
+ (?d "day" "days" ,(* 60 60 24))
+ (?h "hour" "hours" ,(* 60 60))
+ (?m "minute" "minutes" 60)
+ (?s "second" "seconds" 1))
+ "Units used to display durations in a human format.
+The value is a list of time units, beginning with the longest.
+Each element has the form (CHAR UNIT UNITS SECONDS). UNIT is the
+time unit, UNITS is the plural of that unit. CHAR is a character
+abbreviation. And SECONDS is the number of seconds in one UNIT.
+Also see option `magit-log-margin-spec'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :type '(repeat (list (character :tag "Unit character")
+ (string :tag "Unit singular string")
+ (string :tag "Unit plural string")
+ (integer :tag "Seconds in unit"))))
+
+(defcustom magit-log-margin-spec '(28 7 magit-duration-spec)
+ "How to format the log margin.
+
+The log margin is used to display each commit's author followed
+by the commit's age. This option controls the total width of the
+margin and how time units are formatted, the value has the form:
+
+ (WIDTH UNIT-WIDTH DURATION-SPEC)
+
+WIDTH specifies the total width of the log margin. UNIT-WIDTH is
+either the integer 1, in which case time units are displayed as a
+single characters, leaving more room for author names; or it has
+to be the width of the longest time unit string in DURATION-SPEC.
+DURATION-SPEC has to be a variable, its value controls which time
+units, in what language, are being used."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :set-after '(magit-duration-spec)
+ :type '(list (integer :tag "Margin width")
+ (choice :tag "Time unit style"
+ (const :format "%t\n"
+ :tag "abbreviate to single character" 1)
+ (integer :format "%t\n"
+ :tag "show full name" 7))
+ (variable :tag "Duration spec variable")))
+
+(defcustom magit-log-show-refname-after-summary nil
+ "Whether to show refnames after commit summaries.
+This is useful if you use really long branch names."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-log
+ :type 'boolean)
+
+(defface magit-log-graph
+ '((((class color) (background light)) :foreground "grey30")
+ (((class color) (background dark)) :foreground "grey80"))
+ "Face for the graph part of the log output."
+ :group 'magit-faces)
+
+(defface magit-log-author
+ '((((class color) (background light)) :foreground "firebrick")
+ (((class color) (background dark)) :foreground "tomato"))
+ "Face for the author part of the log output."
+ :group 'magit-faces)
+
+(defface magit-log-date
+ '((((class color) (background light)) :foreground "grey30")
+ (((class color) (background dark)) :foreground "grey80"))
+ "Face for the date part of the log output."
+ :group 'magit-faces)
+
+;;;; File Log
+
+(defcustom magit-log-buffer-file-locked t
+ "Whether `magit-log-buffer-file' uses a decicated buffer."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :group 'magit-log
+ :type 'boolean)
+
+;;;; Select Mode
+
+(defcustom magit-log-select-arguments '("-n256" "--decorate")
+ "The log arguments used in `magit-log-select-mode' buffers."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-log
+ :type '(repeat (string :tag "Argument")))
+
+(defcustom magit-log-select-show-usage 'both
+ "Whether to show usage information when selecting a commit from a log.
+The message can be shown in the `echo-area' or the `header-line', or in
+`both' places. If the value isn't one of these symbols, then it should
+be nil, in which case no usage information is shown."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :type '(choice (const :tag "in echo-area" echo-area)
+ (const :tag "in header-line" header-line)
+ (const :tag "in both places" both)
+ (const :tag "nowhere")))
+
+;;;; Cherry Mode
+
+(defcustom magit-cherry-sections-hook
+ '(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
+ :type 'hook)
+
+;;;; Reflog Mode
+
+(defcustom magit-reflog-arguments '("-n256")
+ "The log arguments used in `magit-reflog-mode' buffers."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-log
+ :group 'magit-commands
+ :type '(repeat (string :tag "Argument")))
+
+(defcustom magit-reflog-show-margin t
+ "Whether to initially show the margin in reflog buffers.
+
+When non-nil the author name and date are initially displayed in
+the margin of reflog buffers. The margin can be shown or hidden
+in the current buffer using the command `magit-toggle-margin'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :type 'boolean)
+
+(defface magit-reflog-commit '((t :foreground "green"))
+ "Face for commit commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-amend '((t :foreground "magenta"))
+ "Face for amend commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-merge '((t :foreground "green"))
+ "Face for merge, checkout and branch commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-checkout '((t :foreground "blue"))
+ "Face for checkout commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-reset '((t :foreground "red"))
+ "Face for reset commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-rebase '((t :foreground "magenta"))
+ "Face for rebase commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-cherry-pick '((t :foreground "green"))
+ "Face for cherry-pick commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-remote '((t :foreground "cyan"))
+ "Face for pull and clone commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-other '((t :foreground "cyan"))
+ "Face for other commands in reflogs."
+ :group 'magit-faces)
+
+;;;; Log Sections
+
+(defcustom magit-log-section-commit-count 10
+ "How many recent commits to show in certain log sections.
+How many recent commits `magit-insert-recent-commits' and
+`magit-insert-unpulled-from-upstream-or-recent' (provided
+the upstream isn't ahead of the current branch) show."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-status
+ :type 'number)
+
+(defcustom magit-log-section-arguments '("-n256" "--decorate")
+ "The log arguments used in buffers that show other things besides logs."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-log
+ :group 'magit-status
+ :type '(repeat (string :tag "Argument")))
+
+;;; Commands
+
+(defvar magit-log-popup
+ '(:variable magit-log-arguments
+ :man-page "git-log"
+ :switches ((?g "Show graph" "--graph")
+ (?c "Show graph in color" "--color")
+ (?d "Show refnames" "--decorate")
+ (?S "Show signatures" "--show-signature")
+ (?u "Show diffs" "--patch")
+ (?s "Show diffstats" "--stat")
+ (?h "Show header" "++header")
+ (?D "Simplify by decoration" "--simplify-by-decoration")
+ (?f "Follow renames when showing single-file log" "--follow"))
+ :options ((?n "Limit number of commits" "-n")
+ (?f "Limit to files" "-- " magit-read-files)
+ (?a "Limit to author" "--author=")
+ (?o "Order commits by" "++order=" magit-log-select-order)
+ (?g "Search messages" "--grep=")
+ (?G "Search changes" "-G")
+ (?S "Search occurrences" "-S")
+ (?L "Trace line evolution" "-L" magit-read-file-trace))
+ :actions ((?l "Log current" magit-log-current)
+ (?L "Log local branches" magit-log-branches)
+ (?r "Reflog current" magit-reflog-current)
+ (?o "Log other" magit-log)
+ (?b "Log all branches" magit-log-all-branches)
+ (?O "Reflog other" magit-reflog)
+ (?h "Log HEAD" magit-log-head)
+ (?a "Log all references" magit-log-all)
+ (?H "Reflog HEAD" magit-reflog-head))
+ :default-action magit-log-current
+ :max-action-columns 3))
+
+(defvar magit-log-mode-refresh-popup
+ '(:variable magit-log-arguments
+ :man-page "git-log"
+ :switches ((?g "Show graph" "--graph")
+ (?c "Show graph in color" "--color")
+ (?d "Show refnames" "--decorate")
+ (?S "Show signatures" "--show-signature")
+ (?u "Show diffs" "--patch")
+ (?s "Show diffstats" "--stat")
+ (?D "Simplify by decoration" "--simplify-by-decoration")
+ (?f "Follow renames when showing single-file log" "--follow"))
+ :options ((?n "Limit number of commits" "-n")
+ (?f "Limit to files" "-- " magit-read-files)
+ (?a "Limit to author" "--author=")
+ (?o "Order commits by" "++order=" magit-log-select-order)
+ (?g "Search messages" "--grep=")
+ (?G "Search changes" "-G")
+ (?S "Search occurrences" "-S")
+ (?L "Trace line evolution" "-L" magit-read-file-trace))
+ :actions ((?g "Refresh" magit-log-refresh)
+ (?t "Toggle margin" magit-toggle-margin)
+ (?s "Set defaults" magit-log-set-default-arguments) nil
+ (?w "Save defaults" magit-log-save-default-arguments))
+ :max-action-columns 2))
+
+(defvar magit-reflog-mode-refresh-popup
+ '(:variable magit-reflog-arguments
+ :man-page "git-reflog"
+ :options ((?n "Limit number of commits" "-n"))))
+
+(defvar magit-log-refresh-popup
+ '(:variable magit-log-arguments
+ :man-page "git-log"
+ :switches ((?g "Show graph" "--graph")
+ (?c "Show graph in color" "--color")
+ (?d "Show refnames" "--decorate"))
+ :options ((?n "Limit number of commits" "-n")
+ (?o "Order commits by" "++order=" magit-log-select-order))
+ :actions ((?g "Refresh" magit-log-refresh)
+ (?t "Toggle margin" magit-toggle-margin)
+ (?s "Set defaults" magit-log-set-default-arguments) nil
+ (?w "Save defaults" magit-log-save-default-arguments))
+ :max-action-columns 2))
+
+(magit-define-popup-keys-deferred 'magit-log-popup)
+(magit-define-popup-keys-deferred 'magit-log-mode-refresh-popup)
+(magit-define-popup-keys-deferred 'magit-log-refresh-popup)
+
+(defun magit-read-file-trace (&rest _ignored)
+ (let ((file (magit-read-file-from-rev "HEAD" "File"))
+ (trace (magit-read-string "Trace")))
+ (if (string-match
+ "^\\(/.+/\\|:[^:]+\\|[0-9]+,[-+]?[0-9]+\\)\\(:\\)?$" trace)
+ (concat trace (or (match-string 2 trace) ":") file)
+ (user-error "Trace is invalid, see man git-log"))))
+
+(defun magit-log-select-order (&rest _ignored)
+ (magit-read-char-case "Order commits by " t
+ (?t "[t]opography" "topo")
+ (?a "[a]uthor date" "author-date")
+ (?c "[c]ommitter date" "date")))
+
+(defun magit-log-arguments (&optional refresh)
+ (cond ((memq magit-current-popup
+ '(magit-log-popup magit-log-refresh-popup))
+ (magit-popup-export-file-args magit-current-popup-args))
+ ((derived-mode-p 'magit-log-mode)
+ (list (nth 1 magit-refresh-args)
+ (nth 2 magit-refresh-args)))
+ (refresh
+ (list magit-log-section-arguments nil))
+ (t
+ (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
+ (with-current-buffer buffer
+ (list (nth 1 magit-refresh-args)
+ (nth 2 magit-refresh-args)))
+ (list (default-value 'magit-log-arguments) nil)))))
+
+(defun magit-log-popup (arg)
+ "Popup console for log commands."
+ (interactive "P")
+ (let ((magit-log-refresh-popup
+ (pcase major-mode
+ (`magit-log-mode magit-log-mode-refresh-popup)
+ (_ magit-log-refresh-popup)))
+ (magit-log-arguments
+ (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
+ (with-current-buffer buffer
+ (magit-popup-import-file-args (nth 1 magit-refresh-args)
+ (nth 2 magit-refresh-args)))
+ (default-value 'magit-log-arguments))))
+ (magit-invoke-popup 'magit-log-popup nil arg)))
+
+;;;###autoload
+(defun magit-log-buffer-file-popup ()
+ "Popup console for log commands.
+
+This is a variant of `magit-log-popup' which shows the same popup
+but which limits the log to the file being visited in the current
+buffer."
+ (interactive)
+ (-if-let (file (magit-file-relative-name))
+ (let ((magit-log-arguments
+ (magit-popup-import-file-args
+ (-if-let (buffer (magit-mode-get-buffer 'magit-log-mode))
+ (with-current-buffer buffer
+ (nth 2 magit-refresh-args))
+ (default-value 'magit-log-arguments))
+ (list file))))
+ (magit-invoke-popup 'magit-log-popup nil nil))
+ (user-error "Buffer isn't visiting a file")))
+
+(defun magit-log-refresh-popup (arg)
+ "Popup console for changing log arguments in the current buffer."
+ (interactive "P")
+ (magit-log-refresh-assert)
+ (let ((magit-log-refresh-popup
+ (cond ((derived-mode-p 'magit-log-select-mode)
+ magit-log-refresh-popup)
+ ((derived-mode-p 'magit-log-mode)
+ (let ((def (copy-sequence magit-log-refresh-popup)))
+ (plist-put def :switches (plist-get magit-log-popup :switches))
+ (plist-put def :options (plist-get magit-log-popup :options))
+ def))
+ (t
+ magit-log-refresh-popup)))
+ (magit-log-arguments
+ (cond ((derived-mode-p 'magit-log-select-mode)
+ (cadr magit-refresh-args))
+ ((derived-mode-p 'magit-log-mode)
+ (magit-popup-import-file-args (nth 1 magit-refresh-args)
+ (nth 2 magit-refresh-args)))
+ (t
+ magit-log-section-arguments))))
+ (magit-invoke-popup 'magit-log-refresh-popup nil arg)))
+
+(defun magit-log-refresh (args files)
+ "Set the local log arguments for the current buffer."
+ (interactive (magit-log-arguments t))
+ (magit-log-refresh-assert)
+ (cond ((derived-mode-p 'magit-log-select-mode)
+ (setcar (cdr magit-refresh-args) args))
+ ((derived-mode-p 'magit-log-mode)
+ (setcdr magit-refresh-args (list args files)))
+ (t
+ (setq-local magit-log-section-arguments args)))
+ (magit-refresh))
+
+(defun magit-log-set-default-arguments (args files)
+ "Set the global log arguments for the current buffer."
+ (interactive (magit-log-arguments t))
+ (magit-log-refresh-assert)
+ (cond ((derived-mode-p 'magit-log-select-mode)
+ (customize-set-variable 'magit-log-select-arguments args)
+ (setcar (cdr magit-refresh-args) args))
+ ((derived-mode-p 'magit-log-mode)
+ (customize-set-variable 'magit-log-arguments args)
+ (setcdr magit-refresh-args (list args files)))
+ (t
+ (customize-set-variable 'magit-log-section-arguments args)
+ (kill-local-variable 'magit-log-section-arguments)))
+ (magit-refresh))
+
+(defun magit-log-save-default-arguments (args files)
+ "Set and save the global log arguments for the current buffer."
+ (interactive (magit-log-arguments t))
+ (magit-log-refresh-assert)
+ (cond ((derived-mode-p 'magit-log-select-mode)
+ (customize-save-variable 'magit-log-select-arguments args)
+ (setcar (cdr magit-refresh-args) args))
+ ((derived-mode-p 'magit-log-mode)
+ (customize-save-variable 'magit-log-arguments args)
+ (setcdr magit-refresh-args (list args files)))
+ (t
+ (customize-save-variable 'magit-log-section-arguments args)
+ (kill-local-variable 'magit-log-section-arguments)))
+ (magit-refresh))
+
+(defun magit-log-refresh-assert ()
+ (cond ((derived-mode-p 'magit-reflog-mode)
+ (user-error "Cannot change log arguments in reflog buffers"))
+ ((derived-mode-p 'magit-cherry-mode)
+ (user-error "Cannot change log arguments in cherry buffers"))))
+
+(defvar magit-log-read-revs-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map crm-local-completion-map)
+ (define-key map "\s" 'self-insert-command)
+ map))
+
+(defun magit-log-read-revs (&optional use-current)
+ (or (and use-current (--when-let (magit-get-current-branch) (list it)))
+ (let* ((choose-completion-string-functions
+ '(crm--choose-completion-string))
+ (minibuffer-completion-table #'crm--collection-fn)
+ (minibuffer-completion-confirm t)
+ (crm-completion-table
+ `(,@(and (file-exists-p (magit-git-dir "FETCH_HEAD"))
+ (list "FETCH_HEAD"))
+ ,@(magit-list-branch-names)))
+ (crm-separator "\\(\\.\\.\\.?\\|[, ]\\)")
+ (default (or (magit-branch-or-commit-at-point)
+ (unless use-current
+ (magit-get-previous-branch))))
+ (input (read-from-minibuffer
+ (format "Log rev,s%s: "
+ (if default (format " (%s)" default) ""))
+ nil magit-log-read-revs-map
+ nil 'magit-revision-history default)))
+ (when (string-equal input "")
+ (or (setq input default)
+ (user-error "Nothing selected")))
+ (split-string input "[, ]" t))))
+
+;;;###autoload
+(defun magit-log-current (revs &optional args files)
+ "Show log for the current branch.
+When `HEAD' is detached or with a prefix argument show log for
+one or more revs read from the minibuffer."
+ (interactive (cons (magit-log-read-revs t)
+ (magit-log-arguments)))
+ (magit-log revs args files))
+
+;;;###autoload
+(defun magit-log (revs &optional args files)
+ "Show log for one or more revs read from the minibuffer.
+The user can input any revision or revisions separated by a
+space, or even ranges, but only branches and tags, and a
+representation of the commit at point, are available as
+completion candidates."
+ (interactive (cons (magit-log-read-revs)
+ (magit-log-arguments)))
+ (require 'magit)
+ (magit-mode-setup #'magit-log-mode revs args files)
+ (magit-log-goto-same-commit))
+
+;;;###autoload
+(defun magit-log-head (&optional args files)
+ "Show log for `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log (list "HEAD") args files))
+
+;;;###autoload
+(defun magit-log-branches (&optional args files)
+ "Show log for all local branches and `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log (if (magit-get-current-branch)
+ (list "--branches")
+ (list "HEAD" "--branches"))
+ args files))
+
+;;;###autoload
+(defun magit-log-all-branches (&optional args files)
+ "Show log for all local and remote branches and `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log (if (magit-get-current-branch)
+ (list "--branches" "--remotes")
+ (list "HEAD" "--branches" "--remotes"))
+ args files))
+
+;;;###autoload
+(defun magit-log-all (&optional args files)
+ "Show log for all references and `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log (if (magit-get-current-branch)
+ (list "--all")
+ (list "HEAD" "--all"))
+ args files))
+
+;;;###autoload
+(defun magit-log-buffer-file (&optional follow beg end)
+ "Show log for the blob or file visited in the current buffer.
+With a prefix argument or when `--follow' is part of
+`magit-log-arguments', then follow renames."
+ (interactive (if (region-active-p)
+ (list current-prefix-arg
+ (1- (line-number-at-pos (region-beginning)))
+ (1- (line-number-at-pos (region-end))))
+ (list current-prefix-arg)))
+ (require 'magit)
+ (-if-let (file (magit-file-relative-name))
+ (magit-mode-setup-internal
+ #'magit-log-mode
+ (list (list (or magit-buffer-refname
+ (magit-get-current-branch)
+ "HEAD"))
+ (let ((args (car (magit-log-arguments))))
+ (when (and follow (not (member "--follow" args)))
+ (push "--follow" args))
+ (when (and beg end)
+ (setq args (cons (format "-L%s,%s:%s" beg end file)
+ (cl-delete "-L" args :test
+ 'string-prefix-p)))
+ (setq file nil))
+ args)
+ (and file (list file)))
+ magit-log-buffer-file-locked)
+ (user-error "Buffer isn't visiting a file"))
+ (magit-log-goto-same-commit))
+
+;;;###autoload
+(defun magit-reflog-current ()
+ "Display the reflog of the current branch."
+ (interactive)
+ (magit-reflog (magit-get-current-branch)))
+
+;;;###autoload
+(defun magit-reflog (ref)
+ "Display the reflog of a branch."
+ (interactive (list (magit-read-local-branch-or-ref "Show reflog for")))
+ (require 'magit)
+ (magit-mode-setup #'magit-reflog-mode ref magit-reflog-arguments))
+
+;;;###autoload
+(defun magit-reflog-head ()
+ "Display the `HEAD' reflog."
+ (interactive)
+ (magit-reflog "HEAD"))
+
+(defun magit-log-toggle-commit-limit ()
+ "Toggle the number of commits the current log buffer is limited to.
+If the number of commits is currently limited, then remove that
+limit. Otherwise set it to 256."
+ (interactive)
+ (magit-log-set-commit-limit (lambda (&rest _) nil)))
+
+(defun magit-log-double-commit-limit ()
+ "Double the number of commits the current log buffer is limited to."
+ (interactive)
+ (magit-log-set-commit-limit '*))
+
+(defun magit-log-half-commit-limit ()
+ "Half the number of commits the current log buffer is limited to."
+ (interactive)
+ (magit-log-set-commit-limit '/))
+
+(defun magit-log-set-commit-limit (fn)
+ (let* ((val (car (magit-log-arguments t)))
+ (arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val))
+ (num (and arg (string-to-number (match-string 1 arg))))
+ (num (if num (funcall fn num 2) 256)))
+ (setq val (delete arg val))
+ (setcar (cdr magit-refresh-args)
+ (if (and num (> num 0))
+ (cons (format "-n%i" num) val)
+ val)))
+ (magit-refresh))
+
+(defun magit-log-get-commit-limit ()
+ (--when-let (--first (string-match "^-n\\([0-9]+\\)?$" it)
+ (car (magit-log-arguments t)))
+ (string-to-number (match-string 1 it))))
+
+(defun magit-log-bury-buffer (&optional arg)
+ "Bury the current buffer or the revision buffer in the same frame.
+Like `magit-mode-bury-buffer' (which see) but with a negative
+prefix argument instead bury the revision buffer, provided it
+is displayed in the current frame."
+ (interactive "p")
+ (if (< arg 0)
+ (let* ((buf (magit-mode-get-buffer 'magit-revision-mode))
+ (win (and buf (get-buffer-window buf (selected-frame)))))
+ (if win
+ (with-selected-window win
+ (with-current-buffer buf
+ (magit-mode-bury-buffer (> (abs arg) 1))))
+ (user-error "No revision buffer in this frame")))
+ (magit-mode-bury-buffer (> arg 1))))
+
+;;;###autoload
+(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)
+ (magit-section-when commit
+ (let ((parent-rev (format "%s^%s" (magit-section-value it) (or n 1))))
+ (-if-let (parent-hash (magit-rev-parse "--short" parent-rev))
+ (-if-let (section (--first (equal (magit-section-value it)
+ parent-hash)
+ (magit-section-siblings it 'next)))
+ (magit-section-goto section)
+ (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))))))
+
+;;; Log Mode
+
+(defvar magit-log-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "\C-c\C-b" 'magit-go-backward)
+ (define-key map "\C-c\C-f" 'magit-go-forward)
+ (define-key map "\C-c\C-n" 'magit-log-move-to-parent)
+ (define-key map "=" 'magit-log-toggle-commit-limit)
+ (define-key map "+" 'magit-log-double-commit-limit)
+ (define-key map "-" 'magit-log-half-commit-limit)
+ (define-key map "q" 'magit-log-bury-buffer)
+ map)
+ "Keymap for `magit-log-mode'.")
+
+(define-derived-mode magit-log-mode magit-mode "Magit Log"
+ "Mode for looking at Git log.
+
+This mode is documented in info node `(magit)Log Buffer'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit at point.
+
+Type \\[magit-branch-popup] to see available branch commands.
+Type \\[magit-merge-popup] to merge the branch or commit at point.
+Type \\[magit-cherry-pick-popup] to apply the commit at point.
+Type \\[magit-reset] to reset HEAD to the commit at point.
+
+\\{magit-log-mode-map}"
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer))
+
+(defvar magit-log-disable-graph-hack-args
+ '("-G" "--grep" "--author")
+ "Arguments which disable the graph speedup hack.")
+
+(defun magit-log-refresh-buffer (revs args files)
+ (setq header-line-format
+ (propertize
+ (concat " Commits in " (mapconcat 'identity revs " ")
+ (and files (concat " touching "
+ (mapconcat 'identity files " "))))
+ 'face 'magit-header-line))
+ (unless (= (length files) 1)
+ (setq args (remove "--follow" args)))
+ (when (--any-p (string-match-p
+ (concat "^" (regexp-opt magit-log-remove-graph-args)) it)
+ args)
+ (setq args (remove "--graph" args)))
+ (unless (member "--graph" args)
+ (setq args (remove "--color" args)))
+ (-when-let* ((limit (magit-log-get-commit-limit))
+ (limit (* 2 limit)) ; increase odds for complete graph
+ (count (and (= (length revs) 1)
+ (> limit 1024) ; otherwise it's fast enough
+ (setq revs (car revs))
+ (not (string-match-p "\\.\\." revs))
+ (not (member revs '("--all" "--branches")))
+ (-none-p (lambda (arg)
+ (--any-p (string-prefix-p it arg)
+ magit-log-disable-graph-hack-args))
+ args)
+ (magit-git-string "rev-list" "--count"
+ "--first-parent" args revs))))
+ (setq revs (if (< (string-to-number count) limit)
+ revs
+ (format "%s~%s..%s" revs limit revs))))
+ (magit-insert-section (logbuf)
+ (magit-insert-log revs args files)))
+
+(defun magit-insert-log (revs &optional args files)
+ "Insert a log section.
+Do not add this to a hook variable."
+ (let ((magit-git-global-arguments
+ (remove "--literal-pathspecs" magit-git-global-arguments)))
+ (magit-git-wash (apply-partially #'magit-log-wash-log 'log)
+ "log"
+ (format "--format=%%h%s %s[%%aN][%%at]%%s%s"
+ (if (member "--decorate" args) "%d" "")
+ (if (member "--show-signature" args)
+ (progn (setq args (remove "--show-signature" args)) "%G?")
+ "")
+ (if (member "++header" args)
+ (if (member "--graph" (setq args (remove "++header" args)))
+ (concat "\n" magit-log-revision-headers-format "\n")
+ (concat "\n\1e" magit-log-revision-headers-format "\1e\n"))
+ ""))
+ (progn
+ (--when-let (--first (string-match "^\\+\\+order=\\(.+\\)$" it) args)
+ (setq args (cons (format "--%s-order" (match-string 1 it))
+ (remove it args))))
+ (if (member "--decorate" args)
+ (cons "--decorate=full" (remove "--decorate" args))
+ args))
+ "--use-mailmap" "--no-prefix" revs "--" files)))
+
+(defvar magit-commit-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-show-commit)
+ (define-key map "a" 'magit-cherry-apply)
+ map)
+ "Keymap for `commit' sections.")
+
+(defvar magit-module-commit-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-show-commit)
+ map)
+ "Keymap for `module-commit' sections.")
+
+(defconst magit-log-heading-re
+ (concat "^"
+ "\\(?4:[-_/|\\*o. ]*\\)" ; graph
+ "\\(?1:[0-9a-fA-F]+\\) " ; sha1
+ "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs
+ "\\(?7:[BGUXYREN]\\)?" ; gpg
+ "\\[\\(?5:[^]]*\\)\\]" ; author
+ "\\[\\(?6:[^]]*\\)\\]" ; date
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-cherry-re
+ (concat "^"
+ "\\(?8:[-+]\\) " ; cherry
+ "\\(?1:[0-9a-fA-F]+\\) " ; sha1
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-module-re
+ (concat "^"
+ "\\(?:\\(?11:[<>]\\) \\)?" ; side
+ "\\(?1:[0-9a-fA-F]+\\) " ; sha1
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-bisect-vis-re
+ (concat "^"
+ "\\(?4:[-_/|\\*o. ]*\\)" ; graph
+ "\\(?1:[0-9a-fA-F]+\\) " ; sha1
+ "\\(?:\\(?3:([^()]+)\\) \\)?" ; refs
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-bisect-log-re
+ (concat "^# "
+ "\\(?3:bad:\\|skip:\\|good:\\) " ; "refs"
+ "\\[\\(?1:[^]]+\\)\\] " ; sha1
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-reflog-re
+ (concat "^"
+ "\\(?1:[^ ]+\\) " ; sha1
+ "\\(?:\\(?:[^@]+@{\\(?6:[^}]+\\)} " ; date
+ "\\(?10:merge \\|autosave \\|restart \\|[^:]+: \\)?" ; refsub
+ "\\(?2:.*\\)?\\)\\| \\)$")) ; msg
+
+(defconst magit-reflog-subject-re
+ (concat "\\(?1:[^ ]+\\) ?" ; command
+ "\\(?2:\\(?: ?-[^ ]+\\)+\\)?" ; option
+ "\\(?: ?(\\(?3:[^)]+\\))\\)?")) ; type
+
+(defconst magit-log-stash-re
+ (concat "^"
+ "\\(?1:[^ ]+\\)" ; "sha1"
+ "\\(?5: \\)" ; "author"
+ "\\(?6:[^ ]+\\) " ; date
+ "\\(?2:.*\\)$")) ; msg
+
+(defvar magit-log-count nil)
+
+(defun magit-log-wash-log (style args)
+ (setq args (-flatten args))
+ (when (and (member "--graph" args)
+ (member "--color" args))
+ (let ((ansi-color-apply-face-function
+ (lambda (beg end face)
+ (put-text-property beg end 'font-lock-face
+ (or face 'magit-log-graph)))))
+ (ansi-color-apply-on-region (point-min) (point-max))))
+ (when (eq style 'cherry)
+ (reverse-region (point-min) (point-max)))
+ (let ((magit-log-count 0)
+ (abbrev (magit-abbrev-length)))
+ (magit-wash-sequence (apply-partially 'magit-log-wash-rev style abbrev))
+ (if (derived-mode-p 'magit-log-mode)
+ (when (eq magit-log-count (magit-log-get-commit-limit))
+ (magit-insert-section (longer)
+ (insert-text-button
+ (substitute-command-keys
+ (format "Type \\<%s>\\[%s] to show more history"
+ 'magit-log-mode-map
+ 'magit-log-double-commit-limit))
+ 'action (lambda (_button)
+ (magit-log-double-commit-limit))
+ 'follow-link t
+ 'mouse-face 'magit-section-highlight)))
+ (unless (equal (car args) "cherry")
+ (insert ?\n)))))
+
+(defun magit-log-wash-rev (style abbrev)
+ (when (derived-mode-p 'magit-log-mode)
+ (cl-incf magit-log-count))
+ (looking-at (pcase style
+ (`log magit-log-heading-re)
+ (`cherry magit-log-cherry-re)
+ (`module magit-log-module-re)
+ (`reflog magit-log-reflog-re)
+ (`stash magit-log-stash-re)
+ (`bisect-vis magit-log-bisect-vis-re)
+ (`bisect-log magit-log-bisect-log-re)))
+ (magit-bind-match-strings
+ (hash msg refs graph author date gpg cherry _ refsub side) nil
+ (let ((align (not (member "--stat" (cadr magit-refresh-args))))
+ (non-graph-re (if (eq style 'bisect-vis)
+ magit-log-bisect-vis-re
+ magit-log-heading-re)))
+ (magit-delete-line)
+ (magit-insert-section section (commit hash)
+ (pcase style
+ (`stash (setf (magit-section-type section) 'stash)
+ ;; Replace blank space with nil for
+ ;; `magit-format-log-margin'.
+ (setq author nil))
+ (`module (setf (magit-section-type section) 'module-commit))
+ (`bisect-log (setq hash (magit-rev-parse "--short" hash))))
+ (when cherry
+ (when (and (derived-mode-p 'magit-refs-mode)
+ magit-refs-show-commit-count)
+ (insert (make-string magit-refs-indent-cherry-lines ?\s)))
+ (insert (propertize cherry 'face (if (string= cherry "-")
+ 'magit-cherry-equivalent
+ 'magit-cherry-unmatched)))
+ (insert ?\s))
+ (when side
+ (insert (propertize side 'face (if (string= side "<")
+ 'magit-cherry-equivalent
+ 'magit-cherry-unmatched)))
+ (insert ?\s))
+ (when align
+ (insert (propertize hash 'face 'magit-hash) ?\s))
+ (when graph
+ (insert graph))
+ (unless align
+ (insert (propertize hash 'face 'magit-hash) ?\s))
+ (when (and refs (not magit-log-show-refname-after-summary))
+ (insert (magit-format-ref-labels refs) ?\s))
+ (when refsub
+ (insert (format "%-2s " (1- magit-log-count)))
+ (insert (magit-reflog-format-subject
+ (substring refsub 0 (if (string-match-p ":" refsub) -2 -1)))))
+ (when msg
+ (insert (propertize msg 'face
+ (pcase (and gpg (aref gpg 0))
+ (?G 'magit-signature-good)
+ (?B 'magit-signature-bad)
+ (?U 'magit-signature-untrusted)
+ (?X 'magit-signature-expired)
+ (?Y 'magit-signature-expired-key)
+ (?R 'magit-signature-revoked)
+ (?E 'magit-signature-error)))))
+ (when (and refs magit-log-show-refname-after-summary)
+ (insert ?\s)
+ (insert (magit-format-ref-labels refs)))
+ (insert ?\n)
+ (when (memq style '(log reflog stash))
+ (goto-char (line-beginning-position))
+ (when (and refsub
+ (string-match "\\`\\([^ ]\\) \\+\\(..\\)\\(..\\)" date))
+ (setq date (+ (string-to-number (match-string 1 date))
+ (* (string-to-number (match-string 2 date)) 60 60)
+ (* (string-to-number (match-string 3 date)) 60))))
+ (save-excursion
+ (backward-char)
+ (magit-format-log-margin author date)))
+ (when (and graph
+ (not (eobp))
+ (not (looking-at non-graph-re)))
+ (when (looking-at "\1e")
+ (magit-insert-heading)
+ (delete-char 1)
+ (magit-insert-section (commit-header)
+ (forward-line)
+ (magit-insert-heading)
+ (re-search-forward "\1e")
+ (backward-delete-char 1)
+ (forward-char)
+ (insert ?\n))
+ (delete-char 1))
+ (if (looking-at "^\\(---\\|\n\s\\|\ndiff\\)")
+ (let ((limit (save-excursion
+ (and (re-search-forward non-graph-re nil t)
+ (match-beginning 0)))))
+ (unless (magit-section-content magit-insert-section--current)
+ (magit-insert-heading))
+ (delete-char (if (looking-at "\n") 1 4))
+ (magit-diff-wash-diffs (list "--stat") limit))
+ (when align
+ (setq align (make-string (1+ abbrev) ? )))
+ (when (and (not (eobp)) (not (looking-at non-graph-re)))
+ (when align
+ (setq align (make-string (1+ abbrev) ? )))
+ (while (and (not (eobp)) (not (looking-at non-graph-re)))
+ (when align
+ (save-excursion (insert align)))
+ (magit-format-log-margin)
+ (forward-line))
+ ;; When `--format' is used and its value isn't one of the
+ ;; predefined formats, then `git-log' does not insert a
+ ;; separator line.
+ (save-excursion
+ (forward-line -1)
+ (looking-at "[-_/|\\*o. ]*"))
+ (setq graph (match-string 0))
+ (unless (string-match-p "[/\\]" graph)
+ (insert graph ?\n))))))))
+ t)
+
+(defun magit-format-log-margin (&optional author date)
+ (-let [(width unit-width duration-spec) magit-log-margin-spec]
+ (when (and date (not author))
+ (setq width (+ (if (= unit-width 1) 1 (1+ unit-width))
+ (if (derived-mode-p 'magit-log-mode) 1 0))))
+ (if date
+ (magit-make-margin-overlay
+ (and author
+ (concat (propertize (truncate-string-to-width
+ (or author "")
+ (- width 1 3 ; gap, digits
+ (if (= unit-width 1) 1 (1+ unit-width))
+ (if (derived-mode-p 'magit-log-mode) 1 0))
+ nil ?\s (make-string 1 magit-ellipsis))
+ 'face 'magit-log-author)
+ " "))
+ (propertize (magit-format-duration
+ (abs (- (float-time)
+ (string-to-number date)))
+ (symbol-value duration-spec)
+ unit-width)
+ 'face 'magit-log-date)
+ (and (derived-mode-p 'magit-log-mode)
+ (propertize " " 'face 'fringe)))
+ (magit-make-margin-overlay
+ (propertize (make-string (1- width) ?\s) 'face 'default)
+ (propertize " " 'face 'fringe)))))
+
+(defun magit-format-duration (duration spec &optional width)
+ (-let [(char unit units weight) (car spec)]
+ (let ((cnt (round (/ duration weight 1.0))))
+ (if (or (not (cdr spec))
+ (>= (/ duration weight) 1))
+ (if (eq width 1)
+ (format "%3i%c" cnt char)
+ (format (if width (format "%%3i %%-%is" width) "%i %s")
+ cnt (if (= cnt 1) unit units)))
+ (magit-format-duration duration (cdr spec) width)))))
+
+(defun magit-log-maybe-show-more-commits (section)
+ "Automatically insert more commit sections in a log.
+Only do so if `point' is on the \"show more\" section,
+and `magit-log-auto-more' is non-nil."
+ (when (and (eq (magit-section-type section) 'longer)
+ magit-log-auto-more)
+ (magit-log-double-commit-limit)
+ (forward-line -1)
+ (magit-section-forward)))
+
+(defvar magit--update-revision-buffer nil)
+
+(defun magit-log-maybe-update-revision-buffer (&optional _)
+ "When moving in the log buffer, update the revision buffer.
+If there is no revision buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-log-mode)
+ (magit-log-maybe-update-revision-buffer-1)))
+
+(defun magit-log-maybe-update-revision-buffer-1 ()
+ (unless magit--update-revision-buffer
+ (-when-let* ((commit (magit-section-when 'commit))
+ (buffer (magit-mode-get-buffer 'magit-revision-mode nil t)))
+ (setq magit--update-revision-buffer (list commit buffer))
+ (run-with-idle-timer
+ magit-update-other-window-delay nil
+ (lambda ()
+ (-let [(rev buf) magit--update-revision-buffer]
+ (setq magit--update-revision-buffer nil)
+ (when (buffer-live-p buf)
+ (let ((magit-display-buffer-noselect t))
+ (apply #'magit-show-commit rev (magit-diff-arguments)))))
+ (setq magit--update-revision-buffer nil))))))
+
+(defvar magit--update-blob-buffer nil)
+
+(defun magit-log-maybe-update-blob-buffer (&optional _)
+ "When moving in the log buffer, update the blob buffer.
+If there is no blob buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-log-mode)
+ (magit-log-maybe-update-blob-buffer-1)))
+
+(defun magit-log-maybe-update-blob-buffer-1 ()
+ (unless magit--update-revision-buffer
+ (-when-let* ((commit (magit-section-when 'commit))
+ (buffer (--first (with-current-buffer it magit-buffer-revision)
+ (-map #'window-buffer (window-list)))))
+ (setq magit--update-blob-buffer (list commit buffer))
+ (run-with-idle-timer
+ magit-update-other-window-delay nil
+ (lambda ()
+ (-let [(rev buf) magit--update-blob-buffer]
+ (setq magit--update-blob-buffer nil)
+ (when (buffer-live-p buf)
+ (save-excursion
+ (with-selected-window (get-buffer-window buf)
+ (with-current-buffer buf
+ (magit-blob-visit (list (magit-rev-parse rev)
+ (magit-file-relative-name
+ magit-buffer-file-name))
+ (line-number-at-pos))))))))))))
+
+(defun magit-log-goto-same-commit ()
+ (-when-let* ((prev magit-previous-section)
+ (rev (cond ((magit-section-match 'commit prev)
+ (magit-section-value prev))
+ ((magit-section-match 'branch prev)
+ (magit-rev-format
+ "%h" (magit-section-value prev)))))
+ (same (--first (equal (magit-section-value it) rev)
+ (magit-section-children magit-root-section))))
+ (goto-char (magit-section-start same))))
+
+;;; Select Mode
+
+(defvar magit-log-select-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-log-mode-map)
+ (define-key map "\C-c\C-b" 'undefined)
+ (define-key map "\C-c\C-f" 'undefined)
+ (define-key map "." 'magit-log-select-pick)
+ (define-key map "e" 'magit-log-select-pick)
+ (define-key map "\C-c\C-c" 'magit-log-select-pick)
+ (define-key map "q" 'magit-log-select-quit)
+ (define-key map "\C-c\C-k" 'magit-log-select-quit)
+ map)
+ "Keymap for `magit-log-select-mode'.")
+
+(put 'magit-log-select-pick :advertised-binding [?\C-c ?\C-c])
+(put 'magit-log-select-quit :advertised-binding [?\C-c ?\C-k])
+
+(define-derived-mode magit-log-select-mode magit-log-mode "Magit Select"
+ "Mode for selecting a commit from history.
+
+This mode is documented in info node `(magit)Select from log'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit at point.
+
+\\<magit-log-select-mode-map>\
+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))
+
+(defun magit-log-select-refresh-buffer (rev args)
+ (magit-insert-section (logbuf)
+ (magit-insert-log rev args)))
+
+(defvar-local magit-log-select-pick-function nil)
+(defvar-local magit-log-select-quit-function nil)
+
+(defun magit-log-select (pick &optional msg quit branch)
+ (declare (indent defun))
+ (magit-mode-setup #'magit-log-select-mode
+ (or branch (magit-get-current-branch) "HEAD")
+ magit-log-select-arguments)
+ (magit-log-goto-same-commit)
+ (setq magit-log-select-pick-function pick)
+ (setq magit-log-select-quit-function quit)
+ (when magit-log-select-show-usage
+ (setq msg (substitute-command-keys
+ (format-spec
+ (if msg
+ (if (string-suffix-p "," msg)
+ (concat msg " or %q to abort")
+ msg)
+ "Type %p to select commit at point, or %q to abort")
+ '((?p . "\\[magit-log-select-pick]")
+ (?q . "\\[magit-log-select-quit]")))))
+ (when (memq magit-log-select-show-usage '(both header-line))
+ (setq header-line-format (propertize (concat " " msg) 'face 'bold)))
+ (when (memq magit-log-select-show-usage '(both echo-area))
+ (message "%s" msg))))
+
+(defun magit-log-select-pick ()
+ "Select the commit at point and act on it.
+Call `magit-log-select-pick-function' with the selected
+commit as argument."
+ (interactive)
+ (let ((fun magit-log-select-pick-function)
+ (rev (magit-commit-at-point)))
+ (quit-restore-window nil 'kill)
+ (funcall fun rev)))
+
+(defun magit-log-select-quit ()
+ "Abort selecting a commit, don't act on any commit."
+ (interactive)
+ (quit-restore-window nil 'kill)
+ (when magit-log-select-quit-function
+ (funcall magit-log-select-quit-function)))
+
+;;; Cherry Mode
+
+(defvar magit-cherry-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "q" 'magit-log-bury-buffer)
+ (define-key map "L" 'magit-toggle-margin)
+ map)
+ "Keymap for `magit-cherry-mode'.")
+
+(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry"
+ "Mode for looking at commits not merged upstream.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit at point.
+
+Type \\[magit-cherry-pick-popup] to apply the commit at point.
+
+\\{magit-cherry-mode-map}"
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer))
+
+;;;###autoload
+(defun magit-cherry (head upstream)
+ "Show commits in a branch that are not merged in the upstream branch."
+ (interactive
+ (let ((head (magit-read-branch "Cherry head")))
+ (list head (magit-read-other-branch "Cherry upstream" head
+ (magit-get-upstream-branch head)))))
+ (require 'magit)
+ (magit-mode-setup #'magit-cherry-mode upstream head))
+
+(defun magit-cherry-refresh-buffer (_upstream _head)
+ (magit-insert-section (cherry)
+ (run-hooks 'magit-cherry-sections-hook)))
+
+(defun magit-insert-cherry-headers ()
+ "Insert headers appropriate for `magit-cherry-mode' buffers."
+ (magit-insert-head-branch-header (nth 1 magit-refresh-args))
+ (magit-insert-upstream-branch-header (nth 1 magit-refresh-args)
+ (nth 0 magit-refresh-args)
+ "Upstream: ")
+ (insert ?\n))
+
+(defun magit-insert-cherry-commits ()
+ "Insert commit sections into a `magit-cherry-mode' buffer."
+ (magit-insert-section (cherries)
+ (magit-insert-heading "Cherry commits:")
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" "--abbrev" magit-refresh-args)))
+
+;;; Reflog Mode
+
+(defvar magit-reflog-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-log-mode-map)
+ (define-key map "L" 'magit-toggle-margin)
+ map)
+ "Keymap for `magit-reflog-mode'.")
+
+(define-derived-mode magit-reflog-mode magit-log-mode "Magit Reflog"
+ "Mode for looking at Git reflog.
+
+This mode is documented in info node `(magit)Reflog'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit at point.
+
+Type \\[magit-cherry-pick-popup] to apply the commit at point.
+Type \\[magit-reset] to reset HEAD to the commit at point.
+
+\\{magit-reflog-mode-map}"
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-reflog-refresh-buffer (ref args)
+ (setq header-line-format
+ (propertize (concat " Reflog for " ref) 'face 'magit-header-line))
+ (magit-insert-section (reflogbuf)
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'reflog)
+ "reflog" "show" "--format=%h %gd %gs" "--date=raw" args ref)))
+
+(defvar magit-reflog-labels
+ '(("commit" . magit-reflog-commit)
+ ("amend" . magit-reflog-amend)
+ ("merge" . magit-reflog-merge)
+ ("checkout" . magit-reflog-checkout)
+ ("branch" . magit-reflog-checkout)
+ ("reset" . magit-reflog-reset)
+ ("rebase" . magit-reflog-rebase)
+ ("cherry-pick" . magit-reflog-cherry-pick)
+ ("initial" . magit-reflog-commit)
+ ("pull" . magit-reflog-remote)
+ ("clone" . magit-reflog-remote)
+ ("autosave" . magit-reflog-commit)
+ ("restart" . magit-reflog-reset)))
+
+(defun magit-reflog-format-subject (subject)
+ (let* ((match (string-match magit-reflog-subject-re subject))
+ (command (and match (match-string 1 subject)))
+ (option (and match (match-string 2 subject)))
+ (type (and match (match-string 3 subject)))
+ (label (if (string= command "commit")
+ (or type command)
+ command))
+ (text (if (string= command "commit")
+ label
+ (mapconcat #'identity
+ (delq nil (list command option type))
+ " "))))
+ (format "%-16s "
+ (propertize text 'face
+ (or (cdr (assoc label magit-reflog-labels))
+ 'magit-reflog-other)))))
+
+;;; Log Sections
+;;;; Standard Log Sections
+
+(defvar magit-unpulled-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
+ map)
+ "Keymap for `unpulled' sections.")
+
+(magit-define-section-jumper magit-jump-to-unpulled-from-upstream
+ "Unpulled from @{upstream}" unpulled "..@{upstream}")
+
+(defun magit-insert-unpulled-from-upstream ()
+ "Insert commits that haven't been pulled from the upstream yet."
+ (when (magit-git-success "rev-parse" "@{upstream}")
+ (magit-insert-section (unpulled "..@{upstream}")
+ (magit-insert-heading
+ (format (propertize "Unpulled from %s:" 'face 'magit-section-heading)
+ (magit-get-upstream-branch)))
+ (magit-insert-log "..@{upstream}" magit-log-section-arguments))))
+
+(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote
+ "Unpulled from <push-remote>" unpulled
+ (concat ".." (magit-get-push-branch)))
+
+(defun magit-insert-unpulled-from-pushremote ()
+ "Insert commits that haven't been pulled from the push-remote yet."
+ (--when-let (magit-get-push-branch)
+ (unless (and (equal (magit-rev-name it)
+ (magit-rev-name "@{upstream}"))
+ (or (memq 'magit-insert-unpulled-from-upstream
+ magit-status-sections-hook)
+ (memq 'magit-insert-unpulled-from-upstream-or-recent
+ magit-status-sections-hook)))
+ (magit-insert-section (unpulled (concat ".." it))
+ (magit-insert-heading
+ (format (propertize "Unpulled from %s:" 'face 'magit-section-heading)
+ (propertize it 'face 'magit-branch-remote)))
+ (magit-insert-log (concat ".." it) magit-log-section-arguments)))))
+
+(defvar magit-unpushed-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
+ map)
+ "Keymap for `unpushed' sections.")
+
+(magit-define-section-jumper magit-jump-to-unpushed-to-upstream
+ "Unpushed to @{upstream}" unpushed "@{upstream}..")
+
+(defun magit-insert-unpushed-to-upstream ()
+ "Insert commits that haven't been pushed to the upstream yet."
+ (when (magit-git-success "rev-parse" "@{upstream}")
+ (magit-insert-section (unpushed "@{upstream}..")
+ (magit-insert-heading
+ (format (propertize "Unmerged into %s:" 'face 'magit-section-heading)
+ (magit-get-upstream-branch)))
+ (magit-insert-log "@{upstream}.." magit-log-section-arguments))))
+
+(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote
+ "Unpushed to <push-remote>" unpushed
+ (concat (magit-get-push-branch) ".."))
+
+(defun magit-insert-unpushed-to-pushremote ()
+ "Insert commits that haven't been pushed to the push-remote yet."
+ (--when-let (magit-get-push-branch)
+ (unless (and (equal (magit-rev-name it)
+ (magit-rev-name "@{upstream}"))
+ (memq 'magit-insert-unpushed-to-upstream
+ magit-status-sections-hook))
+ (magit-insert-section (unpushed (concat it ".."))
+ (magit-insert-heading
+ (format (propertize "Unpushed to %s:" 'face 'magit-section-heading)
+ (propertize it 'face 'magit-branch-remote)))
+ (magit-insert-log (concat it "..") magit-log-section-arguments)))))
+
+(defun magit-insert-recent-commits (&optional collapse)
+ "Insert section showing recent commits.
+Show the last `magit-log-section-commit-count' commits."
+ (let* ((start (format "HEAD~%s" magit-log-section-commit-count))
+ (range (and (magit-rev-verify start)
+ (concat start "..HEAD"))))
+ (magit-insert-section (recent range collapse)
+ (magit-insert-heading "Recent commits:")
+ (magit-insert-log range
+ (cons (format "-%d" magit-log-section-commit-count)
+ magit-log-section-arguments)))))
+
+(defun magit-insert-unpulled-from-upstream-or-recent ()
+ "Insert section showing unpulled or recent commits.
+If an upstream is configured for the current branch and it is
+ahead of the current branch, then show the commits that have
+not yet been pulled into the current branch. If no upstream is
+configured or if the upstream is not ahead of the current branch,
+then show the last `magit-log-section-commit-count' commits."
+ (let ((upstream (magit-rev-parse "@{upstream}")))
+ (if (or (not upstream)
+ (equal upstream (magit-rev-parse "HEAD")))
+ (magit-insert-recent-commits t)
+ (magit-insert-unpulled-from-upstream))))
+
+;;;; Auxiliary Log Sections
+
+(defun magit-insert-unpulled-cherries ()
+ "Insert section showing unpulled commits.
+Like `magit-insert-unpulled-to-upstream' but prefix each commit
+which has not been applied yet (i.e. a commit with a patch-id
+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-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" (magit-abbrev-arg)
+ (magit-get-current-branch) "@{upstream}"))))
+
+(defun magit-insert-unpushed-cherries ()
+ "Insert section showing unpushed commits.
+Like `magit-insert-unpushed-to-upstream' but prefix each commit
+which has not been applied to upstream yet (i.e. a commit with
+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-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" (magit-abbrev-arg) "@{upstream}"))))
+
+;;; Buffer Margins
+
+(defvar-local magit-set-buffer-margin-refresh nil)
+
+(defvar-local magit-show-margin nil)
+(put 'magit-show-margin 'permanent-local t)
+
+(defun magit-toggle-margin ()
+ "Show or hide the Magit margin."
+ (interactive)
+ (unless (derived-mode-p 'magit-log-mode 'magit-status-mode 'magit-refs-mode)
+ (user-error "Buffer doesn't contain any logs"))
+ (magit-set-buffer-margin (not (cdr (window-margins)))))
+
+(defun magit-maybe-show-margin ()
+ "Maybe show the margin, depending on the major-mode and an option.
+Supported modes are `magit-log-mode' and `magit-reflog-mode',
+and the respective options are `magit-log-show-margin' and
+`magit-reflog-show-margin'."
+ (if (local-variable-p 'magit-show-margin)
+ (magit-set-buffer-margin magit-show-margin)
+ (pcase major-mode
+ (`magit-log-mode (magit-set-buffer-margin magit-log-show-margin))
+ (`magit-reflog-mode (magit-set-buffer-margin magit-reflog-show-margin)))))
+
+(defun magit-set-buffer-margin (enable)
+ (let ((width (cond ((not enable) nil)
+ ((derived-mode-p 'magit-reflog-mode)
+ (+ (cadr magit-log-margin-spec) 5))
+ (t (car magit-log-margin-spec)))))
+ (setq magit-show-margin width)
+ (when (and enable magit-set-buffer-margin-refresh)
+ (magit-refresh))
+ (-when-let (window (get-buffer-window))
+ (with-selected-window window
+ (set-window-margins nil (car (window-margins)) width)
+ (if enable
+ (add-hook 'window-configuration-change-hook
+ 'magit-set-buffer-margin-1 nil t)
+ (remove-hook 'window-configuration-change-hook
+ 'magit-set-buffer-margin-1 t))))))
+
+(defun magit-set-buffer-margin-1 ()
+ (-when-let (window (get-buffer-window))
+ (with-selected-window window
+ (set-window-margins nil (car (window-margins)) magit-show-margin))))
+
+(defun magit-make-margin-overlay (&rest strings)
+ ;; Don't put the overlay on the complete line to work around #1880.
+ (let ((o (make-overlay (1+ (line-beginning-position))
+ (line-end-position)
+ nil t)))
+ (overlay-put o 'evaporate t)
+ (overlay-put o 'before-string
+ (propertize "o" 'display
+ (list '(margin right-margin)
+ (apply #'concat strings))))))
+
+;;; magit-log.el ends soon
+
+(define-obsolete-variable-alias 'magit-log-section-args
+ 'magit-log-section-arguments "Magit 2.2.0")
+(define-obsolete-function-alias 'magit-insert-unpulled-or-recent-commits
+ 'magit-insert-unpulled-from-upstream-or-recent "Magit 2.4.0")
+
+(provide 'magit-log)
+;; Local Variables:
+;; coding: utf-8
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-log.el ends here
--- /dev/null
+;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements the abstract major-mode `magit-mode' from
+;; which almost all other Magit major-modes derive. The code in here
+;; is mostly concerned with creating and refreshing Magit buffers.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+
+(require 'magit-section)
+(require 'magit-git)
+
+;; For `magit-xref-insert-buttons' from `magit'
+(defvar magit-diff-show-xref-buttons)
+(defvar magit-revision-show-xref-buttons)
+;; For `magit-refresh' and `magit-refresh-all'
+(declare-function magit-auto-revert-buffers 'magit-autorevert)
+
+(require 'format-spec)
+(require 'help-mode)
+
+;;; Options
+
+(defcustom magit-mode-hook
+ '(magit-load-config-extensions
+ magit-xref-setup)
+ "Hook run when entering a mode derived from Magit mode."
+ :group 'magit-modes
+ :type 'hook
+ :options '(magit-load-config-extensions
+ magit-xref-setup
+ bug-reference-mode))
+
+(defcustom magit-mode-setup-hook
+ '(magit-maybe-save-repository-buffers
+ magit-maybe-show-margin)
+ "Hook run by `magit-mode-setup'."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'hook
+ :options '(magit-maybe-save-repository-buffers
+ magit-maybe-show-margin))
+
+(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers)
+ "Hook run before refreshing in `magit-refresh'.
+
+This hook, or `magit-post-refresh-hook', should be used
+for functions that are not tied to a particular buffer.
+
+To run a function with a particular buffer current, use
+`magit-refresh-buffer-hook' and use `derived-mode-p'
+inside your function."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-modes
+ :type 'hook
+ :options '(magit-maybe-save-repository-buffers))
+
+(defcustom magit-post-refresh-hook nil
+ "Hook run after refreshing in `magit-refresh'.
+
+This hook, or `magit-pre-refresh-hook', should be used
+for functions that are not tied to a particular buffer.
+
+To run a function with a particular buffer current, use
+`magit-refresh-buffer-hook' and use `derived-mode-p'
+inside your function."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-modes
+ :type 'hook)
+
+(defcustom magit-display-buffer-function 'magit-display-buffer-traditional
+ "The function used display a Magit buffer.
+
+All Magit buffers (buffers whose major-modes derive from
+`magit-mode') are displayed using `magit-display-buffer',
+which in turn uses the function specified here."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :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")))
+
+(unless (find-lisp-object-file-name 'magit-pre-display-buffer-hook 'defvar)
+ (add-hook 'magit-pre-display-buffer-hook 'magit-save-window-configuration))
+(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration)
+ "Hook run by `magit-display-buffer' before displaying the buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'hook
+ :options '(magit-save-window-configuration))
+
+(unless (find-lisp-object-file-name 'magit-post-display-buffer-hook 'defvar)
+ (add-hook 'magit-post-display-buffer-hook 'magit-maybe-set-dedicated))
+(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated)
+ "Hook run by `magit-display-buffer' after displaying the buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'hook
+ :options '(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-modes
+ :type '(radio (function-item magit-generate-buffer-name-default-function)
+ (function :tag "Function")))
+
+(defcustom magit-buffer-name-format "*%M%v: %t"
+ "The format string used to name Magit buffers.
+
+The following %-sequences are supported:
+
+`%m' The name of the major-mode, but with the `-mode' suffix
+ removed.
+
+`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'.
+
+`%v' The value the buffer is locked to, in parentheses, or an empty
+ string if the buffer is not locked to a value.
+
+`%V' Like \"%v\", but the string is prefixed with a space, unless it
+ is an empty string.
+
+`%t' The top-level directory of the working tree of the
+ repository, or if `magit-uniquify-buffer-names' is non-nil
+ an abbreviation of that.
+
+The value should always contain either \"%m\" or \"%M\" as well as
+\"%t\". If `magit-uniquify-buffer-names' is non-nil, then the
+value must end with \"%t\".
+
+This is used by `magit-generate-buffer-name-default-function'.
+If another `magit-generate-buffer-name-function' is used, then
+it may not respect this option, or on the contrary it may
+support additional %-sequences."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'string)
+
+(defcustom magit-uniquify-buffer-names t
+ "Whether to uniquify the names of Magit buffers."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'boolean)
+
+(defcustom magit-bury-buffer-function 'magit-restore-window-configuration
+ "The function used to bury or kill the current Magit buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type '(radio (function-item quit-window)
+ (function-item magit-mode-quit-window)
+ (function-item magit-restore-window-configuration)
+ (function :tag "Function")))
+
+(defcustom magit-region-highlight-hook
+ '(magit-section-update-region magit-diff-update-hunk-region)
+ "Functions used to highlight the region.
+Each function is run with the current section as only argument
+until one of them returns non-nil. When multiple sections are
+selected, then this hook does not run and the region is not
+displayed. Otherwise fall back to regular region highlighting."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-modes
+ :type 'hook
+ :options '(magit-section-update-region magit-diff-update-hunk-region))
+
+(defcustom magit-refresh-verbose nil
+ "Whether to revert Magit buffers verbosely."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-modes
+ :type 'boolean)
+
+(defcustom magit-refresh-buffer-hook nil
+ "Normal hook for `magit-refresh-buffer' to run after refreshing."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-modes
+ :type 'hook)
+
+(defcustom magit-refresh-status-buffer t
+ "Whether the status buffer is refreshed after running git.
+
+When this is non-nil, then the status buffer is automatically
+refreshed after running git for side-effects, in addition to the
+current Magit buffer, which is always refreshed automatically.
+
+Only set this to nil after exhausting all other options to
+improve performance."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-status
+ :type 'boolean)
+
+(defcustom magit-save-repository-buffers t
+ "Whether to save file-visiting buffers when appropriate.
+
+If this is non-nil then all modified file-visiting buffers
+belonging to the current repository may be saved before running
+commands, before creating new Magit buffers, and before
+explicitly refreshing such buffers. If this is `dontask' then
+this is done without user intervention, if it is t then the user
+has to confirm each save. `dontask' is the recommended setting."
+ :group 'magit
+ :type '(choice (const :tag "Never" nil)
+ (const :tag "Ask" t)
+ (const :tag "Save without asking" dontask)))
+
+(defcustom magit-keep-region-overlay nil
+ "Whether to keep the region overlay when there is a valid selection.
+
+By default Magit removes the regular region overlay if, and only
+if, that region constitutes a valid selection as understood by
+Magit commands. Otherwise it does not remove that overlay, and
+the region looks like it would in other buffers.
+
+There are two types of such valid selections: hunk-internal
+regions and regions that select two or more sibling sections.
+In such cases Magit removes the region overlay and instead
+highlights a slightly larger range. All text (for hunk-internal
+regions) or the headings of all sections (for sibling selections)
+that are inside that range (not just inside the region) are acted
+on by commands such as the staging command. This buffer range
+begins at the beginning of the line on which the region begins
+and ends at the end of the line on which the region ends.
+
+Because Magit acts on this larger range and not the region, it is
+actually quite important to visualize that larger range. If we
+don't do that, then one might think that these commands act on
+the region instead. If you want to *also* visualize the region,
+then set this option to t. But please note that when the region
+does *not* constitute a valid selection, then the region is
+*always* visualized as usual, and that it is usually under such
+circumstances that you want to use a non-magit command to act on
+the region.
+
+Besides keeping the region overlay, setting this option to t also
+causes all face properties, except for `:foreground', to be
+ignored for the faces used to highlight headings of selected
+sections. This avoids the worst conflicts that result from
+displaying the region and the selection overlays at the same
+time. We are not interested in dealing with other conflicts.
+In fact we *already* provide a way to avoid all of these
+conflicts: *not* changing the value of this option.
+
+It should be clear by now that we consider it a mistake to set
+this to display the region when the Magit selection is also
+visualized, but since it has been requested a few times and
+because it doesn't cost much to offer this option we do so.
+However that might change. If the existence of this option
+starts complicating other things, then it will be removed."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'boolean)
+
+;;; Magit Mode
+
+(defvar magit-mode-map
+ (let ((map (make-keymap)))
+ (suppress-keymap map t)
+ (define-key map "\t" 'magit-section-toggle)
+ (define-key map [C-tab] 'magit-section-cycle)
+ (define-key map [M-tab] 'magit-section-cycle-diffs)
+ (define-key map [S-tab] 'magit-section-cycle-global)
+ ;; Next two are for backward compatibility.
+ (define-key map [s-tab] 'magit-section-cycle-global)
+ (define-key map [backtab] 'magit-section-cycle-global)
+ (define-key map "^" 'magit-section-up)
+ (define-key map "n" 'magit-section-forward)
+ (define-key map "p" 'magit-section-backward)
+ (define-key map "\M-n" 'magit-section-forward-sibling)
+ (define-key map "\M-p" 'magit-section-backward-sibling)
+ (define-key map "+" 'magit-diff-more-context)
+ (define-key map "-" 'magit-diff-less-context)
+ (define-key map "0" 'magit-diff-default-context)
+ (define-key map "1" 'magit-section-show-level-1)
+ (define-key map "2" 'magit-section-show-level-2)
+ (define-key map "3" 'magit-section-show-level-3)
+ (define-key map "4" 'magit-section-show-level-4)
+ (define-key map "\M-1" 'magit-section-show-level-1-all)
+ (define-key map "\M-2" 'magit-section-show-level-2-all)
+ (define-key map "\M-3" 'magit-section-show-level-3-all)
+ (define-key map "\M-4" 'magit-section-show-level-4-all)
+ (define-key map "g" 'magit-refresh)
+ (define-key map "G" 'magit-refresh-all)
+ (define-key map "q" 'magit-mode-bury-buffer)
+ (define-key map "$" 'magit-process-buffer)
+ (define-key map "a" 'magit-cherry-apply)
+ (define-key map "A" 'magit-cherry-pick-popup)
+ (define-key map "b" 'magit-branch-popup)
+ (define-key map "B" 'magit-bisect-popup)
+ (define-key map "c" 'magit-commit-popup)
+ (define-key map "d" 'magit-diff-popup)
+ (define-key map "D" 'magit-diff-refresh-popup)
+ (define-key map "h" 'magit-dispatch-popup)
+ (define-key map "?" 'magit-dispatch-popup)
+ (define-key map "\C-c\C-c" 'magit-dispatch-popup)
+ (define-key map "\C-c\C-e" 'magit-dispatch-popup)
+ (define-key map "e" 'magit-ediff-dwim)
+ (define-key map "E" 'magit-ediff-popup)
+ (define-key map "f" 'magit-fetch-popup)
+ (define-key map "F" 'magit-pull-popup)
+ (define-key map "i" 'magit-gitignore)
+ (define-key map "I" 'magit-gitignore-locally)
+ (define-key map "k" 'magit-delete-thing)
+ (define-key map "K" 'magit-file-untrack)
+ (define-key map "l" 'magit-log-popup)
+ (define-key map "L" 'magit-log-refresh-popup)
+ (define-key map "m" 'magit-merge-popup)
+ (define-key map "M" 'magit-remote-popup)
+ (define-key map "o" 'magit-submodule-popup)
+ (define-key map "O" 'magit-subtree-popup)
+ (define-key map "P" 'magit-push-popup)
+ (define-key map "r" 'magit-rebase-popup)
+ (define-key map "R" 'magit-file-rename)
+ (define-key map "t" 'magit-tag-popup)
+ (define-key map "T" 'magit-notes-popup)
+ (define-key map "\r" 'magit-visit-thing)
+ (define-key map [C-return] 'magit-visit-thing)
+ (define-key map "\M-\r" 'magit-dired-jump)
+ (define-key map "\s" 'magit-diff-show-or-scroll-up)
+ (define-key map "\d" 'magit-diff-show-or-scroll-down)
+ (define-key map "s" 'magit-stage-file)
+ (define-key map "S" 'magit-stage-modified)
+ (define-key map "u" 'magit-unstage-file)
+ (define-key map "U" 'magit-unstage-all)
+ (define-key map "v" 'magit-revert-no-commit)
+ (define-key map "V" 'magit-revert-popup)
+ (define-key map "w" 'magit-am-popup)
+ (define-key map "W" 'magit-patch-popup)
+ (define-key map "x" 'magit-reset)
+ (define-key map "X" 'magit-reset-popup)
+ (define-key map "y" 'magit-show-refs-popup)
+ (define-key map "Y" 'magit-cherry)
+ (define-key map "z" 'magit-stash-popup)
+ (define-key map "Z" 'magit-stash-popup)
+ (define-key map ":" 'magit-git-command)
+ (define-key map "!" 'magit-run-popup)
+ (define-key map "\C-xa" 'magit-add-change-log-entry)
+ (define-key map "\C-x4a" 'magit-add-change-log-entry-other-window)
+ (define-key map "\C-w" 'magit-copy-section-value)
+ (define-key map "\M-w" 'magit-copy-buffer-revision)
+ (define-key map [remap evil-previous-line] 'evil-previous-visual-line)
+ (define-key map [remap evil-next-line] 'evil-next-visual-line)
+ map)
+ "Parent keymap for all keymaps of modes derived from `magit-mode'.")
+
+(defun magit-delete-thing ()
+ "This is a placeholder command.
+Where applicable, section-specific keymaps bind another command
+which deletes the thing at point."
+ (interactive)
+ (user-error "There is no thing at point that could be deleted"))
+
+(defun magit-visit-thing ()
+ "This is a placeholder command.
+Where applicable, section-specific keymaps bind another command
+which visits the thing at point."
+ (interactive)
+ (user-error "There is no thing at point that could be visited"))
+
+(easy-menu-define magit-mode-menu magit-mode-map
+ "Magit menu"
+ '("Magit"
+ ["Refresh" magit-refresh t]
+ ["Refresh all" magit-refresh-all t]
+ "---"
+ ["Stage" magit-stage t]
+ ["Stage modified" magit-stage-modified t]
+ ["Unstage" magit-unstage t]
+ ["Reset index" magit-reset-index t]
+ ["Commit" magit-commit-popup t]
+ ["Add log entry" magit-commit-add-log t]
+ ["Tag" magit-tag t]
+ "---"
+ ["Diff working tree" magit-diff-working-tree t]
+ ["Diff" magit-diff t]
+ ("Log"
+ ["Log" magit-log t]
+ ["Reflog" magit-reflog t]
+ ["Extended..." magit-log-popup t])
+ "---"
+ ["Cherry pick" magit-cherry-pick t]
+ ["Revert commit" magit-revert-popup t]
+ "---"
+ ["Ignore" magit-gitignore t]
+ ["Ignore locally" magit-gitignore-locally t]
+ ["Discard" magit-discard t]
+ ["Reset head" magit-reset-head t]
+ ["Stash" magit-stash t]
+ ["Snapshot" magit-snapshot t]
+ "---"
+ ["Branch..." magit-checkout t]
+ ["Merge" magit-merge t]
+ ["Ediff resolve" magit-ediff-resolve t]
+ ["Rebase..." magit-rebase-popup t]
+ "---"
+ ["Push" magit-push t]
+ ["Pull" magit-pull t]
+ ["Remote update" magit-fetch-all t]
+ ("Submodule"
+ ["Submodule update" magit-submodule-update t]
+ ["Submodule update and init" magit-submodule-setup t]
+ ["Submodule init" magit-submodule-init t]
+ ["Submodule sync" magit-submodule-sync t])
+ "---"
+ ("Extensions")
+ "---"
+ ["Display Git output" magit-process-buffer t]
+ ["Quit Magit" magit-mode-bury-buffer t]))
+
+(defun magit-load-config-extensions ()
+ "Load Magit extensions that are defined at the Git config layer."
+ (dolist (ext (magit-get-all "magit.extension"))
+ (let ((sym (intern (format "magit-%s-mode" ext))))
+ (when (fboundp sym)
+ (funcall sym 1)))))
+
+(define-derived-mode magit-mode special-mode "Magit"
+ "Parent major mode from which Magit major modes inherit.
+
+Magit is documented in info node `(magit)'."
+ :group 'magit-modes
+ (buffer-disable-undo)
+ (setq truncate-lines t)
+ (setq buffer-read-only t)
+ (setq-local line-move-visual t) ; see #1771
+ (setq show-trailing-whitespace nil)
+ (setq list-buffers-directory default-directory)
+ (hack-dir-local-variables-non-file-buffer)
+ (make-local-variable 'text-property-default-nonsticky)
+ (push (cons 'keymap t) text-property-default-nonsticky)
+ (add-hook 'post-command-hook #'magit-section-update-highlight t t)
+ (setq-local redisplay-highlight-region-function 'magit-highlight-region)
+ (setq-local redisplay-unhighlight-region-function 'magit-unhighlight-region)
+ (when (bound-and-true-p global-linum-mode)
+ (linum-mode -1))
+ (when (and (fboundp 'nlinum-mode)
+ (bound-and-true-p global-nlinum-mode))
+ (nlinum-mode -1)))
+
+(defvar-local magit-region-overlays nil)
+
+(defun magit-delete-region-overlays ()
+ (mapc #'delete-overlay magit-region-overlays)
+ (setq magit-region-overlays nil))
+
+(defun magit-highlight-region (start end window rol)
+ (magit-delete-region-overlays)
+ (if (and (run-hook-with-args-until-success 'magit-region-highlight-hook
+ (magit-current-section))
+ (not magit-keep-region-overlay))
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol)
+ (funcall (default-value 'redisplay-highlight-region-function)
+ start end window rol)))
+
+(defun magit-unhighlight-region (rol)
+ (setq magit-section-highlighted-section nil)
+ (magit-delete-region-overlays)
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol))
+
+(defvar-local magit-refresh-args nil
+ "The arguments used to refresh the current buffer.")
+(put 'magit-refresh-args 'permanent-local t)
+
+(defvar-local magit-previous-section nil)
+(put 'magit-previous-section 'permanent-local t)
+
+(defun magit-mode-setup (mode &rest args)
+ "Setup up a MODE buffer using ARGS to generate its content."
+ (magit-mode-setup-internal mode args))
+
+(defun magit-mode-setup-internal (mode args &optional locked)
+ "Setup up a MODE buffer using ARGS to generate its content.
+When optional LOCKED is non-nil, then create a buffer that is
+locked to its value, which is derived from MODE and ARGS."
+ (let ((buffer (magit-mode-get-buffer
+ mode t nil
+ (and locked (magit-buffer-lock-value mode args))))
+ (section (magit-current-section)))
+ (with-current-buffer buffer
+ (setq magit-previous-section section)
+ (setq magit-refresh-args args)
+ (funcall mode))
+ (magit-display-buffer buffer)
+ (with-current-buffer buffer
+ (run-hooks 'magit-mode-setup-hook)
+ (magit-refresh-buffer))))
+
+(defvar magit-display-buffer-noselect nil
+ "If non-nil, then `magit-display-buffer' doesn't call `select-window'.")
+
+(defun magit-display-buffer (buffer)
+ "Display BUFFER in some window and maybe select it.
+
+Display the buffer using `magit-display-buffer-function' and
+then, unless `magit-display-buffer-noselect' is non-nil, select
+the window which was used to display the buffer.
+
+Also run the hooks `magit-pre-display-buffer-hook'
+and `magit-post-display-buffer-hook'."
+ (with-current-buffer buffer
+ (run-hooks 'magit-pre-display-buffer-hook))
+ (let ((window (funcall magit-display-buffer-function buffer)))
+ (unless magit-display-buffer-noselect
+ (select-window window)))
+ (with-current-buffer buffer
+ (run-hooks 'magit-post-display-buffer-hook)))
+
+(defun magit-display-buffer-traditional (buffer)
+ "Display BUFFER the way this has traditionally been done."
+ (display-buffer
+ buffer (if (and (derived-mode-p 'magit-mode)
+ (not (memq (with-current-buffer buffer major-mode)
+ '(magit-process-mode
+ magit-revision-mode
+ magit-diff-mode
+ magit-stash-mode
+ magit-status-mode))))
+ '(display-buffer-same-window)
+ nil))) ; display in another window
+
+(defun magit-display-buffer-same-window-except-diff-v1 (buffer)
+ "Display BUFFER in the selected window except for some modes.
+If a buffer's `major-mode' derives from `magit-diff-mode' or
+`magit-process-mode', display it in another window. Display all
+other buffers in the selected window."
+ (display-buffer
+ buffer (if (with-current-buffer buffer
+ (derived-mode-p 'magit-diff-mode 'magit-process-mode))
+ nil ; display in another window
+ '(display-buffer-same-window))))
+
+(defun magit--display-buffer-fullframe (buffer alist)
+ (-when-let (window (or (display-buffer-reuse-window buffer alist)
+ (display-buffer-same-window buffer alist)
+ (display-buffer-pop-up-window buffer alist)
+ (display-buffer-use-some-window buffer alist)))
+ (delete-other-windows window)
+ window))
+
+(defun magit-display-buffer-fullframe-status-v1 (buffer)
+ "Display BUFFER, filling entire frame if BUFFER is a status buffer.
+Otherwise, behave like `magit-display-buffer-traditional'."
+ (if (eq (with-current-buffer buffer major-mode)
+ 'magit-status-mode)
+ (display-buffer buffer '(magit--display-buffer-fullframe))
+ (magit-display-buffer-traditional buffer)))
+
+(defun magit--display-buffer-topleft (buffer alist)
+ (or (display-buffer-reuse-window buffer alist)
+ (-when-let (window2 (display-buffer-pop-up-window buffer alist))
+ (let ((window1 (get-buffer-window))
+ (buffer1 (current-buffer))
+ (buffer2 (window-buffer window2))
+ (w2-quit-restore (window-parameter window2 'quit-restore)))
+ (set-window-buffer window1 buffer2)
+ (set-window-buffer window2 buffer1)
+ (select-window window2)
+ ;; Swap some window state that `magit-mode-quit-window' and
+ ;; `quit-restore-window' inspect.
+ (set-window-prev-buffers window2 (cdr (window-prev-buffers window1)))
+ (set-window-prev-buffers window1 nil)
+ (set-window-parameter window2 'magit-dedicated
+ (window-parameter window1 'magit-dedicated))
+ (set-window-parameter window1 'magit-dedicated t)
+ (set-window-parameter window1 'quit-restore
+ (list 'window 'window
+ (nth 2 w2-quit-restore)
+ (nth 3 w2-quit-restore)))
+ (set-window-parameter window2 'quit-restore nil)
+ window1))))
+
+(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer)
+ "Display BUFFER, filling entire frame if BUFFER is a status buffer.
+When BUFFER derives from `magit-diff-mode' or
+`magit-process-mode', try to display BUFFER to the top or left of
+the current buffer rather than to the bottom or right, as
+`magit-display-buffer-fullframe-status-v1' would. Whether the
+split is made vertically or horizontally is determined by
+`split-window-preferred-function'."
+ (display-buffer
+ buffer
+ (cond ((eq (with-current-buffer buffer major-mode)
+ 'magit-status-mode)
+ '(magit--display-buffer-fullframe))
+ ((with-current-buffer buffer
+ (derived-mode-p 'magit-diff-mode 'magit-process-mode))
+ '(magit--display-buffer-topleft))
+ (t
+ '(display-buffer-same-window)))))
+
+(defun magit--display-buffer-fullcolumn (buffer alist)
+ (-when-let (window (or (display-buffer-reuse-window buffer alist)
+ (display-buffer-same-window buffer alist)
+ (display-buffer-below-selected buffer alist)))
+ (delete-other-windows-vertically window)
+ window))
+
+(defun magit-display-buffer-fullcolumn-most-v1 (buffer)
+ "Display BUFFER using the full column except in some cases.
+For most cases where BUFFER's `major-mode' derives from
+`magit-mode', display it in the selected window and grow that
+window to the full height of the frame, deleting other windows in
+that column as necessary. However, display BUFFER in another
+window if 1) BUFFER's mode derives from `magit-process-mode', or
+2) BUFFER's mode derives from `magit-diff-mode', provided that
+the mode of the current buffer derives from `magit-log-mode' or
+`magit-cherry-mode'."
+ (display-buffer
+ buffer
+ (cond ((and (derived-mode-p 'magit-log-mode 'magit-cherry-mode)
+ (with-current-buffer buffer
+ (derived-mode-p 'magit-diff-mode)))
+ nil)
+ ((with-current-buffer buffer
+ (derived-mode-p 'magit-process-mode))
+ nil)
+ (t
+ '(magit--display-buffer-fullcolumn)))))
+
+(defun magit-maybe-set-dedicated ()
+ "Mark the selected window as dedicated if appropriate.
+
+If a new window was created to display the buffer, then remember
+that fact. That information is used by `magit-mode-quit-window',
+to determine whether the window should be deleted when its last
+Magit buffer is buried."
+ (let ((window (get-buffer-window (current-buffer))))
+ (when (and (window-live-p window)
+ (not (window-prev-buffers window)))
+ (set-window-parameter window 'magit-dedicated t))))
+
+(defvar-local magit--default-directory nil
+ "Value of `default-directory' when buffer is generated.
+This exists to prevent a let-bound `default-directory' from
+tricking `magit-mode-get-buffer' or `magit-mode-get-buffers' into
+thinking a buffer belongs to a repo that it doesn't.")
+(put 'magit--default-directory 'permanent-local 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))))
+
+(defvar-local magit-buffer-locked-p nil)
+(put 'magit-buffer-locked-p 'permanent-local t)
+
+(defun magit-mode-get-buffer (mode &optional create frame value)
+ (-if-let (topdir (magit-toplevel))
+ (or (--first (with-current-buffer it
+ (and (eq major-mode mode)
+ (equal magit--default-directory topdir)
+ (if value
+ (and magit-buffer-locked-p
+ (equal (magit-buffer-lock-value) value))
+ (not magit-buffer-locked-p))))
+ (if frame
+ (-map #'window-buffer
+ (window-list (unless (eq frame t) frame)))
+ (buffer-list)))
+ (and create
+ (let ((default-directory topdir))
+ (magit-generate-new-buffer mode value))))
+ (user-error "Not inside a Git repository")))
+
+(defun magit-generate-new-buffer (mode &optional value)
+ (let* ((name (funcall magit-generate-buffer-name-function mode value))
+ (buffer (generate-new-buffer name)))
+ (with-current-buffer buffer
+ (setq magit--default-directory default-directory)
+ (setq magit-buffer-locked-p (and value t)))
+ (when magit-uniquify-buffer-names
+ (add-to-list 'uniquify-list-buffers-directory-modes mode)
+ (with-current-buffer buffer
+ (setq list-buffers-directory default-directory))
+ (let ((uniquify-buffer-name-style
+ (if (memq uniquify-buffer-name-style '(nil forward))
+ 'post-forward-angle-brackets
+ uniquify-buffer-name-style)))
+ (uniquify-rationalize-file-buffer-names
+ name (file-name-directory (directory-file-name default-directory))
+ buffer)))
+ buffer))
+
+(defun magit-generate-buffer-name-default-function (mode &optional value)
+ (let ((m (substring (symbol-name mode) 0 -5))
+ (v (and value (format "%s" (if (listp value) value (list value))))))
+ (format-spec
+ magit-buffer-name-format
+ `((?m . ,m)
+ (?M . ,(if (eq mode 'magit-status-mode) "magit" m))
+ (?v . ,(or v ""))
+ (?V . ,(if v (concat " " v) ""))
+ (?t . ,(if magit-uniquify-buffer-names
+ (file-name-nondirectory
+ (directory-file-name default-directory))
+ (abbreviate-file-name default-directory)))))))
+
+(defun magit-toggle-buffer-lock ()
+ "Lock the current buffer to its value or unlock it.
+
+Locking a buffer to its value prevents it from being reused to
+display another value. The name of a locked buffer contains its
+value, which allows telling it apart from other locked buffers
+and the unlocked buffer.
+
+Not all Magit buffers can be locked to their values, for example
+it wouldn't make sense to lock a status buffer.
+
+There can only be a single unlocked buffer using a certain
+major-mode per repository. So when a buffer is being unlocked
+and another unlocked buffer already exists for that mode and
+repository, then the former buffer is instead deleted and the
+latter is displayed in its place."
+ (interactive)
+ (if magit-buffer-locked-p
+ (-if-let (unlocked (magit-mode-get-buffer major-mode))
+ (let ((locked (current-buffer)))
+ (switch-to-buffer unlocked nil t)
+ (kill-buffer locked))
+ (setq magit-buffer-locked-p nil)
+ (rename-buffer (funcall magit-generate-buffer-name-function
+ major-mode)))
+ (-if-let (value (magit-buffer-lock-value))
+ (-if-let (locked (magit-mode-get-buffer major-mode nil nil value))
+ (let ((unlocked (current-buffer)))
+ (switch-to-buffer locked nil t)
+ (kill-buffer unlocked))
+ (setq magit-buffer-locked-p t)
+ (rename-buffer (funcall magit-generate-buffer-name-function
+ major-mode value)))
+ (user-error "Buffer has no value it could be locked to"))))
+
+(cl-defun magit-buffer-lock-value
+ (&optional (mode major-mode)
+ (args magit-refresh-args))
+ (cl-case mode
+ (magit-cherry-mode
+ (-let [(upstream head) args]
+ (concat head ".." upstream)))
+ (magit-diff-mode
+ (-let [(rev-or-range const _args files) args]
+ (nconc (cons (or rev-or-range
+ (if (member "--cached" const)
+ (progn (setq const (delete "--cached" const))
+ 'staged)
+ 'unstaged))
+ const)
+ (and files (cons "--" files)))))
+ (magit-log-mode
+ (-let [(revs _args files) args]
+ (if (and revs files)
+ (append revs (cons "--" files))
+ (append revs files))))
+ (magit-refs-mode
+ (-let [(ref args) args]
+ (cons (or ref "HEAD") args)))
+ (magit-revision-mode
+ (-let [(rev __const _args files) args]
+ (if files (cons rev files) (list rev))))
+ ((magit-reflog-mode ; (ref ~args)
+ magit-stash-mode ; (stash _const _args _files)
+ magit-stashes-mode) ; (ref)
+ (car args))))
+
+(defun magit-mode-bury-buffer (&optional kill-buffer)
+ "Bury the current buffer.
+With a prefix argument, kill the buffer instead.
+This is done using `magit-bury-buffer-function'."
+ (interactive "P")
+ (funcall magit-bury-buffer-function kill-buffer))
+
+(defun magit-mode-quit-window (kill-buffer)
+ "Quit the selected window and bury its buffer.
+
+This behaves similar to `quit-window', but when the window
+was originally created to display a Magit buffer and the
+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)))
+ (quit-window kill-buffer)
+ (let ((window (selected-window)))
+ (quit-window kill-buffer)
+ (when (window-live-p window)
+ (delete-window window)))))
+
+;;; Refresh Magit Buffers
+
+(defvar inhibit-magit-refresh nil)
+
+(defun magit-refresh ()
+ "Refresh some buffers belonging to the current repository.
+
+Refresh the current buffer if its major mode derives from
+`magit-mode', and refresh the corresponding status buffer.
+
+Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
+ (interactive)
+ (unless inhibit-magit-refresh
+ (let ((start (current-time))
+ (magit--refresh-cache (list (cons 0 0))))
+ (when magit-refresh-verbose
+ (message "Refreshing magit..."))
+ (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
+ (when (derived-mode-p 'magit-mode)
+ (magit-refresh-buffer))
+ (--when-let (and magit-refresh-status-buffer
+ (not (derived-mode-p 'magit-status-mode))
+ (magit-mode-get-buffer 'magit-status-mode))
+ (with-current-buffer it
+ (magit-refresh-buffer)))
+ (magit-auto-revert-buffers)
+ (magit-run-hook-with-benchmark 'magit-post-refresh-hook)
+ (when magit-refresh-verbose
+ (message "Refreshing magit...done (%.3fs, cached %s/%s)"
+ (float-time (time-subtract (current-time) start))
+ (caar magit--refresh-cache)
+ (+ (caar magit--refresh-cache)
+ (cdar magit--refresh-cache)))))))
+
+(defun magit-refresh-all ()
+ "Refresh all buffers belonging to the current repository.
+
+Refresh all Magit buffers belonging to the current repository,
+and revert buffers that visit files located inside the current
+repository.
+
+Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
+ (interactive)
+ (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
+ (dolist (buffer (magit-mode-get-buffers))
+ (with-current-buffer buffer (magit-refresh-buffer)))
+ (magit-auto-revert-buffers)
+ (magit-run-hook-with-benchmark 'magit-post-refresh-hook))
+
+(defvar-local magit-refresh-start-time nil)
+
+(defun magit-refresh-buffer ()
+ "Refresh the current Magit buffer."
+ (setq magit-refresh-start-time (current-time))
+ (let ((refresh (intern (format "%s-refresh-buffer"
+ (substring (symbol-name major-mode) 0 -5))))
+ (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0)))))
+ (when (functionp refresh)
+ (when magit-refresh-verbose
+ (message "Refreshing buffer `%s'..." (buffer-name)))
+ (let* ((buffer (current-buffer))
+ (windows
+ (--mapcat (with-selected-window it
+ (with-current-buffer buffer
+ (-when-let (section (magit-current-section))
+ (list
+ (nconc (list it section)
+ (magit-refresh-get-relative-position))))))
+ (or (get-buffer-window-list buffer nil t)
+ (list (selected-window))))))
+ (deactivate-mark)
+ (setq magit-section-highlight-overlays nil
+ magit-section-highlighted-section nil
+ magit-section-highlighted-sections nil
+ magit-section-unhighlight-sections nil)
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (save-excursion
+ (apply refresh magit-refresh-args)))
+ (dolist (window windows)
+ (with-selected-window (car window)
+ (with-current-buffer buffer
+ (apply #'magit-section-goto-successor (cdr window)))))
+ (run-hooks 'magit-refresh-buffer-hook)
+ (magit-section-update-highlight)
+ (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)))))))
+
+(defun magit-refresh-get-relative-position ()
+ (-when-let (section (magit-current-section))
+ (let ((start (magit-section-start section)))
+ (list (count-lines start (point))
+ (- (point) (line-beginning-position))
+ (and (eq (magit-section-type section) 'hunk)
+ (region-active-p)
+ (progn (goto-char (line-beginning-position))
+ (when (looking-at "^[-+]") (forward-line))
+ (while (looking-at "^[ @]") (forward-line))
+ (let ((beg (point)))
+ (cond ((looking-at "^[-+]")
+ (forward-line)
+ (while (looking-at "^[-+]") (forward-line))
+ (while (looking-at "^ ") (forward-line))
+ (forward-line -1)
+ (regexp-quote (buffer-substring-no-properties
+ beg (line-end-position))))
+ (t t)))))))))
+
+;;; Save File-Visiting Buffers
+
+(defvar disable-magit-save-buffers nil)
+
+(defun magit-pre-command-hook ()
+ (setq disable-magit-save-buffers nil))
+(add-hook 'pre-command-hook #'magit-pre-command-hook)
+
+(defvar magit-after-save-refresh-buffers nil)
+
+(defun magit-after-save-refresh-buffers ()
+ (dolist (buffer magit-after-save-refresh-buffers)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (magit-refresh-buffer))))
+ (setq magit-after-save-refresh-buffers nil)
+ (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers))
+
+(defun magit-after-save-refresh-status ()
+ "Refresh the status buffer of the current repository.
+
+This function is intended to be added to `after-save-hook'.
+
+If the status buffer does not exist or the file being visited in
+the current buffer isn't inside the working tree of a repository,
+then do nothing.
+
+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 disable-magit-save-buffers)
+ (magit-inside-worktree-p))
+ (--when-let (ignore-errors (magit-mode-get-buffer 'magit-status-mode))
+ (add-to-list 'magit-after-save-refresh-buffers it)
+ (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.
+Do so if `magit-save-repository-buffers' is non-nil. You should
+not remove this from any hooks, instead set that variable to nil
+if you so desire."
+ (when (and magit-save-repository-buffers
+ (not disable-magit-save-buffers))
+ (setq disable-magit-save-buffers t)
+ (let ((msg (current-message)))
+ (magit-save-repository-buffers
+ (eq magit-save-repository-buffers 'dontask))
+ (when (and msg (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)
+
+(defun magit-save-repository-buffers (&optional arg)
+ "Save file-visiting buffers belonging to the current repository.
+After any buffer where `buffer-save-without-query' is non-nil
+is saved without asking, the user is asked about each modified
+buffer which visits a file in the current repository. Optional
+argument (the prefix) non-nil means save all with no questions."
+ (interactive "P")
+ (-when-let (topdir (magit-rev-parse-safe "--show-toplevel"))
+ (save-some-buffers
+ arg (-partial (lambda (topdir)
+ (and buffer-file-name
+ ;; Avoid needlessly connecting to unrelated remotes.
+ (string-prefix-p topdir (file-truename buffer-file-name))
+ (equal (magit-rev-parse-safe "--show-toplevel")
+ topdir)))
+ topdir))))
+
+;;; Restore Window Configuration
+
+(defvar magit-inhibit-save-previous-winconf nil)
+
+(defvar-local magit-previous-window-configuration nil)
+(put 'magit-previous-window-configuration 'permanent-local t)
+
+(defun magit-save-window-configuration ()
+ "Save the current window configuration.
+
+Later, when the buffer is buried, it may be restored by
+`magit-restore-window-configuration'."
+ (if magit-inhibit-save-previous-winconf
+ (when (eq magit-inhibit-save-previous-winconf 'unset)
+ (setq magit-previous-window-configuration nil))
+ (unless (get-buffer-window (current-buffer) (selected-frame))
+ (setq magit-previous-window-configuration
+ (current-window-configuration)))))
+
+(defun magit-restore-window-configuration (&optional kill-buffer)
+ "Bury or kill the current buffer and restore previous window configuration."
+ (let ((winconf magit-previous-window-configuration)
+ (buffer (current-buffer))
+ (frame (selected-frame)))
+ (quit-window kill-buffer (selected-window))
+ (when (and winconf (equal frame (window-configuration-frame winconf)))
+ (set-window-configuration winconf)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (setq magit-previous-window-configuration nil))))))
+
+;;; Buffer History
+
+(defun magit-go-backward ()
+ "Move backward in current buffer's history."
+ (interactive)
+ (if help-xref-stack
+ (help-xref-go-back (current-buffer))
+ (user-error "No previous entry in buffer's history")))
+
+(defun magit-go-forward ()
+ "Move forward in current buffer's history."
+ (interactive)
+ (if help-xref-forward-stack
+ (help-xref-go-forward (current-buffer))
+ (user-error "No next entry in buffer's history")))
+
+(defun magit-insert-xref-buttons (&optional _)
+ "Insert xref buttons."
+ (when (or help-xref-stack help-xref-forward-stack)
+ (when help-xref-stack
+ (magit-xref-insert-button help-back-label 'magit-xref-backward))
+ (when help-xref-forward-stack
+ (when help-xref-stack
+ (insert " "))
+ (magit-xref-insert-button help-forward-label 'magit-xref-forward))))
+
+(defun magit-xref-insert-button (label type)
+ (magit-insert-section (button label)
+ (insert-text-button label 'type type
+ 'help-args (list (current-buffer)))))
+
+(define-button-type 'magit-xref-backward
+ :supertype 'help-back
+ 'mouse-face 'magit-section-highlight
+ 'help-echo (purecopy "mouse-2, RET: go back to previous history entry"))
+
+(define-button-type 'magit-xref-forward
+ :supertype 'help-forward
+ 'mouse-face 'magit-section-highlight
+ 'help-echo (purecopy "mouse-2, RET: go back to next history entry"))
+
+(defun magit-xref-setup ()
+ "Insert backward/forward buttons if the major-mode supports it.
+Currently `magit-log-mode', `magit-reflog-mode',
+`magit-diff-mode', and `magit-revision-mode' support it"
+ (when (memq major-mode '(magit-log-mode
+ magit-reflog-mode
+ magit-diff-mode
+ magit-revision-mode))
+ (when help-xref-stack-item
+ (push (cons (point) help-xref-stack-item) help-xref-stack)
+ (setq help-xref-forward-stack nil))
+ (when (called-interactively-p 'interactive)
+ (--when-let (nthcdr 10 help-xref-stack)
+ (setcdr it nil)))
+ (setq help-xref-stack-item
+ `(magit-xref-restore ,default-directory ,@magit-refresh-args))))
+
+(defun magit-xref-restore (&rest args)
+ (magit-xref-setup)
+ (setq default-directory (car args))
+ (setq magit-refresh-args (cdr args))
+ (magit-refresh-buffer))
+
+;;; Utilities
+
+(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))))
+
+;;; magit-mode.el ends soon
+(provide 'magit-mode)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-mode.el ends here
--- /dev/null
+(define-package "magit" "20161115.1658" "A Git porcelain inside Emacs"
+ '((emacs "24.4")
+ (async "20160711.223")
+ (dash "20160820.501")
+ (with-editor "20160929.734")
+ (git-commit "20160929.801")
+ (magit-popup "20160821.1338"))
+ :url "https://github.com/magit/magit" :keywords
+ '("git" "tools" "vc"))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; magit-process.el --- process functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements the tools used to run Git for side-effects.
+
+;; Note that the functions used to run Git and then consume its
+;; output, are defined in `magit-git.el'. There's a bit of overlap
+;; though.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+
+(require 'with-editor)
+(require 'magit-utils)
+(require 'magit-section)
+(require 'magit-git)
+(require 'magit-mode)
+
+(eval-when-compile (require 'dired))
+(declare-function dired-uncache 'dired)
+
+;;; Options
+
+(defcustom magit-git-output-coding-system
+ (and (eq system-type 'windows-nt) 'utf-8)
+ "Coding system for receiving output from Git.
+
+If non-nil, the Git config value `i18n.logOutputEncoding' should
+be set via `magit-git-global-arguments' to value consistent with
+this."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-process
+ :type '(choice (coding-system :tag "Coding system to decode Git output")
+ (const :tag "Use system default" nil)))
+
+(defcustom magit-process-connection-type (not (eq system-type 'cygwin))
+ "Connection type used for the Git process.
+
+If nil, use pipes: this is usually more efficient, and works on Cygwin.
+If t, use ptys: this enables Magit to prompt for passphrases when needed."
+ :group 'magit-process
+ :type '(choice (const :tag "pipe" nil)
+ (const :tag "pty" t)))
+
+(defcustom magit-need-cygwin-noglob
+ (when (eq system-type 'windows-nt)
+ (with-temp-buffer
+ (let ((process-environment
+ (append magit-git-environment process-environment)))
+ (condition-case e
+ (process-file magit-git-executable
+ nil (current-buffer) nil
+ "-c" "alias.echo=!echo" "echo" "x{0}")
+ (file-error
+ (lwarn 'magit-process :warning
+ "Could not run Git: %S" e))))
+ (equal "x0\n" (buffer-string))))
+ "Whether to use a workaround for Cygwin's globbing behavior.
+
+If non-nil, add environment variables to `process-environment' to
+prevent the git.exe distributed by Cygwin and MSYS2 from
+attempting to perform glob expansion when called from a native
+Windows build of Emacs. See #2246."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-process
+ :type '(choice (const :tag "Yes" t)
+ (const :tag "No" nil)))
+
+(defcustom magit-process-popup-time -1
+ "Popup the process buffer if a command takes longer than this many seconds."
+ :group 'magit-process
+ :type '(choice (const :tag "Never" -1)
+ (const :tag "Immediately" 0)
+ (integer :tag "After this many seconds")))
+
+(defcustom magit-process-log-max 32
+ "Maximum number of sections to keep in a process log buffer.
+When adding a new section would go beyond the limit set here,
+then the older half of the sections are remove. Sections that
+belong to processes that are still running are never removed.
+When this is nil, no sections are ever removed."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-process
+ :type '(choice (const :tag "Never remove old sections" nil) integer))
+
+(defcustom magit-credential-cache-daemon-socket
+ (--some (-let [(prog . args) (split-string it)]
+ (if (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"))))
+ "If non-nil, start a credential cache daemon using this socket.
+
+When using Git's cache credential helper in the normal way, Emacs
+sends a SIGHUP to the credential daemon after the git subprocess
+has exited, causing the daemon to also quit. This can be avoided
+by starting the `git-credential-cache--daemon' process directly
+from Emacs.
+
+The function `magit-maybe-start-credential-cache-daemon' takes
+care of starting the daemon if necessary, using the value of this
+option as the socket. If this option is nil, then it does not
+start any daemon. Likewise if another daemon is already running,
+then it starts no new daemon. This function has to be a member
+of the hook variable `magit-credential-hook' for this to work.
+If an error occurs while starting the daemon, most likely because
+the necessary executable is missing, then the function removes
+itself from the hook, to avoid further futile attempts."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-process
+ :type '(choice (file :tag "Socket")
+ (const :tag "Don't start a cache daemon" nil)))
+
+(defcustom magit-process-yes-or-no-prompt-regexp
+ " [\[(]\\([Yy]\\(?:es\\)?\\)[/|]\\([Nn]o?\\)[\])] ?[?:] ?$"
+ "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 a host
+ "^\\(Enter \\)?[Pp]assword\\( for '\\(?99:.*\\)'\\)?: ?$"
+ "^.*'s password: ?$"
+ "^Yubikey for .*: ?$"
+ "^Enter PIN for .*: ?$")
+ "List of regexps matching password prompts of Git and its subprocesses.
+Also see `magit-process-find-password-functions'."
+ :package-version '(magit . "2.8.0")
+ :group 'magit-process
+ :type '(repeat (regexp)))
+
+(defcustom magit-process-find-password-functions nil
+ "List of functions to try in sequence to get a password.
+
+These functions may be called when git asks for a password, which
+is detected using `magit-process-password-prompt-regexps'. They
+are called if and only if matching the prompt resulted in the
+value of the 99th submatch to be non-nil. Therefore users can
+control for which prompts these functions should be called by
+putting the host name in the 99th submatch, or not.
+
+If the functions are called, then they are called in the order
+given, with the host name as only argument, until one of them
+returns non-nil. If they are not called or none of them returns
+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))
+
+(defcustom magit-process-username-prompt-regexps
+ '("^Username for '.*': ?$")
+ "List of regexps matching username prompts of Git and its subprocesses."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-process
+ :type '(repeat (regexp)))
+
+(defcustom magit-process-ensure-unix-line-ending t
+ "Whether Magit should ensure a unix coding system when talking to Git."
+ :package-version '(magit . "2.6.0")
+ :group 'magit-process
+ :type 'boolean)
+
+(defface magit-process-ok
+ '((t :inherit magit-section-heading :foreground "green"))
+ "Face for zero exit-status."
+ :group 'magit-faces)
+
+(defface magit-process-ng
+ '((t :inherit magit-section-heading :foreground "red"))
+ "Face for non-zero exit-status."
+ :group 'magit-faces)
+
+;;; Process Mode
+
+(defvar magit-process-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ map)
+ "Keymap for `magit-process-mode'.")
+
+(define-derived-mode magit-process-mode magit-mode "Magit Process"
+ "Mode for looking at Git process output."
+ :group 'magit-process
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-process-buffer (&optional nodisplay)
+ "Display the current repository's process buffer.
+
+If that buffer doesn't exist yet, then create it.
+Non-interactively return the buffer and unless
+optional NODISPLAY is non-nil also display it."
+ (interactive)
+ (let ((topdir (magit-toplevel)))
+ (unless topdir
+ (magit--with-safe-default-directory nil
+ (setq topdir default-directory)
+ (let (prev)
+ (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 ((default-directory topdir))
+ (magit-generate-new-buffer 'magit-process-mode)))))
+ (with-current-buffer buffer
+ (if magit-root-section
+ (when magit-process-log-max
+ (magit-process-truncate-log))
+ (magit-process-mode)
+ (let ((inhibit-read-only t)
+ (magit-insert-section--parent nil)
+ (magit-insert-section--oldroot nil))
+ (make-local-variable 'text-property-default-nonsticky)
+ (magit-insert-section (processbuf)
+ (insert "\n")))))
+ (unless nodisplay
+ (magit-display-buffer buffer))
+ buffer)))
+
+(defun magit-process-kill ()
+ "Kill the process at point."
+ (interactive)
+ (magit-section-when process
+ (let ((process (magit-section-value it)))
+ (if (eq (process-status process) 'run)
+ (when (magit-confirm 'kill-process)
+ (kill-process process))
+ (user-error "Process isn't running")))))
+
+;;; Synchronous Processes
+
+(defvar magit-process-raise-error nil)
+
+(defun magit-git (&rest args)
+ "Call Git synchronously in a separate process, for side-effects.
+
+Option `magit-git-executable' specifies the Git executable.
+The arguments ARGS specify arguments to Git, they are flattened
+before use.
+
+Process output goes into a new section in the buffer returned by
+`magit-process-buffer'. If Git exits with a non-zero status,
+then raise an error."
+ (let ((magit-process-raise-error t))
+ (magit-call-git args)))
+
+(defun magit-run-git (&rest args)
+ "Call Git synchronously in a separate process, and refresh.
+
+Option `magit-git-executable' specifies the Git executable and
+option `magit-git-global-arguments' specifies constant arguments.
+The arguments ARGS specify arguments to Git, they are flattened
+before use.
+
+After Git returns, the current buffer (if it is a Magit buffer)
+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'."
+ (magit-call-git args)
+ (magit-refresh))
+
+(defvar magit-pre-call-git-hook nil)
+
+(defun magit-call-git (&rest args)
+ "Call Git synchronously in a separate process.
+
+Option `magit-git-executable' specifies the Git executable and
+option `magit-git-global-arguments' specifies constant arguments.
+The arguments ARGS specify arguments to Git, they are flattened
+before use.
+
+Process output goes into a new section in the buffer returned by
+`magit-process-buffer'."
+ (run-hooks 'magit-pre-call-git-hook)
+ (let ((default-process-coding-system (magit--process-coding-system)))
+ (apply #'magit-call-process magit-git-executable
+ (magit-process-git-arguments args))))
+
+(defun magit-call-process (program &rest args)
+ "Call PROGRAM synchronously in a separate process.
+Process output goes into a new section in the buffer returned by
+`magit-process-buffer'."
+ (-let [(process-buf . section) (magit-process-setup program args)]
+ (magit-process-finish
+ (let ((inhibit-read-only t))
+ (apply #'magit-process-file program nil process-buf nil args))
+ process-buf (current-buffer) default-directory section)))
+
+(defun magit-process-file (&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."
+ (let ((process-environment (append (magit-cygwin-env-vars)
+ process-environment))
+ (default-process-coding-system (magit--process-coding-system)))
+ (apply #'process-file args)))
+
+(defun magit-cygwin-env-vars ()
+ (append magit-git-environment
+ (when magit-need-cygwin-noglob
+ (mapcar (lambda (var)
+ (concat var "=" (--if-let (getenv var)
+ (concat it " noglob")
+ "noglob")))
+ '("CYGWIN" "MSYS")))))
+
+(defvar magit-this-process nil)
+
+(defun magit-run-git-with-input (&rest args)
+ "Call Git in a separate process.
+ARGS is flattened and then used as arguments to Git.
+
+The current buffer's content is used as the process' standard
+input.
+
+Option `magit-git-executable' specifies the Git executable and
+option `magit-git-global-arguments' specifies constant arguments.
+The remaining arguments ARGS specify arguments to Git, they are
+flattened before use."
+ (declare (indent 1))
+ (if (file-remote-p default-directory)
+ ;; We lack `process-file-region', so fall back to asynch +
+ ;; waiting in remote case.
+ (progn
+ (magit-start-git (current-buffer) args)
+ (while (and magit-this-process
+ (eq (process-status magit-this-process) 'run))
+ (sleep-for 0.005)))
+ (run-hooks 'magit-pre-call-git-hook)
+ (-let* ((process-environment (append (magit-cygwin-env-vars)
+ process-environment))
+ (default-process-coding-system (magit--process-coding-system))
+ (flat-args (magit-process-git-arguments args))
+ ((process-buf . section)
+ (magit-process-setup magit-git-executable flat-args))
+ (inhibit-read-only t))
+ (magit-process-finish
+ (apply #'call-process-region (point-min) (point-max)
+ magit-git-executable nil process-buf nil flat-args)
+ process-buf nil default-directory section))))
+
+(defun magit-run-git-with-logfile (file &rest args)
+ "Call Git in a separate process and log its output to FILE.
+This function might have a short halflive."
+ (apply #'magit-process-file magit-git-executable nil `(:file ,file) nil
+ (magit-process-git-arguments args))
+ (magit-refresh))
+
+;;; Asynchronous Processes
+
+(defun magit-run-git-async (&rest args)
+ "Start Git, prepare for refresh, and return the process object.
+ARGS is flattened and then used as arguments to Git.
+
+Display the command line arguments in the echo area.
+
+After Git returns some buffers are refreshed: the buffer that was
+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 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)
+ "Export GIT_EDITOR and start Git.
+Also prepare for refresh and return the process object.
+ARGS is flattened and then used as arguments to Git.
+
+Display the command line arguments in the echo area.
+
+After Git returns some buffers are refreshed: the buffer that was
+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' and `with-editor' for more information."
+ (magit-with-editor (magit-run-git-async args)))
+
+(defun magit-run-git-sequencer (&rest args)
+ "Export GIT_EDITOR and start Git.
+Also prepare for refresh and return the process object.
+ARGS is flattened and then used as arguments to Git.
+
+Display the command line arguments in the echo area.
+
+After Git returns some buffers are refreshed: the buffer that was
+current when this function was called (if it is a Magit buffer
+and still alive), as well as the respective Magit status buffer.
+If the sequence stops at a commit, make the section representing
+that commit the current section by moving `point' there.
+
+See `magit-start-process' and `with-editor' for more information."
+ (apply #'magit-run-git-with-editor args)
+ (set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel)
+ magit-this-process)
+
+(defvar magit-pre-start-git-hook nil)
+
+(defun magit-start-git (input &rest args)
+ "Start Git, prepare for refresh, and return the process object.
+
+If INPUT is non-nil, it has to be a buffer or the name of an
+existing buffer. The buffer content becomes the processes
+standard input.
+
+Option `magit-git-executable' specifies the Git executable and
+option `magit-git-global-arguments' specifies constant arguments.
+The remaining arguments ARGS specify arguments to Git, they are
+flattened before use.
+
+After Git returns some buffers are refreshed: the buffer that was
+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."
+ (run-hooks 'magit-pre-start-git-hook)
+ (let ((default-process-coding-system (magit--process-coding-system)))
+ (apply #'magit-start-process magit-git-executable input
+ (magit-process-git-arguments args))))
+
+(defun magit-start-process (program &optional input &rest args)
+ "Start PROGRAM, prepare for refresh, and return the process object.
+
+If optional argument INPUT is non-nil, it has to be a buffer or
+the name of an existing buffer. The buffer content becomes the
+processes standard input.
+
+The process is started using `start-file-process' and then setup
+to use the sentinel `magit-process-sentinel' and the filter
+`magit-process-filter'. Information required by these functions
+is stored in the process object. When this function returns the
+process has not started to run yet so it is possible to override
+the sentinel and filter.
+
+After the process returns, `magit-process-sentinel' refreshes the
+buffer that was current when `magit-start-process' was called (if
+it is a Magit buffer and still alive), as well as the respective
+Magit status buffer."
+ (-let* (((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))
+ (process-environment (append (magit-cygwin-env-vars)
+ process-environment))
+ (default-process-coding-system (magit--process-coding-system)))
+ (apply #'start-file-process
+ (file-name-nondirectory program)
+ process-buf program args))))
+ (with-editor-set-process-filter process #'magit-process-filter)
+ (set-process-sentinel process #'magit-process-sentinel)
+ (set-process-buffer process process-buf)
+ (process-put process 'section section)
+ (process-put process 'command-buf (current-buffer))
+ (process-put process 'default-dir default-directory)
+ (when inhibit-magit-refresh
+ (process-put process 'inhibit-refresh t))
+ (setf (magit-section-process section) process)
+ (with-current-buffer process-buf
+ (set-marker (process-mark process) (point)))
+ (when input
+ (with-current-buffer input
+ (process-send-region process (point-min) (point-max))
+ (process-send-eof process)))
+ (setq magit-this-process process)
+ (setf (magit-section-value section) process)
+ (magit-process-display-buffer process)
+ process))
+
+;;; Process Internals
+
+(defun magit-process-setup (program args)
+ (magit-process-set-mode-line program args)
+ (let ((pwd default-directory)
+ (buf (magit-process-buffer t)))
+ (cons buf (with-current-buffer buf
+ (prog1 (magit-process-insert-section pwd program args nil nil)
+ (backward-char 1))))))
+
+(defun magit-process-insert-section (pwd program args &optional errcode errlog)
+ (let ((inhibit-read-only t)
+ (magit-insert-section--parent magit-root-section)
+ (magit-insert-section--oldroot nil))
+ (goto-char (1- (point-max)))
+ (magit-insert-section (process)
+ (insert (if errcode
+ (format "%3s " (propertize (number-to-string errcode)
+ 'face 'magit-process-ng))
+ "run "))
+ (unless (equal (expand-file-name pwd)
+ (expand-file-name default-directory))
+ (insert (file-relative-name pwd default-directory) ?\s))
+ (insert (propertize program 'face 'magit-section-heading))
+ (insert " ")
+ (when (and args (equal program magit-git-executable))
+ (setq args (-split-at (length magit-git-global-arguments) args))
+ (insert (propertize (char-to-string magit-ellipsis)
+ 'face 'magit-section-heading
+ 'help-echo (mapconcat #'identity (car args) " ")))
+ (insert " ")
+ (setq args (cadr args)))
+ (insert (propertize (mapconcat #'identity args " ")
+ 'face 'magit-section-heading))
+ (magit-insert-heading)
+ (when errlog
+ (insert-file-contents errlog)
+ (goto-char (1- (point-max))))
+ (insert "\n"))))
+
+(defun magit-process-truncate-log ()
+ (let* ((head nil)
+ (tail (magit-section-children magit-root-section))
+ (count (length tail)))
+ (when (> (1+ count) magit-process-log-max)
+ (while (and (cdr tail)
+ (> count (/ magit-process-log-max 2)))
+ (let* ((inhibit-read-only t)
+ (section (car tail))
+ (process (magit-section-process section)))
+ (cond ((not process))
+ ((memq (process-status process) '(exit signal))
+ (delete-region (magit-section-start section)
+ (1+ (magit-section-end section)))
+ (cl-decf count))
+ (t
+ (push section head))))
+ (pop tail))
+ (setf (magit-section-children magit-root-section)
+ (nconc (reverse head) tail)))))
+
+(defun magit-process-sentinel (process event)
+ "Default sentinel used by `magit-start-process'."
+ (when (memq (process-status process) '(exit signal))
+ (setq event (substring event 0 -1))
+ (when (string-match "^finished" event)
+ (message (concat (capitalize (process-name process)) " finished")))
+ (magit-process-finish process)
+ (when (eq process magit-this-process)
+ (setq magit-this-process nil))
+ (unless (process-get process 'inhibit-refresh)
+ (let ((command-buf (process-get process 'command-buf)))
+ (if (buffer-live-p command-buf)
+ (with-current-buffer command-buf
+ (magit-refresh))
+ (with-temp-buffer
+ (setq default-directory (process-get process 'default-dir))
+ (magit-refresh)))))))
+
+(defun magit-sequencer-process-sentinel (process event)
+ "Special sentinel used by `magit-run-git-sequencer'."
+ (when (memq (process-status process) '(exit signal))
+ (magit-process-sentinel process event)
+ (-when-let (process-buf (process-get process 'process-buf))
+ (when (buffer-live-p process-buf)
+ (-when-let (status-buf (with-current-buffer process-buf
+ (magit-mode-get-buffer 'magit-status-mode)))
+ (with-current-buffer status-buf
+ (--when-let
+ (magit-get-section
+ `((commit . ,(magit-rev-parse "HEAD"))
+ (,(pcase (car (cadr (-split-at
+ (1+ (length magit-git-global-arguments))
+ (process-command process))))
+ ((or "rebase" "am") 'rebase-sequence)
+ ((or "cherry-pick" "revert") 'sequence)))
+ (status)))
+ (goto-char (magit-section-start it))
+ (magit-section-update-highlight))))))))
+
+(defun magit-process-filter (proc string)
+ "Default filter used by `magit-start-process'."
+ (with-current-buffer (process-buffer proc)
+ (let ((inhibit-read-only t))
+ (magit-process-yes-or-no-prompt proc string)
+ (magit-process-username-prompt proc string)
+ (magit-process-password-prompt proc string)
+ (goto-char (process-mark proc))
+ (setq string (propertize string 'magit-section
+ (process-get proc 'section)))
+ ;; Find last ^M in string. If one was found, ignore
+ ;; everything before it and delete the current line.
+ (let ((ret-pos (length string)))
+ (while (and (>= (cl-decf ret-pos) 0)
+ (/= ?\r (aref string ret-pos))))
+ (if (< ret-pos 0)
+ (insert string)
+ (delete-region (line-beginning-position) (point))
+ (insert (substring string (1+ ret-pos)))))
+ (set-marker (process-mark proc) (point)))))
+
+(defmacro magit-process-kill-on-abort (proc &rest body)
+ (declare (indent 1) (debug (form body)))
+ (let ((map (cl-gensym)))
+ `(let ((,map (make-sparse-keymap)))
+ (set-keymap-parent ,map minibuffer-local-map)
+ (define-key ,map "\C-g"
+ (lambda ()
+ (interactive)
+ (ignore-errors (kill-process ,proc))
+ (abort-recursive-edit)))
+ (let ((minibuffer-local-map ,map))
+ ,@body))))
+
+(defun magit-process-yes-or-no-prompt (process string)
+ "Forward Yes-or-No prompts to the user."
+ (-when-let (beg (string-match magit-process-yes-or-no-prompt-regexp string))
+ (let ((max-mini-window-height 30))
+ (process-send-string
+ process
+ (downcase
+ (concat
+ (match-string
+ (if (save-match-data
+ (magit-process-kill-on-abort process
+ (yes-or-no-p (substring string 0 beg)))) 1 2)
+ string)
+ "\n"))))))
+
+(defun magit-process-password-auth-source (key)
+ "Use `auth-source-search' to get a password.
+If found, return the password. Otherwise, return nil."
+ (require 'auth-source)
+ (let ((secret (plist-get (car (auth-source-search :max 1 :host key
+ :require '(:host)))
+ :secret)))
+ (if (functionp secret)
+ (funcall secret)
+ secret)))
+
+(defun magit-process-password-prompt (process string)
+ "Find a password based on prompt STRING and send it to git.
+First try the functions in `magit-process-find-password-functions'.
+If none of them returns a password, then read it from the user
+instead."
+ (--when-let (magit-process-match-prompt
+ magit-process-password-prompt-regexps string)
+ (process-send-string
+ process (magit-process-kill-on-abort process
+ (concat (or (--when-let (match-string 99 string)
+ (run-hook-with-args-until-success
+ 'magit-process-find-password-functions it))
+ (read-passwd it))
+ "\n")))))
+
+(defun magit-process-username-prompt (process string)
+ "Forward username prompts to the user."
+ (--when-let (magit-process-match-prompt
+ magit-process-username-prompt-regexps string)
+ (process-send-string
+ process (magit-process-kill-on-abort process
+ (concat (read-string it nil nil (user-login-name)) "\n")))))
+
+(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? (string-match it string) prompts)
+ (let ((prompt (match-string 0 string)))
+ (cond ((string-suffix-p ": " prompt) prompt)
+ ((string-suffix-p ":" prompt) (concat prompt " "))
+ (t (concat prompt ": "))))))
+
+(defun magit--process-coding-system ()
+ (let ((fro (or magit-git-output-coding-system
+ (car default-process-coding-system)))
+ (to (cdr default-process-coding-system)))
+ (if magit-process-ensure-unix-line-ending
+ (cons (coding-system-change-eol-conversion fro 'unix)
+ (coding-system-change-eol-conversion to 'unix))
+ (cons fro to))))
+
+(defvar magit-credential-hook nil
+ "Hook run before Git needs credentials.")
+
+(defvar magit-credential-cache-daemon-process nil)
+
+(defun magit-maybe-start-credential-cache-daemon ()
+ "Maybe start a `git-credential-cache--daemon' process.
+
+If such a process is already running or if the value of option
+`magit-credential-cache-daemon-socket' is nil, then do nothing.
+Otherwise start the process passing the value of that options
+as argument."
+ (unless (or (not magit-credential-cache-daemon-socket)
+ (process-live-p magit-credential-cache-daemon-process)
+ (memq magit-credential-cache-daemon-process
+ (list-system-processes)))
+ (setq magit-credential-cache-daemon-process
+ (or (--first (-let (((&alist 'comm comm 'user user)
+ (process-attributes it)))
+ (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*"
+ magit-git-executable
+ "credential-cache--daemon"
+ magit-credential-cache-daemon-socket)
+ ;; Some Git implementations (e.g. Windows) won't have
+ ;; this program; if we fail the first time, stop trying.
+ ((debug error)
+ (remove-hook 'magit-credential-hook
+ #'magit-maybe-start-credential-cache-daemon)))))))
+
+(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)
+
+(defun magit-process-set-mode-line (program args)
+ (when (equal program magit-git-executable)
+ (setq args (nthcdr (length magit-git-global-arguments) args)))
+ (let ((str (concat " " program (and args (concat " " (car args))))))
+ (dolist (buf (magit-mode-get-buffers))
+ (with-current-buffer buf (setq mode-line-process str)))))
+
+(defun magit-process-unset-mode-line ()
+ (dolist (buf (magit-mode-get-buffers))
+ (with-current-buffer buf (setq mode-line-process nil))))
+
+(defvar magit-process-error-message-re
+ (concat "^\\(?:error\\|fatal\\|git\\): \\(.*\\)" paragraph-separate))
+
+(define-error 'magit-git-error "Git error")
+
+(defvar-local magit-this-error nil)
+
+(defun magit-process-finish (arg &optional process-buf command-buf
+ default-dir section)
+ (unless (integerp arg)
+ (setq process-buf (process-buffer arg)
+ command-buf (process-get arg 'command-buf)
+ default-dir (process-get arg 'default-dir)
+ section (process-get arg 'section)
+ arg (process-exit-status arg)))
+ (when (featurep 'dired)
+ (dired-uncache default-dir))
+ (when (buffer-live-p process-buf)
+ (with-current-buffer process-buf
+ (magit-process-unset-mode-line)
+ (let ((inhibit-read-only t)
+ (marker (magit-section-start section)))
+ (goto-char marker)
+ (save-excursion
+ (delete-char 3)
+ (set-marker-insertion-type marker nil)
+ (insert (propertize (format "%3s" arg)
+ 'magit-section section
+ 'face (if (= arg 0)
+ 'magit-process-ok
+ 'magit-process-ng)))
+ (set-marker-insertion-type marker t))
+ (if (= (magit-section-end section)
+ (+ (line-end-position) 2))
+ (save-excursion
+ (goto-char (1+ (line-end-position)))
+ (delete-char -1)
+ (setf (magit-section-content section) nil))
+ (let ((buf (magit-process-buffer t)))
+ (when (and (= arg 0)
+ (not (--any-p (eq (window-buffer it) buf)
+ (window-list))))
+ (magit-section-hide section)))))))
+ (unless (= arg 0)
+ (let ((msg (or (and (buffer-live-p process-buf)
+ (with-current-buffer process-buf
+ (save-excursion
+ (goto-char (magit-section-end section))
+ (--when-let (magit-section-content section)
+ (when (re-search-backward
+ magit-process-error-message-re it t)
+ (match-string-no-properties 1))))))
+ "Git failed")))
+ (if magit-process-raise-error
+ (signal 'magit-git-error (list (format "%s (in %s)" msg default-dir)))
+ (when (buffer-live-p process-buf)
+ (with-current-buffer process-buf
+ (-when-let (status-buf (magit-mode-get-buffer 'magit-status-mode))
+ (with-current-buffer status-buf
+ (setq magit-this-error msg)))))
+ (message "%s ... [%s buffer %s for details]" msg
+ (-if-let (key (and (buffer-live-p command-buf)
+ (with-current-buffer command-buf
+ (car (where-is-internal
+ 'magit-process-buffer)))))
+ (format "Hit %s to see" (key-description key))
+ "See")
+ (buffer-name process-buf)))))
+ arg)
+
+(defun magit-process-display-buffer (process)
+ (when (process-live-p process)
+ (let ((buf (process-buffer process)))
+ (cond ((not (buffer-live-p buf)))
+ ((= magit-process-popup-time 0)
+ (if (minibufferp)
+ (switch-to-buffer-other-window buf)
+ (pop-to-buffer buf)))
+ ((> magit-process-popup-time 0)
+ (run-with-timer magit-process-popup-time nil
+ (lambda (p)
+ (when (eq (process-status p) 'run)
+ (let ((buf (process-buffer p)))
+ (when (buffer-live-p buf)
+ (if (minibufferp)
+ (switch-to-buffer-other-window buf)
+ (pop-to-buffer buf))))))
+ process))))))
+
+;;; magit-process.el ends soon
+
+(define-obsolete-variable-alias 'magit-log-output-coding-system
+ 'magit-git-output-coding-system "Magit 2.9.0")
+
+(provide 'magit-process)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-process.el ends here
--- /dev/null
+;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for interacting with remote
+;; repositories. Commands for cloning, fetching, pulling, and
+;; pushing are defined here.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Clone
+
+(defcustom magit-clone-set-remote-head nil
+ "Whether cloning creates the symbolic-ref `<remote>/HEAD'."
+ :package-version '(magit . "2.4.2")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-clone-set-remote.pushDefault 'ask
+ "Whether to set the value of `remote.pushDefault' after cloning.
+
+If t, then set without asking. If nil, then don't set. If
+`ask', then ask."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "set" t)
+ (const :tag "ask" ask)
+ (const :tag "don't set" nil)))
+
+;;;###autoload
+(defun magit-clone (repository directory)
+ "Clone the REPOSITORY to DIRECTORY.
+Then show the status buffer for the new repository."
+ (interactive
+ (let ((url (magit-read-string-ns "Clone repository")))
+ (list url (read-directory-name
+ "Clone to: " nil nil nil
+ (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
+ (match-string 1 url))))))
+ (setq directory (file-name-as-directory (expand-file-name directory)))
+ (magit-run-git-async "clone" repository
+ (magit-convert-filename-for-git directory))
+ ;; Don't refresh the buffer we're calling from.
+ (process-put magit-this-process 'inhibit-refresh t)
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (let ((magit-process-raise-error t))
+ (magit-process-sentinel process event)))
+ (when (and (eq (process-status process) 'exit)
+ (= (process-exit-status process) 0))
+ (let ((default-directory directory))
+ (when (or (eq magit-clone-set-remote.pushDefault t)
+ (and magit-clone-set-remote.pushDefault
+ (y-or-n-p "Set `remote.pushDefault' to \"origin\"? ")))
+ (setf (magit-get "remote.pushDefault") "origin"))
+ (unless magit-clone-set-remote-head
+ (magit-remote-unset-head "origin")))
+ (with-current-buffer (process-get process 'command-buf)
+ (magit-status-internal directory))))))
+
+;;; Setup
+
+(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset
+ "Whether to set the value of `remote.pushDefault' after adding a remote.
+
+If `ask', then always ask. If `ask-if-unset', then ask, but only
+if the variable isn't set already. If nil, then don't ever set.
+If the value is a string, then set without asking, provided the
+name of the name of the added remote is equal to that string and
+the variable isn't already set."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "ask if unset" ask-if-unset)
+ (const :tag "always ask" ask)
+ (string :tag "set if named")
+ (const :tag "don't set")))
+
+;;;###autoload (autoload 'magit-remote-popup "magit-remote" nil t)
+(magit-define-popup magit-remote-popup
+ "Popup console for remote commands."
+ 'magit-commands nil nil
+ :man-page "git-remote"
+ :actions '((?a "Add" magit-remote-add)
+ (?r "Rename" magit-remote-rename)
+ (?k "Remove" magit-remote-remove)
+ (?u "Set url" magit-remote-set-url)))
+
+(defun magit-read-url (prompt &optional initial-input)
+ (let ((url (magit-read-string-ns prompt initial-input)))
+ (if (string-prefix-p "~" url)
+ (expand-file-name url)
+ url)))
+
+;;;###autoload
+(defun magit-remote-add (remote url)
+ "Add a remote named REMOTE and fetch it."
+ (interactive (list (magit-read-string-ns "Remote name")
+ (magit-read-url "Remote url")))
+ (if (pcase (list magit-remote-add-set-remote.pushDefault
+ (magit-get "remote.defaultPush"))
+ (`(,(pred stringp) ,_) t)
+ ((or `(ask ,_) `(ask-if-unset nil))
+ (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote))))
+ (progn (magit-call-git "remote" "add" "-f" remote url)
+ (setf (magit-get "remote.pushDefault") remote)
+ (magit-refresh))
+ (magit-run-git-async "remote" "add" "-f" remote url)))
+
+;;;###autoload
+(defun magit-remote-rename (old new)
+ "Rename the remote named OLD to NEW."
+ (interactive
+ (let ((remote (magit-read-remote "Rename remote")))
+ (list remote (magit-read-string-ns (format "Rename %s to" remote)))))
+ (unless (string= old new)
+ (magit-run-git "remote" "rename" old new)))
+
+;;;###autoload
+(defun magit-remote-set-url (remote url)
+ "Change the url of the remote named REMOTE to URL."
+ (interactive
+ (let ((remote (magit-read-remote "Set url of remote")))
+ (list remote (magit-read-url
+ "Url" (magit-get "remote" remote "url")))))
+ (magit-run-git "remote" "set-url" remote url))
+
+;;;###autoload
+(defun magit-remote-remove (remote)
+ "Delete the remote named REMOTE."
+ (interactive (list (magit-read-remote "Delete remote")))
+ (magit-run-git "remote" "rm" remote))
+
+;;;###autoload
+(defun magit-remote-set-head (remote &optional branch)
+ "Set the local representation of REMOTE's default branch.
+Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
+accordingly. With a prefix argument query for the branch to be
+used, which allows you to select an incorrect value if you fancy
+doing that."
+ (interactive
+ (let ((remote (magit-read-remote "Set HEAD for remote")))
+ (list remote
+ (and current-prefix-arg
+ (magit-read-remote-branch (format "Set %s/HEAD to" remote)
+ remote nil nil t)))))
+ (magit-run-git "remote" "set-head" remote (or branch "--auto")))
+
+;;;###autoload
+(defun magit-remote-unset-head (remote)
+ "Unset the local representation of REMOTE's default branch.
+Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\"."
+ (interactive (list (magit-read-remote "Unset HEAD for remote")))
+ (magit-run-git "remote" "set-head" remote "--delete"))
+
+;;; Fetch
+
+;;;###autoload (autoload 'magit-fetch-popup "magit-remote" nil t)
+(magit-define-popup magit-fetch-popup
+ "Popup console for fetch commands."
+ 'magit-commands
+ :man-page "git-fetch"
+ :switches '((?p "Prune deleted branches" "--prune"))
+ :actions '("Configure"
+ (?C "variables..." magit-branch-config-popup)
+ "Fetch from"
+ (?p magit-get-push-remote magit-fetch-from-pushremote)
+ (?u magit-get-remote magit-fetch-from-upstream)
+ (?e "elsewhere" magit-fetch)
+ (?a "all remotes" magit-fetch-all)
+ "Fetch"
+ (?o "another branch" magit-fetch-branch)
+ (?r "explicit refspec" magit-fetch-refspec)
+ (?m "submodules" magit-submodule-fetch))
+ :default-action 'magit-fetch
+ :max-action-columns 1)
+
+(defun magit-git-fetch (remote args)
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "fetch" remote args))
+
+;;;###autoload
+(defun magit-fetch-from-pushremote (args)
+ "Fetch from the push-remote of the current branch."
+ (interactive (list (magit-fetch-arguments)))
+ (--if-let (magit-get-push-remote)
+ (magit-git-fetch it args)
+ (--if-let (magit-get-current-branch)
+ (user-error "No push-remote is configured for %s" it)
+ (user-error "No branch is checked out"))))
+
+;;;###autoload
+(defun magit-fetch-from-upstream (args)
+ "Fetch from the upstream repository of the current branch."
+ (interactive (list (magit-fetch-arguments)))
+ (--if-let (magit-get-remote)
+ (magit-git-fetch it args)
+ (--if-let (magit-get-current-branch)
+ (user-error "No upstream is configured for %s" it)
+ (user-error "No branch is checked out"))))
+
+;;;###autoload
+(defun magit-fetch (remote args)
+ "Fetch from another repository."
+ (interactive (list (magit-read-remote "Fetch remote")
+ (magit-fetch-arguments)))
+ (magit-git-fetch remote args))
+
+;;;###autoload
+(defun magit-fetch-branch (remote branch args)
+ "Fetch a BRANCH from a REMOTE."
+ (interactive
+ (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
+ (list remote
+ (magit-read-remote-branch "Fetch branch" remote)
+ (magit-fetch-arguments))))
+ (magit-git-fetch remote (cons branch args)))
+
+;;;###autoload
+(defun magit-fetch-refspec (remote refspec args)
+ "Fetch a REFSPEC from a REMOTE."
+ (interactive
+ (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
+ (list remote
+ (magit-read-refspec "Fetch using refspec" remote)
+ (magit-fetch-arguments))))
+ (magit-git-fetch remote (cons refspec args)))
+
+;;;###autoload
+(defun magit-fetch-all (args)
+ "Fetch from all remotes."
+ (interactive (list (magit-fetch-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "remote" "update" args))
+
+;;;###autoload
+(defun magit-fetch-all-prune ()
+ "Fetch from all remotes, and prune.
+Prune remote tracking branches for branches that have been
+removed on the respective remote."
+ (interactive)
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "remote" "update" "--prune"))
+
+;;;###autoload
+(defun magit-fetch-all-no-prune ()
+ "Fetch from all remotes."
+ (interactive)
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "remote" "update"))
+
+;;; Pull
+
+;;;###autoload (autoload 'magit-pull-popup "magit-remote" nil t)
+(magit-define-popup magit-pull-popup
+ "Popup console for pull commands."
+ 'magit-commands
+ :man-page "git-pull"
+ :variables '("Configure"
+ (?r "branch.%s.rebase"
+ magit-cycle-branch*rebase
+ magit-pull-format-branch*rebase)
+ (?C "variables..." magit-branch-config-popup))
+ :actions '((lambda ()
+ (--if-let (magit-get-current-branch)
+ (concat
+ (propertize "Pull into " 'face 'magit-popup-heading)
+ (propertize it 'face 'magit-branch-local)
+ (propertize " from" 'face 'magit-popup-heading))
+ (propertize "Pull from" 'face 'magit-popup-heading)))
+ (?p magit-get-push-branch magit-pull-from-pushremote)
+ (?u magit-get-upstream-branch magit-pull-from-upstream)
+ (?e "elsewhere" magit-pull))
+ :default-action 'magit-pull
+ :max-action-columns 1)
+
+;;;###autoload (autoload 'magit-pull-and-fetch-popup "magit-remote" nil t)
+(magit-define-popup magit-pull-and-fetch-popup
+ "Popup console for pull and fetch commands.
+
+This popup is intended as a replacement for the separate popups
+`magit-pull-popup' and `magit-fetch-popup'. To use it, add this
+to your init file:
+
+ (with-eval-after-load \\='magit-remote
+ (define-key magit-mode-map \"f\" \\='magit-pull-and-fetch-popup)
+ (define-key magit-mode-map \"F\" nil))
+
+The combined popup does not offer all commands and arguments
+available from the individual popups. Instead of the argument
+`--prune' and the command `magit-fetch-all' it uses two commands
+`magit-fetch-prune' and `magit-fetch-no-prune'. And the commands
+`magit-fetch-from-pushremote' and `magit-fetch-from-upstream' are
+missing. To add them use something like:
+
+ (with-eval-after-load \\='magit-remote
+ (magit-define-popup-action \\='magit-pull-and-fetch-popup ?U
+ \\='magit-get-upstream-branch
+ \\='magit-fetch-from-upstream-remote ?F)
+ (magit-define-popup-action \\='magit-pull-and-fetch-popup ?P
+ \\='magit-get-push-branch
+ \\='magit-fetch-from-push-remote ?F))"
+ 'magit-commands
+ :man-page "git-pull"
+ :variables '("Configure"
+ (?r "branch.%s.rebase"
+ magit-cycle-branch*rebase
+ magit-pull-format-branch*rebase)
+ (?C "variables..." magit-branch-config-popup))
+ :actions '((lambda ()
+ (--if-let (magit-get-current-branch)
+ (concat
+ (propertize "Pull into " 'face 'magit-popup-heading)
+ (propertize it 'face 'magit-branch-local)
+ (propertize " from" 'face 'magit-popup-heading))
+ (propertize "Pull from" 'face 'magit-popup-heading)))
+ (?p magit-get-push-branch magit-pull-from-pushremote)
+ (?u magit-get-upstream-branch magit-pull-from-upstream)
+ (?e "elsewhere" magit-pull)
+ "Fetch from"
+ (?f "remotes" magit-fetch-all-no-prune)
+ (?F "remotes and prune" magit-fetch-all-prune)
+ "Fetch"
+ (?o "another branch" magit-fetch-branch)
+ (?s "explicit refspec" magit-fetch-refspec)
+ (?m "submodules" magit-submodule-fetch))
+ :default-action 'magit-fetch
+ :max-action-columns 1)
+
+(defun magit-pull-format-branch*rebase ()
+ (magit-popup-format-variable (format "branch.%s.rebase"
+ (or (magit-get-current-branch) "<name>"))
+ '("true" "false")
+ "false" "pull.rebase"))
+
+(defun magit-git-pull (source args)
+ (run-hooks 'magit-credential-hook)
+ (-let [(remote . branch)
+ (magit-split-branch-name source)]
+ (magit-run-git-with-editor "pull" args remote branch)))
+
+;;;###autoload
+(defun magit-pull-from-pushremote (args)
+ "Pull from the push-remote of the current branch."
+ (interactive (list (magit-pull-arguments)))
+ (--if-let (magit-get-push-branch)
+ (magit-git-pull it args)
+ (--if-let (magit-get-current-branch)
+ (user-error "No push-remote is configured for %s" it)
+ (user-error "No branch is checked out"))))
+
+;;;###autoload
+(defun magit-pull-from-upstream (args)
+ "Pull from the upstream of the current branch."
+ (interactive (list (magit-pull-arguments)))
+ (--if-let (magit-get-upstream-branch)
+ (progn (run-hooks 'magit-credential-hook)
+ (magit-run-git-with-editor
+ "pull" args (car (magit-split-branch-name it))))
+ (--if-let (magit-get-current-branch)
+ (user-error "No upstream is configured for %s" it)
+ (user-error "No branch is checked out"))))
+
+;;;###autoload
+(defun magit-pull (source args)
+ "Pull from a branch read in the minibuffer."
+ (interactive (list (magit-read-remote-branch "Pull" nil nil nil t)
+ (magit-pull-arguments)))
+ (magit-git-pull source args))
+
+;;; Push
+
+(defcustom magit-push-current-set-remote-if-missing t
+ "Whether to configure missing remotes before pushing.
+
+When nil, then the command `magit-push-current-to-pushremote' and
+`magit-push-current-to-upstream' do not appear in the push popup
+if the push-remote resp. upstream is not configured. If the user
+invokes one of these commands anyway, then it raises an error.
+
+When non-nil, then these commands always appear in the push
+popup. But if the required configuration is missing, then they
+do appear in a way that indicates that this is the case. If the
+user invokes one of them, then it asks for the necessary
+configuration, stores the configuration, and then uses it to push
+a first time.
+
+This option also affects whether the argument `--set-upstream' is
+available in the popup. If the value is t, then that argument is
+redundant. But note that changing the value of this option does
+not take affect immediately, the argument will only be added or
+removed after restarting Emacs."
+ :package-version '(magit . "2.6.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "don't set" nil)
+ (const :tag "set branch.<name>.pushRemote" t)
+ (const :tag "set remote.pushDefault" default)))
+
+;;;###autoload (autoload 'magit-push-popup "magit-remote" nil t)
+(magit-define-popup magit-push-popup
+ "Popup console for push commands."
+ 'magit-commands
+ :man-page "git-push"
+ :switches `((?f "Force with lease" "--force-with-lease")
+ (?F "Force" "--force")
+ (?h "Disable hooks" "--no-verify")
+ (?d "Dry run" "--dry-run")
+ ,@(and (not magit-push-current-set-remote-if-missing)
+ '((?u "Set upstream" "--set-upstream"))))
+ :actions '("Configure"
+ (?C "variables..." magit-branch-config-popup)
+ (lambda ()
+ (--when-let (magit-get-current-branch)
+ (concat (propertize "Push " 'face 'magit-popup-heading)
+ (propertize it 'face 'magit-branch-local)
+ (propertize " to" 'face 'magit-popup-heading))))
+ (?p magit--push-current-to-pushremote-desc
+ magit-push-current-to-pushremote)
+ (?u magit--push-current-to-upstream-desc
+ magit-push-current-to-upstream)
+ (?e "elsewhere\n" magit-push-current)
+ "Push"
+ (?o "another branch" magit-push)
+ (?T "a tag" magit-push-tag)
+ (?r "explicit refspecs" magit-push-refspecs)
+ (?t "all tags" magit-push-tags)
+ (?m "matching branches" magit-push-matching))
+ :max-action-columns 2)
+
+(defun magit-git-push (branch target args)
+ (run-hooks 'magit-credential-hook)
+ (-let [(remote . target)
+ (magit-split-branch-name target)]
+ (magit-run-git-async "push" "-v" args remote
+ (format "%s:refs/heads/%s" branch target))))
+
+;;;###autoload
+(defun magit-push-current-to-pushremote (args &optional push-remote)
+ "Push the current branch to `branch.<name>.pushRemote'.
+If that variable is unset, then push to `remote.pushDefault'.
+
+When `magit-push-current-set-remote-if-missing' is non-nil and
+the push-remote is not configured, then read the push-remote from
+the user, set it, and then push to it. With a prefix argument
+the push-remote can be changed before pushed to it."
+ (interactive
+ (list (magit-push-arguments)
+ (and (magit--push-current-set-pushremote-p current-prefix-arg)
+ (magit-read-remote
+ (if (eq magit-push-current-set-remote-if-missing 'default)
+ "Set `remote.pushDefault' and push there"
+ (format "Set `branch.%s.pushRemote' and push there"
+ (magit-get-current-branch)))))))
+ (--if-let (magit-get-current-branch)
+ (progn (when push-remote
+ (setf (magit-get
+ (if (eq magit-push-current-set-remote-if-missing 'default)
+ "remote.pushDefault"
+ (format "branch.%s.pushRemote"
+ (magit-get-current-branch))))
+ push-remote))
+ (-if-let (remote (magit-get-push-remote it))
+ (if (member remote (magit-list-remotes))
+ (magit-git-push it (concat remote "/" it) args)
+ (user-error "Remote `%s' doesn't exist" remote))
+ (user-error "No push-remote is configured for %s" it)))
+ (user-error "No branch is checked out")))
+
+(defun magit--push-current-set-pushremote-p (&optional change)
+ (and (or change
+ (and magit-push-current-set-remote-if-missing
+ (not (magit-get-push-remote))))
+ (magit-get-current-branch)))
+
+(defun magit--push-current-to-pushremote-desc ()
+ (--if-let (magit-get-push-branch)
+ (concat (magit-branch-set-face it) "\n")
+ (and (magit--push-current-set-pushremote-p)
+ (concat
+ (propertize (if (eq magit-push-current-set-remote-if-missing 'default)
+ "pushDefault"
+ "pushRemote")
+ 'face 'bold)
+ ", after setting that\n"))))
+
+;;;###autoload
+(defun magit-push-current-to-upstream (args &optional upstream)
+ "Push the current branch to its upstream branch.
+
+When `magit-push-current-set-remote-if-missing' is non-nil and
+the upstream is not configured, then read the upstream from the
+user, set it, and then push to it. With a prefix argument the
+upstream can be changed before pushed to it."
+ (interactive
+ (list (magit-push-arguments)
+ (and (magit--push-current-set-upstream-p current-prefix-arg)
+ (magit-read-upstream-branch))))
+ (--if-let (magit-get-current-branch)
+ (progn
+ (when upstream
+ (magit-set-branch*merge/remote it upstream))
+ (-if-let (target (magit-get-upstream-branch it))
+ (magit-git-push it target args)
+ (user-error "No upstream is configured for %s" it)))
+ (user-error "No branch is checked out")))
+
+(defun magit--push-current-set-upstream-p (&optional change)
+ (and (or change
+ (and magit-push-current-set-remote-if-missing
+ (not (magit-get-upstream-branch))))
+ (magit-get-current-branch)))
+
+(defun magit--push-current-to-upstream-desc ()
+ (--if-let (magit-get-upstream-branch)
+ (concat (magit-branch-set-face it) "\n")
+ (and (magit--push-current-set-upstream-p)
+ (concat (propertize "@{upstream}" 'face 'bold)
+ ", after setting that\n"))))
+
+;;;###autoload
+(defun magit-push-current (target args)
+ "Push the current branch to a branch read in the minibuffer."
+ (interactive
+ (--if-let (magit-get-current-branch)
+ (list (magit-read-remote-branch (format "Push %s to" it)
+ nil nil it 'confirm)
+ (magit-push-arguments))
+ (user-error "No branch is checked out")))
+ (magit-git-push (magit-get-current-branch) target args))
+
+;;;###autoload
+(defun magit-push (source target args)
+ "Push an arbitrary branch or commit somewhere.
+Both the source and the target are read in the minibuffer."
+ (interactive
+ (let ((source (magit-read-local-branch-or-commit "Push")))
+ (list source
+ (magit-read-remote-branch
+ (format "Push %s to" source) nil
+ (if (magit-local-branch-p source)
+ (or (magit-get-push-branch source)
+ (magit-get-upstream-branch source))
+ (and (magit-rev-ancestor-p source "HEAD")
+ (or (magit-get-push-branch)
+ (magit-get-upstream-branch))))
+ source 'confirm)
+ (magit-push-arguments))))
+ (magit-git-push source target args))
+
+;;;###autoload
+(defun magit-push-refspecs (remote refspecs args)
+ "Push one or multiple REFSPECS to a REMOTE.
+Both the REMOTE and the REFSPECS are read in the minibuffer. To
+use multiple REFSPECS, separate them with commas. Completion is
+only available for the part before the colon, or when no colon
+is used."
+ (interactive
+ (list (magit-read-remote "Push to remote")
+ (completing-read-multiple
+ "Push refspec,s: "
+ (cons "HEAD" (magit-list-local-branch-names)))
+ (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args remote refspecs))
+
+;;;###autoload
+(defun magit-push-matching (remote &optional args)
+ "Push all matching branches to another repository.
+If multiple remotes exist, then read one from the user.
+If just one exists, use that without requiring confirmation."
+ (interactive (list (magit-read-remote "Push matching branches to" nil t)
+ (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args remote ":"))
+
+;;;###autoload
+(defun magit-push-tags (remote &optional args)
+ "Push all tags to another repository.
+If only one remote exists, then push to that. Otherwise prompt
+for a remote, offering the remote configured for the current
+branch as default."
+ (interactive (list (magit-read-remote "Push tags to remote" nil t)
+ (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" remote "--tags" args))
+
+;;;###autoload
+(defun magit-push-tag (tag remote &optional args)
+ "Push a tag to another repository."
+ (interactive
+ (let ((tag (magit-read-tag "Push tag")))
+ (list tag (magit-read-remote (format "Push %s to remote" tag) nil t)
+ (magit-push-arguments))))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" remote tag args))
+
+;;;###autoload
+(defun magit-push-implicitly (args)
+ "Push somewhere without using an explicit refspec.
+
+This command simply runs \"git push -v [ARGS]\". ARGS are the
+arguments specified in the popup buffer. No explicit refspec
+arguments are used. Instead the behavior depends on at least
+these Git variables: `push.default', `remote.pushDefault',
+`branch.<branch>.pushRemote', `branch.<branch>.remote',
+`branch.<branch>.merge', and `remote.<remote>.push'.
+
+To add this command to the push popup add this to your init file:
+
+ (with-eval-after-load \\='magit-remote
+ (magit-define-popup-action \\='magit-push-popup ?P
+ 'magit-push-implicitly--desc
+ 'magit-push-implicitly ?p t))
+
+The function `magit-push-implicitly--desc' attempts to predict
+what this command will do, the value it returns is displayed in
+the popup buffer."
+ (interactive (list (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args))
+
+(defun magit-push-implicitly--desc ()
+ (let ((default (magit-get "push.default")))
+ (unless (equal default "nothing")
+ (or (-when-let* ((remote (or (magit-get-remote)
+ (magit-remote-p "origin")))
+ (refspec (magit-get "remote" remote "push")))
+ (format "%s using %s"
+ (propertize remote 'face 'magit-branch-remote)
+ (propertize refspec 'face 'bold)))
+ (--when-let (and (not (magit-get-push-branch))
+ (magit-get-upstream-branch))
+ (format "%s aka %s\n"
+ (magit-branch-set-face it)
+ (propertize "@{upstream}" 'face 'bold)))
+ (--when-let (magit-get-push-branch)
+ (format "%s aka %s\n"
+ (magit-branch-set-face it)
+ (propertize "pushRemote" 'face 'bold)))
+ (--when-let (magit-get-@{push}-branch)
+ (format "%s aka %s\n"
+ (magit-branch-set-face it)
+ (propertize "@{push}" 'face 'bold)))
+ (format "using %s (%s is %s)\n"
+ (propertize "git push" 'face 'bold)
+ (propertize "push.default" 'face 'bold)
+ (propertize default 'face 'bold))))))
+
+;;;###autoload
+(defun magit-push-to-remote (remote args)
+ "Push to REMOTE without using an explicit refspec.
+The REMOTE is read in the minibuffer.
+
+This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
+are the arguments specified in the popup buffer. No refspec
+arguments are used. Instead the behavior depends on at least
+these Git variables: `push.default', `remote.pushDefault',
+`branch.<branch>.pushRemote', `branch.<branch>.remote',
+`branch.<branch>.merge', and `remote.<remote>.push'.
+
+To add this command to the push popup add this to your init file:
+
+ (with-eval-after-load \\='magit-remote
+ (magit-define-popup-action \\='magit-push-popup ?r
+ 'magit-push-to-remote--desc
+ 'magit-push-to-remote ?p t))"
+ (interactive (list (magit-read-remote "Push to remote")
+ (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args remote))
+
+(defun magit-push-to-remote--desc ()
+ (format "using %s\n" (propertize "git push <remote>" 'face 'bold)))
+
+;;; Email
+
+;;;###autoload (autoload 'magit-patch-popup "magit-remote" nil t)
+(magit-define-popup magit-patch-popup
+ "Popup console for patch commands."
+ 'magit-commands
+ :man-page "git-format-patch"
+ :switches '("Switches for formatting patches"
+ (?l "Add cover letter" "--cover-letter"))
+ :options '("Options for formatting patches"
+ (?f "From" "--from=")
+ (?t "To" "--to=")
+ (?c "CC" "--cc=")
+ (?r "In reply to" "--in-reply-to=")
+ (?v "Reroll count" "--reroll-count=")
+ (?s "Thread style" "--thread=")
+ (?U "Context lines" "-U")
+ (?M "Detect renames" "-M")
+ (?C "Detect copies" "-C")
+ (?A "Diff algorithm" "--diff-algorithm="
+ magit-diff-select-algorithm)
+ (?o "Output directory" "--output-directory="))
+ :actions '((?p "Format patches" magit-format-patch)
+ (?r "Request pull" magit-request-pull))
+ :default-action 'magit-format-patch)
+
+;;;###autoload
+(defun magit-format-patch (range args)
+ "Create patches for the commits in RANGE.
+When a single commit is given for RANGE, create a patch for the
+changes introduced by that commit (unlike 'git format-patch'
+which creates patches for all commits that are reachable from
+HEAD but not from the specified commit)."
+ (interactive
+ (list (-if-let (revs (magit-region-values 'commit))
+ (concat (car (last revs)) "^.." (car revs))
+ (let ((range (magit-read-range-or-commit "Format range or commit")))
+ (if (string-match-p "\\.\\." range)
+ range
+ (format "%s~..%s" range range))))
+ (magit-patch-arguments)))
+ (magit-call-git "format-patch" range args)
+ (when (member "--cover-letter" args)
+ (find-file
+ (expand-file-name
+ "0000-cover-letter.patch"
+ (let ((topdir (magit-toplevel)))
+ (or (--some (and (string-match "--output-directory=\\(.+\\)" it)
+ (expand-file-name (match-string 1 it) topdir))
+ args)
+ topdir))))))
+
+;;;###autoload
+(defun magit-request-pull (url start end)
+ "Request upstream to pull from you public repository.
+
+URL is the url of your publically accessible repository.
+START is a commit that already is in the upstream repository.
+END is the last commit, usually a branch name, which upstream
+is asked to pull. START has to be reachable from that commit."
+ (interactive
+ (list (magit-get "remote" (magit-read-remote "Remote") "url")
+ (magit-read-branch-or-commit "Start" (magit-get-upstream-branch))
+ (magit-read-branch-or-commit "End")))
+ (let ((dir default-directory))
+ ;; mu4e changes default-directory
+ (compose-mail)
+ (setq default-directory dir))
+ (message-goto-body)
+ (magit-git-insert "request-pull" start url end)
+ (set-buffer-modified-p nil))
+
+;;; magit-remote.el ends soon
+(provide 'magit-remote)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-remote.el ends here
--- /dev/null
+;;; magit-section.el --- section functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements "sections" as used in all Magit buffers.
+;; If you have used Magit before then you probably know what that
+;; means, otherwise think "read-only Org-Mode for Git", kinda.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+
+(require 'magit-utils)
+
+(defvar magit-keep-region-overlay)
+
+;;; Options
+
+(defgroup magit-section nil
+ "Expandable sections."
+ :group 'magit)
+
+(defcustom magit-section-show-child-count t
+ "Whether to append the number of children to section headings."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-section
+ :type 'boolean)
+
+(defcustom magit-section-movement-hook
+ '(magit-hunk-set-window-start
+ magit-log-maybe-update-revision-buffer
+ magit-log-maybe-show-more-commits)
+ "Hook run by `magit-section-goto'.
+That function in turn is used by all section movement commands."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-section
+ :type 'hook
+ :options '(magit-hunk-set-window-start
+ magit-status-maybe-update-revision-buffer
+ magit-status-maybe-update-blob-buffer
+ magit-log-maybe-update-revision-buffer
+ magit-log-maybe-update-blob-buffer
+ magit-log-maybe-show-more-commits))
+
+(defcustom magit-section-highlight-hook
+ '(magit-diff-highlight
+ magit-section-highlight
+ magit-section-highlight-selection)
+ "Functions used to highlight the current section.
+Each function is run with the current section as only argument
+until one of them returns non-nil."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-section
+ :type 'hook
+ :options '(magit-diff-highlight
+ magit-section-highlight
+ magit-section-highlight-selection))
+
+(defcustom magit-section-unhighlight-hook
+ '(magit-diff-unhighlight)
+ "Functions used to unhighlight the previously current section.
+Each function is run with the current section as only argument
+until one of them returns non-nil. Most sections are properly
+unhighlighted without requiring a specialized unhighlighter,
+diff-related sections being the only exception."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-section
+ :type 'hook
+ :options '(magit-diff-unhighlight))
+
+(defcustom magit-section-set-visibility-hook
+ '(magit-diff-expansion-threshold
+ magit-section-set-visibility-from-cache)
+ "Hook used to set the initial visibility of a section.
+Stop at the first function that returns non-nil. The value
+should be `show' or `hide'. If no function returns non-nil
+determine the visibility as usual, i.e. use the hardcoded
+section specific default (see `magit-insert-section')."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-section
+ :type 'hook
+ :options '(magit-diff-expansion-threshold
+ magit-section-set-visibility-from-cache))
+
+(defface magit-section-highlight
+ '((((class color) (background light)) :background "grey95")
+ (((class color) (background dark)) :background "grey20"))
+ "Face for highlighting the current section."
+ :group 'magit-faces)
+
+(defface magit-section-heading
+ '((((class color) (background light)) :foreground "DarkGoldenrod4" :weight bold)
+ (((class color) (background dark)) :foreground "LightGoldenrod2" :weight bold))
+ "Face for section headings."
+ :group 'magit-faces)
+
+(defface magit-section-secondary-heading '((t :weight bold))
+ "Face for section headings of some secondary headings."
+ :group 'magit-faces)
+
+(defface magit-section-heading-selection
+ '((((class color) (background light)) :foreground "salmon4")
+ (((class color) (background dark)) :foreground "LightSalmon3"))
+ "Face for selected section headings."
+ :group 'magit-faces)
+
+;;; Core
+
+(cl-defstruct magit-section
+ type value start content end hidden washer refined
+ source diff-header process parent children)
+
+(defvar-local magit-root-section nil
+ "The root section in the current buffer.
+All other sections are descendants of this section. The value
+of this variable is set by `magit-insert-section' and you should
+never modify it.")
+(put 'magit-root-section 'permanent-local t)
+
+(defun magit-current-section ()
+ "Return the section at point."
+ (or (get-text-property (point) 'magit-section) magit-root-section))
+
+(defun magit-section-ident (section)
+ "Return an unique identifier for SECTION.
+The return value has the form ((TYPE . VALUE)...)."
+ (cons (cons (magit-section-type section)
+ (magit-section-value section))
+ (--when-let (magit-section-parent section)
+ (magit-section-ident it))))
+
+(defun magit-get-section (ident &optional root)
+ "Return the section identified by IDENT.
+IDENT has to be a list as returned by `magit-section-ident'."
+ (setq ident (reverse ident))
+ (let ((section (or root magit-root-section)))
+ (when (eq (car (pop ident)) (magit-section-type section))
+ (while (and ident
+ (setq section
+ (--first
+ (and (eq (caar ident) (magit-section-type it))
+ (equal (cdar ident) (magit-section-value it)))
+ (magit-section-children section))))
+ (pop ident))
+ section)))
+
+(defvar magit-insert-section--current nil "For internal use only.")
+(defvar magit-insert-section--parent nil "For internal use only.")
+(defvar magit-insert-section--oldroot nil "For internal use only.")
+
+;;; Commands
+;;;; Movement
+
+(defun magit-section-forward ()
+ "Move to the beginning of the next visible section."
+ (interactive)
+ (if (eobp)
+ (user-error "No next section")
+ (let ((section (magit-current-section)))
+ (if (magit-section-parent section)
+ (let ((next (and (not (magit-section-hidden section))
+ (not (= (magit-section-end section) (1+ (point))))
+ (car (magit-section-children section)))))
+ (while (and section (not next))
+ (unless (setq next (car (magit-section-siblings section 'next)))
+ (setq section (magit-section-parent section))))
+ (if next
+ (magit-section-goto next)
+ (user-error "No next section")))
+ (magit-section-goto 1)))))
+
+(defun magit-section-backward ()
+ "Move to the beginning of the current or the previous visible section.
+When point is at the beginning of a section then move to the
+beginning of the previous visible section. Otherwise move to
+the beginning of the current section."
+ (interactive)
+ (if (bobp)
+ (user-error "No previous section")
+ (let ((section (magit-current-section)) children)
+ (cond
+ ((and (= (point) (1- (magit-section-end section)))
+ (setq children (magit-section-children section)))
+ (magit-section-goto (car (last children))))
+ ((and (magit-section-parent section)
+ (not (= (point) (magit-section-start section))))
+ (magit-section-goto section))
+ (t
+ (let ((prev (car (magit-section-siblings section 'prev))))
+ (if prev
+ (while (and (not (magit-section-hidden prev))
+ (setq children (magit-section-children prev)))
+ (setq prev (car (last children))))
+ (setq prev (magit-section-parent section)))
+ (cond (prev
+ (magit-section-goto prev))
+ ((magit-section-parent section)
+ (user-error "No previous section"))
+ ;; Eob special cases.
+ ((not (get-text-property (1- (point)) 'invisible))
+ (magit-section-goto -1))
+ (t
+ (goto-char (previous-single-property-change
+ (1- (point)) 'invisible))
+ (forward-line -1)
+ (magit-section-goto (magit-current-section))))))))))
+
+(defun magit-section-up ()
+ "Move to the beginning of the parent section."
+ (interactive)
+ (--if-let (magit-section-parent (magit-current-section))
+ (magit-section-goto it)
+ (user-error "No parent section")))
+
+(defun magit-section-forward-sibling ()
+ "Move to the beginning of the next sibling section.
+If there is no next sibling section, then move to the parent."
+ (interactive)
+ (let ((current (magit-current-section)))
+ (if (magit-section-parent current)
+ (--if-let (car (magit-section-siblings current 'next))
+ (magit-section-goto it)
+ (magit-section-forward))
+ (magit-section-goto 1))))
+
+(defun magit-section-backward-sibling ()
+ "Move to the beginning of the previous sibling section.
+If there is no previous sibling section, then move to the parent."
+ (interactive)
+ (let ((current (magit-current-section)))
+ (if (magit-section-parent current)
+ (--if-let (car (magit-section-siblings current 'prev))
+ (magit-section-goto it)
+ (magit-section-backward))
+ (magit-section-goto -1))))
+
+(defun magit-section-goto (arg)
+ (if (integerp arg)
+ (progn (forward-line arg)
+ (setq arg (magit-current-section)))
+ (goto-char (magit-section-start arg)))
+ (run-hook-with-args 'magit-section-movement-hook arg))
+
+(defun magit-section-set-window-start (section)
+ "Ensure the beginning of SECTION is visible."
+ (unless (pos-visible-in-window-p (magit-section-end section))
+ (set-window-start (selected-window) (magit-section-start section))))
+
+(defun magit-hunk-set-window-start (section)
+ "Ensure the beginning of the `hunk' SECTION is visible.
+It the SECTION has a different type, then do nothing."
+ (when (eq (magit-section-type section) 'hunk)
+ (magit-section-set-window-start section)))
+
+(defmacro magit-define-section-jumper (name heading type &optional value)
+ "Define an interactive function to go some section.
+Together TYPE and VALUE identify the section.
+HEADING is the displayed heading of the section."
+ (declare (indent defun))
+ `(defun ,name (&optional expand) ,(format "\
+Jump to the section \"%s\".
+With a prefix argument also expand it." heading)
+ (interactive "P")
+ (--if-let (magit-get-section
+ (cons (cons ',type ,value)
+ (magit-section-ident magit-root-section)))
+ (progn (goto-char (magit-section-start it))
+ (when expand
+ (with-local-quit (magit-section-show it))
+ (recenter 0)))
+ (message ,(format "Section \"%s\" wasn't found" heading)))))
+
+;;;; Visibility
+
+(defun magit-section-show (section)
+ "Show the body of the current section."
+ (interactive (list (magit-current-section)))
+ (setf (magit-section-hidden section) nil)
+ (-when-let (washer (magit-section-washer section))
+ (setf (magit-section-washer section) nil)
+ (let ((inhibit-read-only t)
+ (magit-insert-section--parent section)
+ (content (magit-section-content section)))
+ (save-excursion
+ (if (and content (< content (magit-section-end section)))
+ (funcall washer section) ; already partially washed (hunk)
+ (goto-char (magit-section-end section))
+ (setf (magit-section-content section) (point-marker))
+ (funcall washer)
+ (setf (magit-section-end section) (point-marker)))))
+ (magit-section-update-highlight))
+ (-when-let (beg (magit-section-content section))
+ (remove-overlays beg (magit-section-end section) 'invisible t))
+ (magit-section-update-visibility-cache section)
+ (dolist (child (magit-section-children section))
+ (if (magit-section-hidden child)
+ (magit-section-hide child)
+ (magit-section-show child))))
+
+(defun magit-section-hide (section)
+ "Hide the body of the current section."
+ (interactive (list (magit-current-section)))
+ (if (eq section magit-root-section)
+ (user-error "Cannot hide root section")
+ (setf (magit-section-hidden section) t)
+ (-when-let (beg (magit-section-content section))
+ (let ((end (magit-section-end section)))
+ (remove-overlays beg end 'invisible t)
+ (let ((o (make-overlay beg end)))
+ (overlay-put o 'evaporate t)
+ (overlay-put o 'invisible t))))
+ (when (memq (magit-section-type section) '(unpulled unpushed))
+ (magit-section-cache-visibility section))))
+
+(defun magit-section-toggle (section)
+ "Toggle visibility of the body of the current section."
+ (interactive (list (magit-current-section)))
+ (if (eq section magit-root-section)
+ (user-error "Cannot hide root section")
+ (goto-char (magit-section-start section))
+ (if (magit-section-hidden section)
+ (magit-section-show section)
+ (magit-section-hide section))))
+
+(defun magit-section-toggle-children (section)
+ "Toggle visibility of bodies of children of the current section."
+ (interactive (list (magit-current-section)))
+ (goto-char (magit-section-start section))
+ (let* ((children (magit-section-children section))
+ (show (-any? 'magit-section-hidden children)))
+ (dolist (c children)
+ (setf (magit-section-hidden c) show)))
+ (magit-section-show section))
+
+(defun magit-section-show-children (section &optional depth)
+ "Recursively show the bodies of children of the current section.
+With a prefix argument show children that deep and hide deeper
+children."
+ (interactive (list (magit-current-section)))
+ (magit-section-show-children-1 section depth)
+ (magit-section-show section))
+
+(defun magit-section-show-children-1 (section &optional depth)
+ (dolist (s (magit-section-children section))
+ (setf (magit-section-hidden s) nil)
+ (if depth
+ (if (> depth 0)
+ (magit-section-show-children-1 s (1- depth))
+ (magit-section-hide s))
+ (magit-section-show-children-1 s))))
+
+(defun magit-section-hide-children (section)
+ "Recursively hide the bodies of children of the current section."
+ (interactive (list (magit-current-section)))
+ (mapc 'magit-section-hide (magit-section-children section)))
+
+(defun magit-section-show-headings (section)
+ "Recursively show headings of children of the current section.
+Only show the headings, previously shown text-only bodies are
+hidden."
+ (interactive (list (magit-current-section)))
+ (magit-section-show-headings-1 section)
+ (magit-section-show section))
+
+(defun magit-section-show-headings-1 (section)
+ (dolist (s (magit-section-children section))
+ (setf (magit-section-hidden s) nil)
+ (when (or (magit-section-children s)
+ (not (magit-section-content s)))
+ (magit-section-show-headings-1 s))))
+
+(defun magit-section-cycle (section)
+ "Cycle visibility of current section and its children."
+ (interactive (list (magit-current-section)))
+ (goto-char (magit-section-start section))
+ (if (magit-section-hidden section)
+ (progn (magit-section-show section)
+ (magit-section-hide-children section))
+ (let ((children (magit-section-children section)))
+ (cond ((and (-any? 'magit-section-hidden children)
+ (-any? 'magit-section-children children))
+ (magit-section-show-headings section))
+ ((-any? 'magit-section-hidden-body children)
+ (magit-section-show-children section))
+ (t
+ (magit-section-hide section))))))
+
+(defun magit-section-cycle-global ()
+ "Cycle visibility of all sections in the current buffer."
+ (interactive)
+ (let ((children (magit-section-children magit-root-section)))
+ (cond ((and (-any? 'magit-section-hidden children)
+ (-any? 'magit-section-children children))
+ (magit-section-show-headings magit-root-section))
+ ((-any? 'magit-section-hidden-body children)
+ (magit-section-show-children magit-root-section))
+ (t
+ (mapc 'magit-section-hide children)))))
+
+(defun magit-section-cycle-diffs ()
+ "Cycle visibility of diff-related sections in the current buffer."
+ (interactive)
+ (-when-let (sections
+ (cond ((derived-mode-p 'magit-status-mode)
+ (--mapcat
+ (when it
+ (when (magit-section-hidden it)
+ (magit-section-show it))
+ (magit-section-children it))
+ (list (magit-get-section '((staged) (status)))
+ (magit-get-section '((unstaged) (status))))))
+ ((derived-mode-p 'magit-diff-mode)
+ (--filter (eq (magit-section-type it) 'file)
+ (magit-section-children magit-root-section)))))
+ (if (-any? 'magit-section-hidden sections)
+ (dolist (s sections)
+ (magit-section-show s)
+ (magit-section-hide-children s))
+ (let ((children (-mapcat 'magit-section-children sections)))
+ (cond ((and (-any? 'magit-section-hidden children)
+ (-any? 'magit-section-children children))
+ (mapc 'magit-section-show-headings sections))
+ ((-any? 'magit-section-hidden-body children)
+ (mapc 'magit-section-show-children sections))
+ (t
+ (mapc 'magit-section-hide sections)))))))
+
+(defun magit-section-hidden-body (section &optional pred)
+ (--if-let (magit-section-children section)
+ (funcall (or pred '-any?) 'magit-section-hidden-body it)
+ (and (magit-section-content section)
+ (magit-section-hidden section))))
+
+(defun magit-section-invisible-p (section)
+ "Return t if the SECTION's body is invisible.
+When the body of an ancestor of SECTION is collapsed then
+SECTION's body (and heading) obviously cannot be visible."
+ (or (magit-section-hidden section)
+ (--when-let (magit-section-parent section)
+ (magit-section-invisible-p it))))
+
+(defun magit-section-show-level (level)
+ "Show surrounding sections up to LEVEL.
+If LEVEL is negative show up to the absolute value.
+Sections at higher levels are hidden."
+ (if (< level 0)
+ (let ((s (magit-current-section)))
+ (setq level (- level))
+ (while (> (1- (length (magit-section-ident s))) level)
+ (setq s (magit-section-parent s))
+ (goto-char (magit-section-start s)))
+ (magit-section-show-children magit-root-section (1- level)))
+ (cl-do* ((s (magit-current-section) (magit-section-parent s))
+ (i (1- (length (magit-section-ident s))) (cl-decf i)))
+ ((cond ((< i level) (magit-section-show-children s (- level i 1)) t)
+ ((= i level) (magit-section-hide s) t))
+ (magit-section-goto s)))))
+
+(defun magit-section-show-level-1 ()
+ "Show surrounding sections on first level."
+ (interactive)
+ (magit-section-show-level 1))
+
+(defun magit-section-show-level-1-all ()
+ "Show all sections on first level."
+ (interactive)
+ (magit-section-show-level -1))
+
+(defun magit-section-show-level-2 ()
+ "Show surrounding sections up to second level."
+ (interactive)
+ (magit-section-show-level 2))
+
+(defun magit-section-show-level-2-all ()
+ "Show all sections up to second level."
+ (interactive)
+ (magit-section-show-level -2))
+
+(defun magit-section-show-level-3 ()
+ "Show surrounding sections up to third level."
+ (interactive)
+ (magit-section-show-level 3))
+
+(defun magit-section-show-level-3-all ()
+ "Show all sections up to third level."
+ (interactive)
+ (magit-section-show-level -3))
+
+(defun magit-section-show-level-4 ()
+ "Show surrounding sections up to fourth level."
+ (interactive)
+ (magit-section-show-level 4))
+
+(defun magit-section-show-level-4-all ()
+ "Show all sections up to fourth level."
+ (interactive)
+ (magit-section-show-level -4))
+
+;;;; Auxiliary
+
+(defun magit-describe-section ()
+ "Show information about the section at point.
+This command is intended for debugging purposes."
+ (interactive)
+ (let ((section (magit-current-section)))
+ (message "%S %S %s-%s"
+ (magit-section-value section)
+ (apply 'vector (mapcar 'car (magit-section-ident section)))
+ (marker-position (magit-section-start section))
+ (marker-position (magit-section-end section)))))
+
+;;; Match
+
+(cl-defun magit-section-match
+ (condition &optional (section (magit-current-section)))
+ "Return t if SECTION matches CONDITION.
+
+SECTION defaults to the section at point. If SECTION is not
+specified and there also is no section at point, then return
+nil.
+
+CONDITION can take the following forms:
+ (CONDITION...) matches if any of the CONDITIONs matches.
+ [TYPE...] matches if the first TYPE matches the type
+ of the section, the second matches that of
+ its parent, and so on.
+ [* TYPE...] matches sections that match [TYPE...] and
+ also recursively all their child sections.
+ TYPE matches sections of TYPE regardless of the
+ types of the parent sections.
+
+Each TYPE is a symbol. Note that it is not necessary to specify
+all TYPEs up to the root section as printed by
+`magit-describe-type', unless of course you want to be that
+precise."
+ ;; When recursing SECTION actually is a type list. Matching
+ ;; macros also pass such a list instead of a section struct.
+ (and section
+ (magit-section-match-1 condition
+ (mapcar #'car (magit-section-ident section)))))
+
+(defun magit-section-match-1 (condition type-list)
+ (if (listp condition)
+ (--first (magit-section-match-1 it type-list) condition)
+ (magit-section-match-2 (if (symbolp condition)
+ (list condition)
+ (append condition nil))
+ type-list)))
+
+(defun magit-section-match-2 (l1 l2)
+ (or (null l1)
+ (if (eq (car l1) '*)
+ (or (magit-section-match-2 (cdr l1) l2)
+ (and l2
+ (magit-section-match-2 l1 (cdr l2))))
+ (and l2
+ (equal (car l1) (car l2))
+ (magit-section-match-2 (cdr l1) (cdr l2))))))
+
+(defmacro magit-section-when (condition &rest body)
+ "If the section at point matches CONDITION evaluate BODY.
+
+If the section matches, then evaluate BODY forms sequentially
+with `it' bound to the section and return the value of the last
+form. If there are no BODY forms, then return the value of the
+section. If the section does not match or if there is no section
+at point then return nil.
+
+See `magit-section-match' for the forms CONDITION can take."
+ (declare (indent 1)
+ (debug (sexp body)))
+ `(--when-let (magit-current-section)
+ (when (magit-section-match ',condition it)
+ ,@(or body '((magit-section-value it))))))
+
+(defmacro magit-section-case (&rest clauses)
+ "Choose among clauses on the type of the section at point.
+
+Each clause looks like (CONDITION BODY...). The type of the
+section is compared against each CONDITION; the BODY forms of the
+first match are evaluated sequentially and the value of the last
+form is returned. Inside BODY the symbol `it' is bound to the
+section at point. If no clause succeeds or if there is no
+section at point return nil.
+
+See `magit-section-match' for the forms CONDITION can take.
+Additionally a CONDITION of t is allowed in the final clause, and
+matches if no other CONDITION match, even if there is no section
+at point."
+ (declare (indent 0)
+ (debug (&rest (sexp body))))
+ (let ((ident (cl-gensym "id")))
+ `(let* ((it (magit-current-section))
+ (,ident (and it (mapcar 'car (magit-section-ident it)))))
+ (cond ,@(mapcar (lambda (clause)
+ `(,(or (eq (car clause) t)
+ `(and it (magit-section-match-1
+ ',(car clause) ,ident)))
+ ,@(cdr clause)))
+ clauses)))))
+;;; Create
+
+(defvar magit-insert-section-hook nil
+ "Hook run after `magit-insert-section's BODY.
+Avoid using this hook and only ever do so if you know
+what you are doing and are sure there is no other way.")
+
+(defmacro magit-insert-section (&rest args)
+ "Insert a section at point.
+
+TYPE is the section type, a symbol. Many commands that act on
+the current section behave differently depending on that type.
+Also if a variable `magit-TYPE-section-map' exists, then use
+that as the text-property `keymap' of all text belonging to the
+section (but this may be overwritten in subsections). TYPE can
+also have the form `(eval FORM)' in which case FORM is evaluated
+at runtime.
+
+Optional VALUE is the value of the section, usually a string
+that is required when acting on the section.
+
+When optional HIDE is non-nil collapse the section body by
+default, i.e. when first creating the section, but not when
+refreshing the buffer. Else expand it by default. This can be
+overwritten using `magit-section-set-visibility-hook'. When a
+section is recreated during a refresh, then the visibility of
+predecessor is inherited and HIDE is ignored (but the hook is
+still honored).
+
+BODY is any number of forms that actually insert the section's
+heading and body. Optional NAME, if specified, has to be a
+symbol, which is then bound to the struct of the section being
+inserted.
+
+Before BODY is evaluated the `start' of the section object is set
+to the value of `point' and after BODY was evaluated its `end' is
+set to the new value of `point'; BODY is responsible for moving
+`point' forward.
+
+If it turns out inside BODY that the section is empty, then
+`magit-cancel-section' can be used to abort and remove all traces
+of the partially inserted section. This can happen when creating
+a section by washing Git's output and Git didn't actually output
+anything this time around.
+
+\(fn [NAME] (TYPE &optional VALUE HIDE) &rest BODY)"
+ (declare (indent defun)
+ (debug ([&optional symbolp]
+ (&or [("eval" symbolp) &optional form form]
+ [symbolp &optional form form])
+ body)))
+ (let ((s (if (symbolp (car args))
+ (pop args)
+ (cl-gensym "section"))))
+ `(let* ((,s (make-magit-section
+ :type ,(let ((type (nth 0 (car args))))
+ (if (eq (car-safe type) 'eval)
+ (cadr type)
+ `',type))
+ :value ,(nth 1 (car args))
+ :start (point-marker)
+ :parent magit-insert-section--parent)))
+ (setf (magit-section-hidden ,s)
+ (-if-let (value (run-hook-with-args-until-success
+ 'magit-section-set-visibility-hook ,s))
+ (eq value 'hide)
+ (--if-let (and magit-insert-section--oldroot
+ (magit-get-section
+ (magit-section-ident ,s)
+ magit-insert-section--oldroot))
+ (magit-section-hidden it)
+ ,(nth 2 (car args)))))
+ (let ((magit-insert-section--current ,s)
+ (magit-insert-section--parent ,s)
+ (magit-insert-section--oldroot
+ (or magit-insert-section--oldroot
+ (unless magit-insert-section--parent
+ (prog1 magit-root-section
+ (setq magit-root-section ,s))))))
+ (catch 'cancel-section
+ ,@(cdr args)
+ (run-hooks 'magit-insert-section-hook)
+ (magit-insert-child-count ,s)
+ (set-marker-insertion-type (magit-section-start ,s) t)
+ (let* ((end (setf (magit-section-end ,s) (point-marker)))
+ (map (intern (format "magit-%s-section-map"
+ (magit-section-type ,s))))
+ (map (and (boundp map) (symbol-value map))))
+ (save-excursion
+ (goto-char (magit-section-start ,s))
+ (while (< (point) end)
+ (let ((next (or (next-single-property-change
+ (point) 'magit-section)
+ end)))
+ (unless (get-text-property (point) 'magit-section)
+ (put-text-property (point) next 'magit-section ,s)
+ (when map
+ (put-text-property (point) next 'keymap map)))
+ (goto-char next)))))
+ (if (eq ,s magit-root-section)
+ (magit-section-show ,s)
+ (setf (magit-section-children (magit-section-parent ,s))
+ (nconc (magit-section-children (magit-section-parent ,s))
+ (list ,s)))))
+ ,s))))
+
+(defun magit-cancel-section ()
+ (when magit-insert-section--current
+ (if (not (magit-section-parent magit-insert-section--current))
+ (insert "(empty)\n")
+ (delete-region (magit-section-start magit-insert-section--current)
+ (point))
+ (setq magit-insert-section--current nil)
+ (throw 'cancel-section nil))))
+
+(defun magit-insert-heading (&rest args)
+ "Insert the heading for the section currently being inserted.
+
+This function should only be used inside `magit-insert-section'.
+
+When called without any arguments, then just set the `content'
+slot of the object representing the section being inserted to
+a marker at `point'. The section should only contain a single
+line when this function is used like this.
+
+When called with arguments ARGS, which have to be strings, then
+insert those strings at point. The section should not contain
+any text before this happens and afterwards it should again only
+contain a single line. If the `face' property is set anywhere
+inside any of these strings, then insert all of them unchanged.
+Otherwise use the `magit-section-heading' face for all inserted
+text.
+
+The `content' property of the section struct is the end of the
+heading (which lasts from `start' to `content') and the beginning
+of the the body (which lasts from `content' to `end'). If the
+value of `content' is nil, then the section has no heading and
+its body cannot be collapsed. If a section does have a heading
+then its height must be exactly one line, including a trailing
+newline character. This isn't enforced, you are responsible for
+getting it right. The only exception is that this function does
+insert a newline character if necessary."
+ (declare (indent defun))
+ (when args
+ (let ((heading (apply #'concat args)))
+ (insert (if (next-single-property-change 0 'face (concat "0" heading))
+ heading
+ (propertize heading 'face 'magit-section-heading)))))
+ (unless (bolp)
+ (insert ?\n))
+ (setf (magit-section-content magit-insert-section--current) (point-marker)))
+
+(defvar magit-insert-headers-hook nil "For internal use only.")
+
+(defun magit-insert-headers (hooks)
+ (let ((magit-insert-section-hook
+ (cons 'magit-insert-remaining-headers
+ (if (listp magit-insert-section-hook)
+ magit-insert-section-hook
+ (list magit-insert-section-hook))))
+ (magit-insert-headers-hook hooks)
+ wrapper)
+ (while (and (setq wrapper (pop magit-insert-headers-hook))
+ (= (point) (point-min)))
+ (funcall wrapper))))
+
+(defun magit-insert-remaining-headers ()
+ (if (= (point) (point-min))
+ (magit-cancel-section)
+ (magit-insert-heading)
+ (remove-hook 'magit-insert-section-hook 'magit-insert-remaining-headers)
+ (mapc #'funcall magit-insert-headers-hook)
+ (insert "\n")))
+
+(defun magit-insert-child-count (section)
+ "Modify SECTION's heading to contain number of child sections.
+
+If `magit-section-show-child-count' is non-nil and the SECTION
+has children and its heading ends with \":\", then replace that
+with \" (N)\", where N is the number of child sections.
+
+This function is called by `magit-insert-section' after that has
+evaluated its BODY. Admittedly that's a bit of a hack."
+ ;; This has to be fast, not pretty!
+ (let (content count)
+ (when (and magit-section-show-child-count
+ (setq count (length (magit-section-children section)))
+ (> count 0)
+ (setq content (magit-section-content section))
+ (eq (char-before (1- content)) ?:))
+ (save-excursion
+ (goto-char (- content 2))
+ (insert (format " (%s)" count))
+ (delete-char 1)))))
+
+;;; Update
+
+(defvar-local magit-section-highlight-overlays nil)
+(defvar-local magit-section-highlighted-section nil)
+(defvar-local magit-section-highlighted-sections nil)
+(defvar-local magit-section-unhighlight-sections nil)
+
+(defun magit-section-update-region (_)
+ ;; Don't show complete region. Highlighting emphasizes headings.
+ (magit-region-sections))
+
+(defun magit-section-update-highlight ()
+ (let ((section (magit-current-section)))
+ (unless (eq section magit-section-highlighted-section)
+ (let ((inhibit-read-only t)
+ (deactivate-mark nil)
+ (selection (magit-region-sections)))
+ (mapc #'delete-overlay magit-section-highlight-overlays)
+ (setq magit-section-unhighlight-sections
+ magit-section-highlighted-sections
+ magit-section-highlighted-sections nil)
+ (unless (eq section magit-root-section)
+ (run-hook-with-args-until-success
+ 'magit-section-highlight-hook section selection))
+ (--each magit-section-unhighlight-sections
+ (run-hook-with-args-until-success
+ 'magit-section-unhighlight-hook it selection))
+ (restore-buffer-modified-p nil)
+ (unless (eq magit-section-highlighted-section section)
+ (setq magit-section-highlighted-section
+ (unless (magit-section-hidden section) section))))
+ (setq deactivate-mark nil))))
+
+(defun magit-section-highlight (section selection)
+ "Highlight SECTION and if non-nil all SELECTION.
+This function works for any section but produces undesirable
+effects for diff related sections, which by default are
+highlighted using `magit-diff-highlight'. Return t."
+ (cond (selection
+ (magit-section-make-overlay (magit-section-start (car selection))
+ (magit-section-end (car (last selection)))
+ 'magit-section-highlight)
+ (magit-section-highlight-selection nil selection))
+ (t
+ (magit-section-make-overlay (magit-section-start section)
+ (magit-section-end section)
+ 'magit-section-highlight)))
+ t)
+
+(defun magit-section-highlight-selection (_ selection)
+ "Highlight the section selection region.
+If SELECTION is non-nil then it is a list of sections selected by
+the region. The headings of these sections are then highlighted.
+
+This is a fallback for people who don't want to highlight the
+current section and therefore removed `magit-section-highlight'
+from `magit-section-highlight-hook'.
+
+This function is necessary to ensure that a representation of
+such a region is visible. If neither of these functions were
+part of the hook variable, then such a region would be
+invisible."
+ (when selection
+ (--each selection
+ (magit-section-make-overlay (magit-section-start it)
+ (or (magit-section-content it)
+ (magit-section-end it))
+ 'magit-section-heading-selection))
+ t))
+
+(defun magit-section-make-overlay (start end face)
+ ;; Yes, this doesn't belong here. But the alternative of
+ ;; spreading this hack across the code base is even worse.
+ (when (and magit-keep-region-overlay
+ (memq face '(magit-section-heading-selection
+ magit-diff-file-heading-selection
+ magit-diff-hunk-heading-selection)))
+ (setq face (list :foreground (face-foreground face))))
+ (let ((ov (make-overlay start end nil t)))
+ (overlay-put ov 'face face)
+ (overlay-put ov 'evaporate t)
+ (push ov magit-section-highlight-overlays)
+ ov))
+
+(defun magit-section-goto-successor (section line char arg)
+ (let ((ident (magit-section-ident section)))
+ (--if-let (magit-get-section ident)
+ (let ((start (magit-section-start it)))
+ (goto-char start)
+ (unless (eq it magit-root-section)
+ (ignore-errors
+ (forward-line line)
+ (forward-char char))
+ (unless (eq (magit-current-section) it)
+ (goto-char start))))
+ (or (and (eq (magit-section-type section) 'hunk)
+ (-when-let (parent (magit-get-section
+ (magit-section-ident
+ (magit-section-parent section))))
+ (let* ((children (magit-section-children parent))
+ (siblings (magit-section-siblings section 'prev))
+ (previous (nth (length siblings) children)))
+ (if (not arg)
+ (--when-let (or previous (car (last children)))
+ (magit-section-goto it)
+ t)
+ (when previous
+ (magit-section-goto previous))
+ (if (and (stringp arg)
+ (re-search-forward
+ arg (magit-section-end parent) t))
+ (goto-char (match-beginning 0))
+ (goto-char (magit-section-end (car (last children))))
+ (forward-line -1)
+ (while (looking-at "^ ") (forward-line -1))
+ (while (looking-at "^[-+]") (forward-line -1))
+ (forward-line))))))
+ (goto-char (--if-let (magit-section-goto-successor-1 section)
+ (if (eq (magit-section-type it) 'button)
+ (point-min)
+ (magit-section-start it))
+ (point-min)))))))
+
+(defun magit-section-goto-successor-1 (section)
+ (or (--when-let (pcase (magit-section-type section)
+ (`staged 'unstaged)
+ (`unstaged 'staged)
+ (`unpushed 'unpulled)
+ (`unpulled 'unpushed))
+ (magit-get-section `((,it) (status))))
+ (--when-let (car (magit-section-siblings section 'next))
+ (magit-get-section (magit-section-ident it)))
+ (--when-let (car (magit-section-siblings section 'prev))
+ (magit-get-section (magit-section-ident it)))
+ (--when-let (magit-section-parent section)
+ (or (magit-get-section (magit-section-ident it))
+ (magit-section-goto-successor-1 it)))))
+
+;;; Visibility
+
+(defvar-local magit-section-visibility-cache nil)
+(put 'magit-section-visibility-cache 'permanent-local t)
+
+(defun magit-section-set-visibility-from-cache (section)
+ "Set SECTION's visibility to the cached value.
+Currently the cache can only be used to remember that a section's
+body should be collapsed, not that it should be expanded. Return
+either `hide' or nil."
+ (and (member (magit-section-visibility-ident section)
+ magit-section-visibility-cache)
+ 'hide))
+
+(cl-defun magit-section-cache-visibility
+ (&optional (section magit-insert-section--current))
+ (let ((ident (magit-section-visibility-ident section)))
+ (if (magit-section-hidden section)
+ (cl-pushnew ident magit-section-visibility-cache :test #'equal)
+ (setq magit-section-visibility-cache
+ (delete ident magit-section-visibility-cache)))))
+
+(defun magit-section-update-visibility-cache (section)
+ (setq magit-section-visibility-cache
+ (delete (magit-section-visibility-ident section)
+ magit-section-visibility-cache)))
+
+(defun magit-section-visibility-ident (section)
+ (let ((type (magit-section-type section))
+ (value (magit-section-value section)))
+ (cons type
+ (cond ((not (memq type '(unpulled unpushed))) value)
+ ((string-match-p "@{upstream}" value) value)
+ ;; Unfortunately Git chokes on "@{push}" when the
+ ;; value of `push.default' does not allow a 1:1
+ ;; mapping. But collapsed logs of unpushed and
+ ;; unpulled commits in the status buffer should
+ ;; remain invisible after changing branches.
+ ;; So we have to pretend the value is constant.
+ ((string-match-p "\\`\\.\\." value) "..@{push}")
+ (t "@{push}..")))))
+
+;;; Utilities
+
+(cl-defun magit-section-selected-p (section &optional (selection nil sselection))
+ (and (not (eq section magit-root-section))
+ (or (eq section (magit-current-section))
+ (memq section (if sselection
+ selection
+ (setq selection (magit-region-sections))))
+ (--when-let (magit-section-parent section)
+ (magit-section-selected-p it selection)))))
+
+(defun magit-section-parent-value (section)
+ (setq section (magit-section-parent section))
+ (when section (magit-section-value section)))
+
+(defun magit-section-siblings (section &optional direction)
+ "Return a list of the sibling sections of SECTION.
+
+If optional DIRECTION is `prev' then return siblings that come
+before SECTION, if it is `next' then return siblings that come
+after SECTION. For all other values return all siblings
+excluding SECTION itself."
+ (-when-let (parent (magit-section-parent section))
+ (let ((siblings (magit-section-children parent)))
+ (pcase direction
+ (`prev (cdr (member section (reverse siblings))))
+ (`next (cdr (member section siblings)))
+ (_ (remq section siblings))))))
+
+(defun magit-region-values (&rest types)
+ "Return a list of the values of the selected sections.
+
+Also see `magit-region-sections' whose doc-string explains when a
+region is a valid section selection. If the region is not active
+or is not a valid section selection, then return nil. If optional
+TYPES is non-nil then the selection not only has to be valid; the
+types of all selected sections additionally have to match one of
+TYPES, or nil is returned."
+ (mapcar 'magit-section-value (apply 'magit-region-sections types)))
+
+(defun magit-region-sections (&rest types)
+ "Return a list of the selected sections.
+
+When the region is active and constitutes a valid section
+selection, then return a list of all selected sections. This is
+the case when the region begins in the heading of a section and
+ends in the heading of a sibling of that first section. When
+the selection is not valid then return nil. Most commands that
+can act on the selected sections, then instead just act on the
+current section, the one point is in.
+
+When the region looks like it would in any other buffer then
+the selection is invalid. When the selection is valid then the
+region uses the `magit-section-highlight' face. This does not
+apply to diffs where things get a bit more complicated, but even
+here if the region looks like it usually does, then that's not
+a valid selection as far as this function is concerned.
+
+If optional TYPES is non-nil then the selection not only has to
+be valid; the types of all selected sections additionally have to
+match one of TYPES, or nil is returned."
+ (when (use-region-p)
+ (let* ((rbeg (region-beginning))
+ (rend (region-end))
+ (sbeg (get-text-property rbeg 'magit-section))
+ (send (get-text-property rend 'magit-section)))
+ (unless (memq send (list sbeg magit-root-section nil))
+ (let ((siblings (magit-section-siblings sbeg 'next)) sections)
+ (when (and (memq send siblings)
+ (magit-section-position-in-heading-p sbeg rbeg)
+ (magit-section-position-in-heading-p send rend))
+ (while siblings
+ (push (car siblings) sections)
+ (when (eq (pop siblings) send)
+ (setq siblings nil)))
+ (setq sections (cons sbeg (nreverse sections)))
+ (when (or (not types)
+ (--all-p (memq (magit-section-type it) types) sections))
+ sections)))))))
+
+(defun magit-section-position-in-heading-p (section pos)
+ "Return t if POSITION is inside the heading of SECTION."
+ (and (>= pos (magit-section-start section))
+ (< pos (or (magit-section-content section)
+ (magit-section-end section)))
+ t))
+
+(defun magit-section-internal-region-p (&optional section)
+ "Return t if the region is active and inside SECTION's body.
+If optional SECTION is nil, use the current section."
+ (and (region-active-p)
+ (or section (setq section (magit-current-section)))
+ (let ((beg (get-text-property (region-beginning) 'magit-section)))
+ (and (eq beg (get-text-property (region-end) 'magit-section))
+ (eq beg section)))
+ (not (or (magit-section-position-in-heading-p section (region-beginning))
+ (magit-section-position-in-heading-p section (region-end))))
+ t))
+
+(defun magit-wash-sequence (function)
+ "Repeatedly call FUNCTION until it returns nil or eob is reached.
+FUNCTION has to move point forward or return nil."
+ (while (and (not (eobp)) (funcall function))))
+
+(defun magit-add-section-hook (hook function &optional at append local)
+ "Add to the value of section hook HOOK the function FUNCTION.
+
+Add FUNCTION at the beginning of the hook list unless optional
+APPEND is non-nil, in which case FUNCTION is added at the end.
+If FUNCTION already is a member then move it to the new location.
+
+If optional AT is non-nil and a member of the hook list, then
+add FUNCTION next to that instead. Add before or after AT, or
+replace AT with FUNCTION depending on APPEND. If APPEND is the
+symbol `replace', then replace AT with FUNCTION. For any other
+non-nil value place FUNCTION right after AT. If nil, then place
+FUNCTION right before AT. If FUNCTION already is a member of the
+list but AT is not, then leave FUNCTION where ever it already is.
+
+If optional LOCAL is non-nil, then modify the hook's buffer-local
+value rather than its global value. This makes the hook local by
+copying the default value. That copy is then modified.
+
+HOOK should be a symbol. If HOOK is void, it is first set to nil.
+HOOK's value must not be a single hook function. FUNCTION should
+be a function that takes no arguments and inserts one or multiple
+sections at point, moving point forward. FUNCTION may choose not
+to insert its section(s), when doing so would not make sense. It
+should not be abused for other side-effects. To remove FUNCTION
+again use `remove-hook'."
+ (unless (boundp hook)
+ (error "Cannot add function to undefined hook variable %s" hook))
+ (or (default-boundp hook) (set-default hook nil))
+ (let ((value (if local
+ (if (local-variable-p hook)
+ (symbol-value hook)
+ (unless (local-variable-if-set-p hook)
+ (make-local-variable hook))
+ (copy-sequence (default-value hook)))
+ (default-value hook))))
+ (if at
+ (when (setq at (member at value))
+ (setq value (delq function value))
+ (cond ((eq append 'replace)
+ (setcar at function))
+ (append
+ (push function (cdr at)))
+ (t
+ (push (car at) (cdr at))
+ (setcar at function))))
+ (setq value (delq function value)))
+ (unless (member function value)
+ (setq value (if append
+ (append value (list function))
+ (cons function value))))
+ (when (eq append 'replace)
+ (setq value (delq at value)))
+ (if local
+ (set hook value)
+ (set-default hook value))))
+
+;;; magit-section.el ends soon
+(provide 'magit-section)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-section.el ends here
--- /dev/null
+;;; magit-sequence.el --- history manipulation in Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Support for Git commands that replay commits and help the user make
+;; changes along the way. Supports `cherry-pick', `revert', `rebase',
+;; `rebase--interactive' and `am'.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+;;;; Faces
+
+(defface magit-sequence-pick
+ '((t :inherit default))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-stop
+ '((((class color) (background light)) :foreground "DarkOliveGreen4")
+ (((class color) (background dark)) :foreground "DarkSeaGreen2"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-part
+ '((((class color) (background light)) :foreground "Goldenrod4")
+ (((class color) (background dark)) :foreground "LightGoldenrod2"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-head
+ '((((class color) (background light)) :foreground "SkyBlue4")
+ (((class color) (background dark)) :foreground "LightSkyBlue1"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-drop
+ '((((class color) (background light)) :foreground "IndianRed")
+ (((class color) (background dark)) :foreground "IndianRed"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-done
+ '((t :inherit magit-hash))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-onto
+ '((t :inherit magit-sequence-done))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+;;; Common
+
+;;;###autoload
+(defun magit-sequencer-continue ()
+ "Resume the current cherry-pick or revert sequence."
+ (interactive)
+ (if (magit-sequencer-in-progress-p)
+ (if (magit-anything-unstaged-p t)
+ (user-error "Cannot continue due to unstaged changes")
+ (magit-run-git-sequencer
+ (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue"))
+ (user-error "No cherry-pick or revert in progress")))
+
+;;;###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")))
+
+;;;###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")))
+
+(defun magit-sequencer-in-progress-p ()
+ (or (magit-cherry-pick-in-progress-p)
+ (magit-revert-in-progress-p)))
+
+;;; Cherry-Pick
+
+;;;###autoload (autoload 'magit-cherry-pick-popup "magit-sequence" nil t)
+(magit-define-popup magit-cherry-pick-popup
+ "Popup console for cherry-pick commands."
+ 'magit-commands
+ :man-page "git-cherry-pick"
+ :switches '((?s "Add Signed-off-by lines" "--signoff")
+ (?e "Edit commit messages" "--edit")
+ (?x "Reference cherry in commit message" "-x")
+ (?F "Attempt fast-forward" "--ff")
+ (?m "Reply merge relative to parent" "--mainline="))
+ :options '((?s "Strategy" "--strategy="))
+ :actions '((?A "Cherry Pick" magit-cherry-pick)
+ (?a "Cherry Apply" magit-cherry-apply))
+ :sequence-actions '((?A "Continue" magit-sequencer-continue)
+ (?s "Skip" magit-sequencer-skip)
+ (?a "Abort" magit-sequencer-abort))
+ :sequence-predicate 'magit-sequencer-in-progress-p
+ :default-arguments '("--ff"))
+
+(defun magit-cherry-pick-read-args (prompt)
+ (list (or (nreverse (magit-region-values 'commit))
+ (magit-read-other-branch-or-commit prompt))
+ (magit-cherry-pick-arguments)))
+
+;;;###autoload
+(defun magit-cherry-pick (commit &optional args)
+ "Cherry-pick COMMIT.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then pick all of them,
+without prompting."
+ (interactive (magit-cherry-pick-read-args "Cherry-pick"))
+ (magit-assert-one-parent (car (if (listp commit)
+ commit
+ (split-string commit "\\.\\.")))
+ "cherry-pick")
+ (magit-run-git-sequencer "cherry-pick" args commit))
+
+;;;###autoload
+(defun magit-cherry-apply (commit &optional args)
+ "Apply the changes in COMMIT but do not commit them.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then apply all of them,
+without prompting."
+ (interactive (magit-cherry-pick-read-args "Apply changes from commit"))
+ (magit-assert-one-parent commit "cherry-pick")
+ (magit-run-git-sequencer "cherry-pick" "--no-commit"
+ (remove "--ff" args) commit))
+
+(defun magit-cherry-pick-in-progress-p ()
+ ;; .git/sequencer/todo does not exist when there is only one commit left.
+ (file-exists-p (magit-git-dir "CHERRY_PICK_HEAD")))
+
+;;; Revert
+
+;;;###autoload (autoload 'magit-revert-popup "magit-sequence" nil t)
+(magit-define-popup magit-revert-popup
+ "Popup console for revert commands."
+ 'magit-commands
+ :man-page "git-revert"
+ :switches '((?s "Add Signed-off-by lines" "--signoff"))
+ :options '((?s "Strategy" "--strategy=")
+ (?S "Sign using gpg" "--gpg-sign=" magit-read-gpg-secret-key))
+ :actions '((?V "Revert commit(s)" magit-revert)
+ (?v "Revert changes" magit-revert-no-commit))
+ :sequence-actions '((?V "Continue" magit-sequencer-continue)
+ (?s "Skip" magit-sequencer-skip)
+ (?a "Abort" magit-sequencer-abort))
+ :sequence-predicate 'magit-sequencer-in-progress-p)
+
+(defun magit-revert-read-args (prompt)
+ (list (or (magit-region-values 'commit)
+ (magit-read-branch-or-commit prompt))
+ (magit-revert-arguments)))
+
+;;;###autoload
+(defun magit-revert (commit &optional args)
+ "Revert COMMIT by creating a new commit.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting."
+ (interactive (magit-revert-read-args "Revert commit"))
+ (magit-assert-one-parent commit "revert")
+ (magit-run-git-sequencer "revert" args commit))
+
+;;;###autoload
+(defun magit-revert-no-commit (commit &optional args)
+ "Revert COMMIT by applying it in reverse to the worktree.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting."
+ (interactive (magit-revert-read-args "Revert changes"))
+ (magit-assert-one-parent commit "revert")
+ (magit-run-git-sequencer "revert" "--no-commit" args commit))
+
+(defun magit-revert-in-progress-p ()
+ ;; .git/sequencer/todo does not exist when there is only one commit left.
+ (file-exists-p (magit-git-dir "REVERT_HEAD")))
+
+;;; Patch
+
+;;;###autoload (autoload 'magit-am-popup "magit-sequence" nil t)
+(magit-define-popup magit-am-popup
+ "Popup console for mailbox commands."
+ 'magit-commands
+ :man-page "git-am"
+ :switches '((?3 "Fall back on 3way merge" "--3way")
+ (?s "Add Signed-off-by lines" "--signoff")
+ (?c "Remove text before scissors line" "--scissors")
+ (?k "Inhibit removal of email cruft" "--keep")
+ (?b "Limit removal of email cruft" "--keep-non-patch")
+ (?d "Use author date as committer date"
+ "--committer-date-is-author-date")
+ (?D "Use committer date as author date" "--ignore-date"))
+ :options '((?p "Remove leading slashes from paths" "-p"
+ magit-popup-read-number))
+ :actions '((?w "Apply patches" magit-am-apply-patches)
+ (?m "Apply maildir" magit-am-apply-maildir))
+ :default-arguments '("--3way")
+ :default-actions 'magit-am-apply-patches
+ :sequence-actions '((?w "Continue" magit-am-continue)
+ (?s "Skip" magit-am-skip)
+ (?a "Abort" magit-am-abort))
+ :sequence-predicate 'magit-am-in-progress-p)
+
+;;;###autoload
+(defun magit-am-apply-patches (&optional files args)
+ "Apply the patches FILES."
+ (interactive (list (or (magit-region-values 'file)
+ (list (let ((default (magit-file-at-point)))
+ (read-file-name
+ (if default
+ (format "Apply patch (%s): " default)
+ "Apply patch: ")
+ nil default))))
+ (magit-am-arguments)))
+ (magit-run-git-sequencer "am" args "--" (mapcar 'expand-file-name files)))
+
+;;;###autoload
+(defun magit-am-apply-maildir (&optional maildir args)
+ "Apply the patches from MAILDIR."
+ (interactive (list (read-file-name "Apply mbox or Maildir: ")
+ (magit-am-arguments)))
+ (magit-run-git-sequencer "am" args (expand-file-name maildir)))
+
+;;;###autoload
+(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")))
+
+;;;###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")))
+
+;;;###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")))
+
+(defun magit-am-in-progress-p ()
+ (file-exists-p (magit-git-dir "rebase-apply/applying")))
+
+;;; Rebase
+
+;;;###autoload (autoload 'magit-rebase-popup "magit-sequence" nil t)
+(magit-define-popup magit-rebase-popup
+ "Key menu for rebasing."
+ 'magit-commands
+ :man-page "git-rebase"
+ :switches '((?k "Keep empty commits" "--keep-empty")
+ (?p "Preserve merges" "--preserve-merges")
+ (?c "Lie about author date" "--committer-date-is-author-date")
+ (?a "Autosquash" "--autosquash")
+ (?A "Autostash" "--autostash")
+ (?i "Interactive" "--interactive"))
+ :actions '((lambda ()
+ (concat (propertize "Rebase " 'face 'magit-popup-heading)
+ (propertize (or (magit-get-current-branch) "HEAD")
+ 'face 'magit-branch-local)
+ (propertize " onto" 'face 'magit-popup-heading)))
+ (?p (lambda ()
+ (--when-let (magit-get-push-branch) (concat it "\n")))
+ magit-rebase-onto-pushremote)
+ (?u (lambda ()
+ (--when-let (magit-get-upstream-branch) (concat it "\n")))
+ magit-rebase-onto-upstream)
+ (?e "elsewhere" magit-rebase)
+ "Rebase"
+ (?i "interactively" magit-rebase-interactive)
+ (?m "to edit a commit" magit-rebase-edit-commit)
+ (?s "subset" magit-rebase-subset)
+ (?w "to reword a commit" magit-rebase-reword-commit) nil
+ (?f "to autosquash" magit-rebase-autosquash))
+ :sequence-actions '((?r "Continue" magit-rebase-continue)
+ (?s "Skip" magit-rebase-skip)
+ (?e "Edit" magit-rebase-edit)
+ (?a "Abort" magit-rebase-abort))
+ :sequence-predicate 'magit-rebase-in-progress-p
+ :max-action-columns 2)
+
+(defun magit-git-rebase (target args)
+ (magit-run-git-sequencer "rebase" target args))
+
+;;;###autoload
+(defun magit-rebase-onto-pushremote (args)
+ "Rebase the current branch onto `branch.<name>.pushRemote'.
+If that variable is unset, then rebase onto `remote.pushDefault'."
+ (interactive (list (magit-rebase-arguments)))
+ (--if-let (magit-get-current-branch)
+ (-if-let (remote (magit-get-push-remote it))
+ (if (member remote (magit-list-remotes))
+ (magit-git-rebase (concat remote "/" it) args)
+ (user-error "Remote `%s' doesn't exist" remote))
+ (user-error "No push-remote is configured for %s" it))
+ (user-error "No branch is checked out")))
+
+;;;###autoload
+(defun magit-rebase-onto-upstream (args)
+ "Rebase the current branch onto its upstream branch."
+ (interactive (list (magit-rebase-arguments)))
+ (--if-let (magit-get-current-branch)
+ (-if-let (target (magit-get-upstream-branch it))
+ (magit-git-rebase target args)
+ (user-error "No upstream is configured for %s" it))
+ (user-error "No branch is checked out")))
+
+;;;###autoload
+(defun magit-rebase (target args)
+ "Rebase the current branch onto a branch read in the minibuffer.
+All commits that are reachable from head but not from the
+selected branch TARGET are being rebased."
+ (interactive (list (magit-read-other-branch-or-commit "Rebase onto")
+ (magit-rebase-arguments)))
+ (message "Rebasing...")
+ (magit-git-rebase target args)
+ (message "Rebasing...done"))
+
+;;;###autoload
+(defun magit-rebase-subset (newbase start args)
+ "Rebase a subset of the current branches history onto a new base.
+Rebase commits from START to `HEAD' onto NEWBASE.
+START has to be selected from a list of recent commits."
+ (interactive (list (magit-read-other-branch-or-commit
+ "Rebase subset onto" nil
+ (magit-get-upstream-branch))
+ nil
+ (magit-rebase-arguments)))
+ (if start
+ (progn (message "Rebasing...")
+ (magit-run-git-sequencer "rebase" "--onto" newbase start args)
+ (message "Rebasing...done"))
+ (magit-log-select
+ `(lambda (commit)
+ (magit-rebase-subset ,newbase (concat commit "^") (list ,@args)))
+ (concat "Type %p on a commit to rebase it "
+ "and commits above it onto " newbase ","))))
+
+(defun magit-rebase-interactive-1 (commit args message &optional editor)
+ (declare (indent 2))
+ (when commit
+ (if (eq commit :merge-base)
+ (setq commit (--if-let (magit-get-upstream-branch)
+ (magit-git-string "merge-base" it "HEAD")
+ nil))
+ (unless (magit-rev-ancestor-p commit "HEAD")
+ (user-error "%s isn't an ancestor of HEAD" commit))
+ (if (magit-commit-parents commit)
+ (setq commit (concat commit "^"))
+ (setq args (cons "--root" args)))))
+ (when (and commit
+ (magit-git-lines "rev-list" "--merges" (concat commit "..HEAD")))
+ (magit-read-char-case "Proceed despite merge in rebase range? " nil
+ (?c "[c]ontinue")
+ (?s "[s]elect other" (setq commit nil))
+ (?a "[a]bort" (user-error "Quit"))))
+ (if commit
+ (let ((process-environment process-environment))
+ (when editor
+ (push (concat "GIT_SEQUENCE_EDITOR=" editor) process-environment))
+ (magit-run-git-sequencer "rebase" "-i" args
+ (unless (member "--root" args) commit)))
+ (magit-log-select
+ `(lambda (commit)
+ (magit-rebase-interactive-1 commit (list ,@args) ,message ,editor))
+ message)))
+
+;;;###autoload
+(defun magit-rebase-interactive (commit args)
+ "Start an interactive rebase sequence."
+ (interactive (list (magit-commit-at-point)
+ (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 commit args
+ "Type %p on a commit to rebase it and all commits above it,"))
+
+;;;###autoload
+(defun magit-rebase-autosquash (args)
+ "Combine squash and fixup commits with their intended targets."
+ (interactive (list (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 :merge-base (cons "--autosquash" args)
+ "Type %p on a commit to squash into it and then rebase as necessary,"
+ "true"))
+
+;;;###autoload
+(defun magit-rebase-edit-commit (commit args)
+ "Edit a single older commit using rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 commit args
+ "Type %p on a commit to edit it,"
+ "perl -i -p -e '++$x if not $x and s/^pick/edit/'"))
+
+;;;###autoload
+(defun magit-rebase-reword-commit (commit args)
+ "Reword a single older commit using rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 commit args
+ "Type %p on a commit to reword its message,"
+ "perl -i -p -e '++$x if not $x and s/^pick/reword/'"))
+
+;;;###autoload
+(defun magit-rebase-continue (&optional noedit)
+ "Restart the current rebasing operation.
+In some cases this pops up a commit message buffer for you do
+edit. With a prefix argument the old message is reused as-is."
+ (interactive "P")
+ (if (magit-rebase-in-progress-p)
+ (if (magit-anything-unstaged-p t)
+ (user-error "Cannot continue rebase with unstaged changes")
+ (if noedit
+ (let ((process-environment process-environment))
+ (push "GIT_EDITOR=true" process-environment)
+ (magit-run-git-async "rebase" "--continue")
+ (set-process-sentinel magit-this-process
+ #'magit-sequencer-process-sentinel)
+ magit-this-process)
+ (magit-run-git-sequencer "rebase" "--continue")))
+ (user-error "No rebase in progress")))
+
+;;;###autoload
+(defun magit-rebase-skip ()
+ "Skip the current commit and restart the current rebase operation."
+ (interactive)
+ (if (magit-rebase-in-progress-p)
+ (magit-run-git-sequencer "rebase" "--skip")
+ (user-error "No rebase in progress")))
+
+;;;###autoload
+(defun magit-rebase-edit ()
+ "Edit the todo list of the current rebase operation."
+ (interactive)
+ (if (magit-rebase-in-progress-p)
+ (magit-run-git-sequencer "rebase" "--edit-todo")
+ (user-error "No rebase in progress")))
+
+;;;###autoload
+(defun magit-rebase-abort ()
+ "Abort the current rebase operation, restoring the original branch."
+ (interactive)
+ (if (magit-rebase-in-progress-p)
+ (when (magit-confirm 'abort-rebase "Abort this rebase")
+ (magit-run-git "rebase" "--abort"))
+ (user-error "No rebase in progress")))
+
+(defun magit-rebase-in-progress-p ()
+ "Return t if a rebase is in progress."
+ (or (file-exists-p (magit-git-dir "rebase-merge"))
+ (file-exists-p (magit-git-dir "rebase-apply/onto"))))
+
+;;; Sections
+
+(defun magit-insert-sequencer-sequence ()
+ "Insert section for the on-going cherry-pick or revert sequence.
+If no such sequence is in progress, do nothing."
+ (let ((picking (magit-cherry-pick-in-progress-p)))
+ (when (or picking (magit-revert-in-progress-p))
+ (magit-insert-section (sequence)
+ (magit-insert-heading (if picking "Cherry Picking" "Reverting"))
+ (-when-let (lines (cdr (magit-file-lines (magit-git-dir "sequencer/todo"))))
+ (dolist (line (nreverse lines))
+ (when (string-match "^\\(pick\\|revert\\) \\([^ ]+\\) \\(.*\\)$" line)
+ (magit-bind-match-strings (cmd hash msg) line
+ (magit-insert-section (commit hash)
+ (insert (propertize cmd 'face 'magit-sequence-pick)
+ " " (propertize hash 'face 'magit-hash)
+ " " msg "\n"))))))
+ (magit-sequence-insert-sequence
+ (magit-file-line (magit-git-dir (if picking
+ "CHERRY_PICK_HEAD"
+ "REVERT_HEAD")))
+ (magit-file-line (magit-git-dir "sequencer/head")))
+ (insert "\n")))))
+
+(defun magit-insert-am-sequence ()
+ "Insert section for the on-going patch applying sequence.
+If no such sequence is in progress, do nothing."
+ (when (magit-am-in-progress-p)
+ (magit-insert-section (rebase-sequence)
+ (magit-insert-heading "Applying patches")
+ (let ((patches (nreverse (magit-rebase-patches)))
+ patch commit)
+ (while patches
+ (setq patch (pop patches)
+ commit (magit-rev-verify-commit
+ (cadr (split-string (magit-file-line patch)))))
+ (cond ((and commit patches)
+ (magit-sequence-insert-commit
+ "pick" commit 'magit-sequence-pick))
+ (patches
+ (magit-sequence-insert-am-patch
+ "pick" patch 'magit-sequence-pick))
+ (commit
+ (magit-sequence-insert-sequence commit "ORIG_HEAD"))
+ (t
+ (magit-sequence-insert-am-patch
+ "stop" patch 'magit-sequence-stop)
+ (magit-sequence-insert-sequence nil "ORIG_HEAD")))))
+ (insert ?\n))))
+
+(defun magit-sequence-insert-am-patch (type patch face)
+ (magit-insert-section (file patch)
+ (insert (propertize type 'face face)
+ ?\s (propertize (file-name-nondirectory patch) 'face 'magit-hash)
+ ?\n)))
+
+(defun magit-insert-rebase-sequence ()
+ "Insert section for the on-going rebase sequence.
+If no such sequence is in progress, do nothing."
+ (when (magit-rebase-in-progress-p)
+ (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge")))
+ (dir (if interactive "rebase-merge/" "rebase-apply/"))
+ (name (-> (concat dir "head-name") magit-git-dir magit-file-line))
+ (onto (-> (concat dir "onto") magit-git-dir magit-file-line))
+ (onto (or (magit-rev-name onto name)
+ (magit-rev-name onto "refs/heads/*") onto))
+ (name (or (magit-rev-name name "refs/heads/*") name)))
+ (magit-insert-section (rebase-sequence)
+ (magit-insert-heading (format "Rebasing %s onto %s" name onto))
+ (if interactive
+ (magit-rebase-insert-merge-sequence)
+ (magit-rebase-insert-apply-sequence))
+ (magit-sequence-insert-sequence
+ (magit-file-line
+ (magit-git-dir
+ (concat dir (if interactive "stopped-sha" "original-commit"))))
+ onto (--map (cadr (split-string it))
+ (magit-file-lines (magit-git-dir "rebase-merge/done"))))
+ (insert ?\n)))))
+
+(defun magit-rebase-insert-merge-sequence ()
+ (dolist (line (nreverse
+ (magit-file-lines
+ (magit-git-dir "rebase-merge/git-rebase-todo"))))
+ (when (string-match (format "^\\([^%c ]+\\) \\([^ ]+\\) .*$"
+ (string-to-char
+ (or (magit-get "core.commentChar") "#")))
+ line)
+ (magit-bind-match-strings (action hash) line
+ (magit-sequence-insert-commit action hash 'magit-sequence-pick)))))
+
+(defun magit-rebase-insert-apply-sequence ()
+ (dolist (patch (nreverse (cdr (magit-rebase-patches))))
+ (magit-sequence-insert-commit
+ "pick" (cadr (split-string (magit-file-line patch))) 'magit-sequence-pick)))
+
+(defun magit-rebase-patches ()
+ (directory-files (magit-git-dir "rebase-apply") t "^[0-9]\\{4\\}$"))
+
+(defun magit-sequence-insert-sequence (stop onto &optional orig)
+ (let ((head (magit-rev-parse "HEAD")) done)
+ (setq onto (if onto (magit-rev-parse onto) head))
+ (setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD")))
+ (when (and stop (not (member stop done)))
+ (let ((id (magit-patch-id stop)))
+ (--if-let (--first (equal (magit-patch-id it) id) done)
+ (setq stop it)
+ (cond
+ ((--first (magit-rev-equal it 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...
+ ((magit-anything-unmerged-p)
+ ;; ...and time travel isn't for the faint of heart.
+ (magit-sequence-insert-commit "join" stop 'magit-sequence-part))
+ ((magit-anything-modified-p t)
+ ;; ...and the dust hasn't settled yet...
+ (magit-sequence-insert-commit
+ (let ((staged (magit-commit-tree "oO" nil "HEAD"))
+ (unstaged (magit-commit-worktree "oO" "--reset")))
+ (cond
+ ;; ...but we could end up at the same tree just by committing.
+ ((or (magit-rev-equal staged stop)
+ (magit-rev-equal unstaged stop)) "goal")
+ ;; ...but the changes are still there, untainted.
+ ((or (equal (magit-patch-id staged) id)
+ (equal (magit-patch-id unstaged) id)) "same")
+ ;; ...and some changes are gone and/or others were added.
+ (t "work")))
+ stop 'magit-sequence-part))
+ ;; The commit is definitely gone...
+ ((--first (magit-rev-equal it stop) done)
+ ;; ...but all of its changes are still in effect.
+ (magit-sequence-insert-commit "poof" stop 'magit-sequence-drop))
+ (t
+ ;; ...and some changes are gone and/or other changes were added.
+ (magit-sequence-insert-commit "gone" stop 'magit-sequence-drop)))
+ (setq stop nil))))
+ (dolist (rev done)
+ (apply 'magit-sequence-insert-commit
+ (cond ((equal rev stop)
+ ;; ...but its reincarnation lives on.
+ ;; Or it didn't die in the first place.
+ (list (if (and (equal rev head)
+ (equal (magit-patch-id (concat stop "^"))
+ (magit-patch-id (car (last orig 2)))))
+ "stop" ; We haven't done anything yet.
+ "same") ; There are new commits.
+ rev (if (equal rev head)
+ 'magit-sequence-head
+ 'magit-sequence-stop)))
+ ((equal rev head)
+ (list "done" rev 'magit-sequence-head))
+ (t
+ (list "done" rev 'magit-sequence-done)))))
+ (magit-sequence-insert-commit "onto" onto
+ (if (equal onto head)
+ 'magit-sequence-head
+ 'magit-sequence-onto))))
+
+(defun magit-sequence-insert-commit (type hash face)
+ (magit-insert-section (commit hash)
+ (insert (propertize type 'face face) ?\s
+ (magit-format-rev-summary hash) ?\n)))
+
+;;; magit-sequence.el ends soon
+(provide 'magit-sequence)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-sequence.el ends here
--- /dev/null
+;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Support for Git stashes.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-stash-popup "magit-stash" nil t)
+(magit-define-popup magit-stash-popup
+ "Popup console for stash commands."
+ 'magit-commands
+ :man-page "git-stash"
+ :switches '((?u "Also save untracked files" "--include-untracked")
+ (?a "Also save untracked and ignored files" "--all"))
+ :actions '((?z "Save" magit-stash)
+ (?Z "Snapshot" magit-snapshot)
+ (?p "Pop" magit-stash-pop)
+ (?i "Save index" magit-stash-index)
+ (?I "Snapshot index" magit-snapshot-index)
+ (?a "Apply" magit-stash-apply)
+ (?w "Save worktree" magit-stash-worktree)
+ (?W "Snapshot worktree" magit-snapshot-worktree)
+ (?l "List" magit-stash-list)
+ (?x "Save keeping index" magit-stash-keep-index)
+ (?r "Snapshot to wipref" magit-wip-commit)
+ (?v "Show" magit-stash-show)
+ (?b "Branch" magit-stash-branch)
+ (?k "Drop" magit-stash-drop) nil
+ (?f "Format patch" magit-stash-format-patch))
+ :default-action 'magit-stash
+ :max-action-columns 3)
+
+;;;###autoload
+(defun magit-stash (message &optional include-untracked)
+ "Create a stash of the index and working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-stash-read-args))
+ (magit-stash-save message t t include-untracked t))
+
+;;;###autoload
+(defun magit-stash-index (message)
+ "Create a stash of the index only.
+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)))
+ (magit-stash-save message t nil nil t 'worktree))
+
+;;;###autoload
+(defun magit-stash-worktree (message &optional include-untracked)
+ "Create a stash of unstaged changes in the working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-stash-read-args))
+ (magit-stash-save message nil t include-untracked t 'index))
+
+;;;###autoload
+(defun magit-stash-keep-index (message &optional include-untracked)
+ "Create a stash of the index and working tree, keeping index intact.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-stash-read-args))
+ (magit-stash-save message t t include-untracked t 'index))
+
+(defun magit-stash-read-args ()
+ (list (magit-stash-read-message)
+ (magit-stash-read-untracked)))
+
+(defun magit-stash-read-untracked ()
+ (let ((prefix (prefix-numeric-value current-prefix-arg))
+ (args (magit-stash-arguments)))
+ (cond ((or (= prefix 16) (member "--all" args)) 'all)
+ ((or (= prefix 4) (member "--include-untracked" args)) t))))
+
+(defun magit-stash-read-message ()
+ (let* ((default (format "On %s: "
+ (or (magit-get-current-branch) "(no branch)")))
+ (input (magit-read-string "Stash message" default)))
+ (if (equal input default)
+ (concat default (magit-rev-format "%h %s"))
+ input)))
+
+;;;###autoload
+(defun magit-snapshot (&optional include-untracked)
+ "Create a snapshot of the index and working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-snapshot-read-args))
+ (magit-snapshot-save t t include-untracked t))
+
+;;;###autoload
+(defun magit-snapshot-index ()
+ "Create a snapshot of the index only.
+Unstaged and untracked changes are not stashed."
+ (interactive)
+ (magit-snapshot-save t nil nil t))
+
+;;;###autoload
+(defun magit-snapshot-worktree (&optional include-untracked)
+ "Create a snapshot of unstaged changes in the working tree.
+Untracked files are included according to popup arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-snapshot-read-args))
+ (magit-snapshot-save nil t include-untracked t))
+
+(defun magit-snapshot-read-args ()
+ (list (magit-stash-read-untracked)))
+
+(defun magit-snapshot-save (index worktree untracked &optional refresh)
+ (magit-stash-save (concat "WIP on " (magit-stash-summary))
+ index worktree untracked refresh t))
+
+;;;###autoload
+(defun magit-stash-apply (stash)
+ "Apply a stash to the working tree.
+Try to preserve the stash index. If that fails because there
+are staged changes, apply without preserving the stash index."
+ (interactive (list (magit-read-stash "Apply stash" t)))
+ (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
+ (magit-refresh)
+ (magit-run-git "stash" "apply" stash)))
+
+(defun magit-stash-pop (stash)
+ "Apply a stash to the working tree and remove it from stash list.
+Try to preserve the stash index. If that fails because there
+are staged changes, apply without preserving the stash index
+and forgo removing the stash."
+ (interactive (list (magit-read-stash "Apply pop" t)))
+ (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
+ (magit-stash-drop stash)
+ (magit-run-git "stash" "apply" stash)))
+
+;;;###autoload
+(defun magit-stash-drop (stash)
+ "Remove a stash from the stash list.
+When the region is active offer to drop all contained stashes."
+ (interactive (list (--if-let (magit-region-values 'stash)
+ (magit-confirm t nil "Drop %i stashes" it)
+ (magit-read-stash "Drop stash"))))
+ (dolist (stash (if (listp stash)
+ (nreverse (prog1 stash (setq stash (car stash))))
+ (list stash)))
+ (message "Deleted refs/%s (was %s)" stash
+ (magit-rev-parse "--short" stash))
+ (magit-call-git "rev-parse" stash)
+ (magit-call-git "reflog" "delete" "--updateref" "--rewrite" stash))
+ (-when-let (ref (and (string-match "\\(.+\\)@{[0-9]+}$" stash)
+ (match-string 1 stash)))
+ (unless (string-match "^refs/" ref)
+ (setq ref (concat "refs/" ref)))
+ (unless (magit-rev-verify (concat ref "@{0}"))
+ (magit-run-git "update-ref" "-d" ref)))
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-stash-clear (ref)
+ "Remove all stashes saved in REF's reflog by deleting REF."
+ (interactive
+ (let ((ref (or (magit-section-when 'stashes) "refs/stash")))
+ (if (magit-confirm t (format "Drop all stashes in %s" ref))
+ (list ref)
+ (user-error "Abort"))))
+ (magit-run-git "update-ref" "-d" ref))
+
+;;;###autoload
+(defun magit-stash-branch (stash branch)
+ "Create and checkout a new BRANCH from STASH."
+ (interactive (list (magit-read-stash "Branch stash" t)
+ (magit-read-string-ns "Branch name")))
+ (magit-run-git "stash" "branch" branch stash))
+
+;;;###autoload
+(defun magit-stash-format-patch (stash)
+ "Create a patch from STASH"
+ (interactive (list (magit-read-stash "Create patch from stash" t)))
+ (with-temp-file (magit-rev-format "0001-%f.patch" stash)
+ (magit-git-insert "stash" "show" "-p" stash))
+ (magit-refresh))
+
+;;; Plumbing
+
+(defun magit-stash-save (message index worktree untracked
+ &optional refresh keep noerror ref)
+ (if (or (and index (magit-staged-files t))
+ (and worktree (magit-modified-files t))
+ (and untracked (magit-untracked-files (eq untracked 'all))))
+ (magit-with-toplevel
+ (magit-stash-store message (or ref "refs/stash")
+ (magit-stash-create message index worktree untracked))
+ (if (eq keep 'worktree)
+ (with-temp-buffer
+ (magit-git-insert "diff" "--cached")
+ (magit-run-git-with-input
+ "apply" "--reverse" "--cached" "--ignore-space-change" "-")
+ (magit-run-git-with-input
+ "apply" "--reverse" "--ignore-space-change" "-"))
+ (unless (eq keep t)
+ (if (eq keep 'index)
+ (magit-call-git "checkout" "--" ".")
+ (magit-call-git "reset" "--hard" "HEAD"))
+ (when untracked
+ (magit-call-git "clean" "-f" (and (eq untracked 'all) "-x")))))
+ (when refresh
+ (magit-refresh)))
+ (unless noerror
+ (user-error "No %s changes to save" (cond ((not index) "unstaged")
+ ((not worktree) "staged")
+ (t "local"))))))
+
+(defun magit-stash-store (message ref commit)
+ (magit-update-ref ref message commit t))
+
+(defun magit-stash-create (message index worktree untracked)
+ (unless (magit-rev-parse "--verify" "HEAD")
+ (error "You do not have the initial commit yet"))
+ (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false")
+ magit-git-global-arguments))
+ (default-directory (magit-toplevel))
+ (summary (magit-stash-summary))
+ (head "HEAD"))
+ (when (and worktree (not index))
+ (setq head (magit-commit-tree "pre-stash index" nil "HEAD")))
+ (or (setq index (magit-commit-tree (concat "index on " summary) nil head))
+ (error "Cannot save the current index state"))
+ (and untracked
+ (setq untracked (magit-untracked-files (eq untracked 'all)))
+ (setq untracked (magit-with-temp-index nil nil
+ (or (and (magit-update-files untracked)
+ (magit-commit-tree
+ (concat "untracked files on " summary)))
+ (error "Cannot save the untracked files")))))
+ (magit-with-temp-index index "-m"
+ (when worktree
+ (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head))
+ (error "Cannot save the current worktree state")))
+ (or (magit-commit-tree message nil head index untracked)
+ (error "Cannot save the current worktree state")))))
+
+(defun magit-stash-summary ()
+ (concat (or (magit-get-current-branch) "(no branch)")
+ ": " (magit-rev-format "%h %s")))
+
+;;; Sections
+
+(defvar magit-stashes-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-delete-thing] 'magit-stash-clear)
+ map)
+ "Keymap for `stashes' section.")
+
+(defvar magit-stash-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-stash-show)
+ (define-key map [remap magit-delete-thing] 'magit-stash-drop)
+ (define-key map "a" 'magit-stash-apply)
+ (define-key map "A" 'magit-stash-pop)
+ map)
+ "Keymap for `stash' sections.")
+
+(magit-define-section-jumper magit-jump-to-stashes
+ "Stashes" stashes "refs/stash")
+
+(cl-defun magit-insert-stashes (&optional (ref "refs/stash")
+ (heading "Stashes:"))
+ "Insert `stashes' section showing reflog for \"refs/stash\".
+If optional REF is non-nil show reflog for that instead.
+If optional HEADING is non-nil use that as section heading
+instead of \"Stashes:\"."
+ (when (magit-rev-verify ref)
+ (magit-insert-section (stashes ref (not magit-status-expand-stashes))
+ (magit-insert-heading heading)
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
+ "reflog" "--format=%gd %at %gs" ref))))
+
+;;; List Stashes
+
+;;;###autoload
+(defun magit-stash-list ()
+ "List all stashes in a buffer."
+ (interactive)
+ (magit-mode-setup #'magit-stashes-mode "refs/stash"))
+
+(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes"
+ "Mode for looking at lists of stashes."
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer))
+
+(cl-defun magit-stashes-refresh-buffer (ref)
+ (magit-insert-section (stashesbuf)
+ (magit-insert-heading (if (equal ref "refs/stash")
+ "Stashes:"
+ (format "Stashes [%s]:" ref)))
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
+ "reflog" "--format=%gd %at %gs" ref)))
+
+;;; Show Stash
+
+(defcustom magit-stash-sections-hook
+ '(magit-insert-stash-worktree
+ magit-insert-stash-index
+ magit-insert-stash-untracked)
+ "Hook run to insert sections into stash buffers."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :type 'hook)
+
+;;;###autoload
+(defun magit-stash-show (stash &optional args files)
+ "Show all diffs of a stash in a buffer."
+ (interactive (cons (or (and (not current-prefix-arg)
+ (magit-stash-at-point))
+ (magit-read-stash "Show stash"))
+ (-let [(args files) (magit-diff-arguments)]
+ (list (delete "--stat" args) files))))
+ (magit-mode-setup #'magit-stash-mode stash nil args files))
+
+(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash"
+ "Mode for looking at individual stashes."
+ :group 'magit-diff
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-stash-refresh-buffer (stash _const _args _files)
+ (setq header-line-format
+ (concat
+ "\s" (propertize (capitalize stash) 'face 'magit-section-heading)
+ "\s" (magit-rev-format "%s" stash)))
+ (magit-insert-section (stash)
+ (run-hooks 'magit-stash-sections-hook)))
+
+(defun magit-stash-insert-section (commit range message &optional files)
+ (magit-insert-section (commit commit)
+ (magit-insert-heading message)
+ (magit-git-wash #'magit-diff-wash-diffs
+ "diff" range "-p" "--no-prefix"
+ (nth 2 magit-refresh-args)
+ "--" (or files (nth 3 magit-refresh-args)))))
+
+(defun magit-insert-stash-index ()
+ "Insert section showing staged changes of the stash."
+ (let ((stash (car magit-refresh-args)))
+ (magit-stash-insert-section (format "%s^2" stash)
+ (format "%s^..%s^2" stash stash)
+ "Staged")))
+
+(defun magit-insert-stash-worktree ()
+ "Insert section showing unstaged changes of the stash."
+ (let ((stash (car magit-refresh-args)))
+ (magit-stash-insert-section stash
+ (format "%s^2..%s" stash stash)
+ "Unstaged")))
+
+(defun magit-insert-stash-untracked ()
+ "Insert section showing the untracked files commit of the stash."
+ (let ((stash (car magit-refresh-args))
+ (rev (concat (car magit-refresh-args) "^3")))
+ (when (magit-rev-verify rev)
+ (magit-stash-insert-section (format "%s^3" stash)
+ (format "%s^..%s^3" stash stash)
+ "Untracked files"
+ (magit-git-items "ls-tree" "-z" "--name-only"
+ "-r" "--full-tree" rev)))))
+
+;;; magit-stash.el ends soon
+(provide 'magit-stash)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-stash.el ends here
--- /dev/null
+;;; magit-submodule.el --- submodule support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-submodule-list-columns
+ '(("Path" 25 magit-modulelist-column-path nil)
+ ("Version" 25 magit-repolist-column-version nil)
+ ("Branch" 20 magit-repolist-column-branch nil)
+ ("L<U" 3 magit-repolist-column-unpulled-from-upstream (:right-align t))
+ ("L>U" 3 magit-repolist-column-unpushed-to-upstream (:right-align t))
+ ("L<P" 3 magit-repolist-column-unpulled-from-pushremote (:right-align t))
+ ("L>P" 3 magit-repolist-column-unpushed-to-pushremote (:right-align t)))
+ "List of columns displayed by `magit-list-submodules'.
+
+Each element has the form (HEADER WIDTH FORMAT PROPS).
+
+HEADER is the string displayed in the header. WIDTH is the width
+of the column. FORMAT is a function that is called with one
+argument, the repository identification (usually its basename),
+and with `default-directory' bound to the toplevel of its working
+tree. It has to return a string to be inserted or nil. PROPS is
+an alist that supports the keys `:right-align' and `:pad-right'."
+ :package-version '(magit . "2.8.0")
+ :group 'magit-commands
+ :type `(repeat (list :tag "Column"
+ (string :tag "Header Label")
+ (integer :tag "Column Width")
+ (function :tag "Inserter Function")
+ (repeat :tag "Properties"
+ (list (choice :tag "Property"
+ (const :right-align)
+ (const :pad-right)
+ (symbol))
+ (sexp :tag "Value"))))))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-submodule-popup "magit-submodule" nil t)
+(magit-define-popup magit-submodule-popup
+ "Popup console for submodule commands."
+ 'magit-commands nil nil
+ :man-page "git-submodule"
+ :actions '((?a "Add" magit-submodule-add)
+ (?b "Setup" magit-submodule-setup)
+ (?i "Init" magit-submodule-init)
+ (?u "Update" magit-submodule-update)
+ (?s "Sync" magit-submodule-sync)
+ (?f "Fetch" magit-submodule-fetch)
+ (?d "Deinit" magit-submodule-deinit)))
+
+;;;###autoload
+(defun magit-submodule-add (url &optional path name)
+ "Add the repository at URL as a submodule.
+
+Optional PATH is the path to the submodule relative to the root
+of the superproject. If it is nil, then the path is determined
+based on the URL.
+
+Optional NAME is the name of the submodule. If it is nil, then
+PATH also becomes the name."
+ (interactive
+ (magit-with-toplevel
+ (let* ((url (magit-read-string-ns "Add submodule (remote url)"))
+ (path (let ((read-file-name-function #'read-file-name-default))
+ (directory-file-name
+ (file-relative-name
+ (read-directory-name
+ "Add submodules at path: " nil nil nil
+ (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
+ (match-string 1 url))))))))
+ (list url
+ (directory-file-name path)
+ (magit-submodule-read-name path)))))
+ (magit-run-git "submodule" "add" (and name (list "--name" name)) url path))
+
+;;;###autoload
+(defun magit-submodule-read-name (path)
+ (setq path (directory-file-name (file-relative-name path)))
+ (push (file-name-nondirectory path) minibuffer-history)
+ (magit-read-string-ns
+ "Submodule name" nil (cons 'minibuffer-history 2)
+ (or (--keep (-let [(var val) (split-string it "=")]
+ (and (equal val path)
+ (cadr (split-string var "\\."))))
+ (magit-git-lines "config" "--list" "-f" ".gitmodules"))
+ path)))
+
+;;;###autoload
+(defun magit-submodule-setup ()
+ "Clone and register missing submodules and checkout appropriate commits."
+ (interactive)
+ (magit-with-toplevel
+ (--if-let (--filter (not (file-exists-p (expand-file-name ".git" it)))
+ (magit-get-submodules))
+ (magit-run-git-async "submodule" "update" "--init" "--" it)
+ (message "All submodules already setup"))))
+
+;;;###autoload
+(defun magit-submodule-init ()
+ "Register submodules listed in \".gitmodules\" into \".git/config\"."
+ (interactive)
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "init")))
+
+;;;###autoload
+(defun magit-submodule-update (&optional init)
+ "Clone missing submodules and checkout appropriate commits.
+With a prefix argument also register submodules in \".git/config\"."
+ (interactive "P")
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "update" (and init "--init"))))
+
+;;;###autoload
+(defun magit-submodule-sync ()
+ "Update each submodule's remote URL according to \".gitmodules\"."
+ (interactive)
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "sync")))
+
+;;;###autoload
+(defun magit-submodule-fetch (&optional all)
+ "Fetch all submodules.
+With a prefix argument fetch all remotes."
+ (interactive "P")
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "foreach"
+ (format "git fetch %s || true" (if all "--all" "")))))
+
+;;;###autoload
+(defun magit-submodule-deinit (path)
+ "Unregister the submodule at PATH."
+ (interactive
+ (list (magit-completing-read "Deinit module" (magit-get-submodules)
+ nil t nil nil (magit-section-when module))))
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "deinit" path)))
+
+;;; Sections
+
+;;;###autoload
+(defun magit-insert-submodules ()
+ "Insert sections for all modules.
+For each section insert the path and the output of `git describe --tags'."
+ (-when-let (modules (magit-get-submodules))
+ (magit-insert-section (submodules nil t)
+ (magit-insert-heading "Modules:")
+ (magit-with-toplevel
+ (let ((col-format (format "%%-%is " (min 25 (/ (window-width) 3)))))
+ (dolist (module modules)
+ (let ((default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (magit-insert-section (submodule module t)
+ (insert (propertize (format col-format module)
+ 'face 'magit-diff-file-heading))
+ (if (not (file-exists-p ".git"))
+ (insert "(uninitialized)")
+ (insert (format col-format
+ (--if-let (magit-get-current-branch)
+ (propertize it 'face 'magit-branch-local)
+ (propertize "(detached)" 'face 'warning))))
+ (--when-let (magit-git-string "describe" "--tags")
+ (when (string-match-p "\\`[0-9]" it)
+ (insert ?\s))
+ (insert (propertize it 'face 'magit-tag))))
+ (insert ?\n))))))
+ (insert ?\n))))
+
+(defvar magit-submodules-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-list-submodules)
+ map)
+ "Keymap for `submodules' sections.")
+
+(defvar magit-submodule-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [C-return] 'magit-submodule-visit)
+ (define-key map "\C-j" 'magit-submodule-visit)
+ (define-key map [remap magit-visit-thing] 'magit-submodule-visit)
+ (define-key map [remap magit-delete-thing] 'magit-submodule-deinit)
+ (define-key map "K" 'magit-file-untrack)
+ (define-key map "R" 'magit-file-rename)
+ map)
+ "Keymap for `submodule' sections.")
+
+(defun magit-submodule-visit (module &optional other-window)
+ "Visit MODULE by calling `magit-status' on it.
+Offer to initialize MODULE if it's not checked out yet.
+With a prefix argument, visit in another window."
+ (interactive (list (or (magit-section-when submodule)
+ (magit-read-module-path "Visit module"))
+ current-prefix-arg))
+ (magit-with-toplevel
+ (let ((path (expand-file-name module)))
+ (if (and (not (file-exists-p (expand-file-name ".git" module)))
+ (not (y-or-n-p (format "Initialize submodule '%s' first?"
+ module))))
+ (when (file-exists-p path)
+ (dired-jump other-window (concat path "/.")))
+ (magit-run-git-async "submodule" "update" "--init" "--" module)
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (let ((magit-process-raise-error t))
+ (magit-process-sentinel process event))
+ (when (and (eq (process-status process) 'exit)
+ (= (process-exit-status process) 0))
+ (magit-diff-visit-directory path other-window))))))))
+
+;;;###autoload
+(defun magit-insert-modules-unpulled-from-upstream ()
+ "Insert sections for modules that haven't been pulled from the upstream.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unpulled from @{upstream}"
+ 'modules-unpulled-from-upstream
+ 'magit-get-upstream-ref
+ "HEAD..%s"))
+
+;;;###autoload
+(defun magit-insert-modules-unpulled-from-pushremote ()
+ "Insert sections for modules that haven't been pulled from the push-remote.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unpulled from <push-remote>"
+ 'modules-unpulled-from-pushremote
+ 'magit-get-push-branch
+ "HEAD..%s"))
+
+;;;###autoload
+(defun magit-insert-modules-unpushed-to-upstream ()
+ "Insert sections for modules that haven't been pushed to the upstream.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unmerged into @{upstream}"
+ 'modules-unpushed-to-upstream
+ 'magit-get-upstream-ref
+ "%s..HEAD"))
+
+;;;###autoload
+(defun magit-insert-modules-unpushed-to-pushremote ()
+ "Insert sections for modules that haven't been pushed to the push-remote.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unpushed to <push-remote>"
+ 'modules-unpushed-to-pushremote
+ 'magit-get-push-branch
+ "%s..HEAD"))
+
+(defun magit--insert-modules-logs (heading type fn format)
+ "For internal use, don't add to a hook."
+ (-when-let (modules (magit-get-submodules))
+ (magit-insert-section section ((eval type) nil t)
+ (string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading)
+ (magit-insert-heading
+ (concat
+ (propertize (match-string 1 heading) 'face 'magit-section-heading) " "
+ (propertize (match-string 2 heading) 'face 'magit-branch-remote) ":"))
+ (magit-with-toplevel
+ (dolist (module modules)
+ (let ((default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (--when-let (and (magit-file-accessible-directory-p default-directory)
+ (funcall fn))
+ (magit-insert-section sec (file module t)
+ (magit-insert-heading
+ (concat (propertize module 'face 'magit-diff-file-heading) ":"))
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'module)
+ "log" "--oneline" (format format it))
+ (when (> (point) (magit-section-content sec))
+ (delete-char -1)))))))
+ (if (> (point) (magit-section-content section))
+ (insert ?\n)
+ (magit-cancel-section)))))
+
+;;; List
+
+;;;###autoload
+(defun magit-list-submodules ()
+ "Display a list of the current repository's submodules."
+ (interactive)
+ (magit-display-buffer (magit-mode-get-buffer 'magit-submodule-list-mode t))
+ (magit-submodule-list-mode)
+ (setq tabulated-list-entries
+ (mapcar (lambda (module)
+ (let ((default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (list module
+ (vconcat (--map (or (funcall (nth 2 it) module) "")
+ magit-submodule-list-columns)))))
+ (magit-get-submodules)))
+ (tabulated-list-print))
+
+(defvar magit-submodule-list-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map tabulated-list-mode-map)
+ (define-key map "g" 'magit-list-submodules)
+ (define-key map "\r" 'magit-repolist-status)
+ map)
+ "Local keymap for Magit-Submodule-List mode buffers.")
+
+(define-derived-mode magit-submodule-list-mode tabulated-list-mode "Modules"
+ "Major mode for browsing a list of Git submodules."
+ (setq x-stretch-cursor nil)
+ (setq tabulated-list-padding 0)
+ (setq tabulated-list-sort-key (cons "Path" nil))
+ (setq tabulated-list-format
+ (vconcat (mapcar (-lambda ((title width _fn props))
+ (nconc (list title width t)
+ (-flatten props)))
+ magit-submodule-list-columns)))
+ (tabulated-list-init-header))
+
+(defun magit-modulelist-column-path (path)
+ "Insert the relative path of the submodule."
+ path)
+
+;;; magit-submodule.el ends soon
+
+(define-obsolete-function-alias 'magit-insert-unpulled-module-commits
+ 'magit-insert-modules-unpulled-from-upstream "Magit 2.6.0")
+(define-obsolete-function-alias 'magit-insert-unpushed-module-commits
+ 'magit-insert-modules-unpushed-to-upstream "Magit 2.6.0")
+
+(provide 'magit-submodule)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-submodule.el ends here
--- /dev/null
+;;; magit-subtree.el --- subtree support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Code:
+
+(require 'magit)
+
+;;;###autoload (autoload 'magit-subtree-popup "magit-subtree" nil t)
+(magit-define-popup magit-subtree-popup
+ "Popup console for subtree commands."
+ 'magit-commands
+ :man-page "git-subtree"
+ :switches '("Switches for add, merge, push, and pull"
+ (?s "Squash" "--squash")
+ "Switches for split"
+ (?i "Ignore joins" "--ignore-joins")
+ (?j "Rejoin" "--rejoin"))
+ :options '("Options"
+ (?p "Prefix" "--prefix=" magit-subtree-read-prefix)
+ "Options for add, merge, and pull"
+ (?m "Message" "--message=")
+ "Options for split"
+ (?a "Annotate" "--annotate=")
+ (?b "Branch" "--branch=")
+ (?o "Onto" "--onto=" magit-read-branch-or-commit))
+ :actions '((?a "Add" magit-subtree-add)
+ (?m "Merge" magit-subtree-merge)
+ (?p "Push" magit-subtree-push)
+ (?c "Add commit" magit-subtree-add-commit)
+ (?f "Pull" magit-subtree-pull)
+ (?s "Split" magit-subtree-split))
+ :max-action-columns 3)
+
+(defun magit-subtree-prefix (prompt)
+ (--if-let (--first (string-prefix-p "--prefix=" it)
+ (magit-subtree-arguments))
+ (substring it 9)
+ (magit-subtree-read-prefix prompt)))
+
+(defun magit-subtree-read-prefix (prompt &optional default)
+ (let* ((insert-default-directory nil)
+ (topdir (magit-toplevel))
+ (prefix (read-directory-name (concat prompt ": ") topdir default)))
+ (if (file-name-absolute-p prefix)
+ ;; At least `ido-mode's variant is not compatible.
+ (if (string-prefix-p topdir prefix)
+ (file-relative-name prefix topdir)
+ (user-error "%s isn't inside the repository at %s" prefix topdir))
+ prefix)))
+
+(defun magit-subtree-args ()
+ (-filter (lambda (arg)
+ (if (eq this-command 'magit-subtree-split)
+ (or (equal arg "--ignore-joins")
+ (equal arg "--rejoin")
+ (string-prefix-p "--annotate=" arg)
+ (string-prefix-p "--branch=" arg)
+ (string-prefix-p "--onto=" arg))
+ (or (equal arg "--squash")
+ (and (string-prefix-p "--message=" arg)
+ (not (eq this-command 'magit-subtree-push))))))
+ (magit-subtree-arguments)))
+
+(defun magit-git-subtree (subcmd prefix &rest args)
+ (magit-run-git-async "subtree" subcmd (concat "--prefix=" prefix) args))
+
+;;;###autoload
+(defun magit-subtree-add (prefix repository commit args)
+ "Add COMMIT from REPOSITORY as a new subtree at PREFIX."
+ (interactive (list (magit-subtree-prefix "Add subtree")
+ (magit-read-string-ns "Repository")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-args)))
+ (magit-git-subtree "add" prefix args repository commit))
+
+;;;###autoload
+(defun magit-subtree-add-commit (prefix commit args)
+ "Add COMMIT as a new subtree at PREFIX."
+ (interactive (list (magit-subtree-prefix "Add subtree")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-args)))
+ (magit-git-subtree "add" prefix args commit))
+
+;;;###autoload
+(defun magit-subtree-merge (prefix commit args)
+ "Merge COMMIT into the PREFIX subtree."
+ (interactive (list (magit-subtree-prefix "Merge into subtree")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-args)))
+ (magit-git-subtree "merge" prefix args commit))
+
+;;;###autoload
+(defun magit-subtree-pull (prefix repository commit args)
+ "Pull COMMIT from REPOSITORY into the PREFIX subtree."
+ (interactive (list (magit-subtree-prefix "Pull into subtree")
+ (magit-read-string-ns "From repository")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-args)))
+ (magit-git-subtree "pull" prefix args repository commit))
+
+;;;###autoload
+(defun magit-subtree-push (prefix repository ref args)
+ "Extract the history of the subtree PREFIX and push it to REF on REPOSITORY."
+ (interactive (list (magit-subtree-prefix "Push subtree")
+ (magit-read-string-ns "To repository")
+ (magit-read-string-ns "To reference")
+ (magit-subtree-args)))
+ (magit-git-subtree "push" prefix args repository ref))
+
+;;;###autoload
+(defun magit-subtree-split (prefix commit args)
+ "Extract the history of the subtree PREFIX."
+ (interactive (list (magit-subtree-prefix "Split subtree")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-args)))
+ (magit-git-subtree "split" prefix args commit))
+
+;;; magit-subtree.el ends soon
+(provide 'magit-subtree)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-subtree.el ends here
--- /dev/null
+;;; magit-utils.el --- various utilities -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Contains code from GNU Emacs https://www.gnu.org/software/emacs,
+;; released under the GNU General Public License version 3 or later.
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library defines several utility functions used by several
+;; other libraries which cannot depend on one another (because
+;; circular dependencies are not good). Luckily most (all) of these
+;; functions have very little (nothing) to do with Git, so we not only
+;; have to do this, it even makes sense.
+
+;; Unfortunately there are also some options which are used by several
+;; libraries which cannot depend on one another, they are defined here
+;; too.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+
+(eval-when-compile (require 'ido))
+(declare-function ido-completing-read+ 'ido-completing-read+)
+
+(defvar magit-wip-before-change-mode)
+
+;;; Options
+
+(defcustom magit-completing-read-function 'magit-builtin-completing-read
+ "Function to be called when requesting input from the user.
+
+For Helm users, the simplest way to get Helm completion is to
+turn on `helm-mode' and leave this option set to the default
+value. However, if you prefer to not use `helm-mode' but still
+want Magit to use Helm for completion, you can set this option to
+`helm--completing-read-default'."
+ :group 'magit
+ :type '(radio (function-item magit-builtin-completing-read)
+ (function-item magit-ido-completing-read)
+ (function-item helm--completing-read-default)
+ (function :tag "Other")))
+
+(defcustom magit-no-confirm-default nil
+ "A list of commands which should just use the default choice.
+
+Many commands let the user choose the target they act on offering
+a sensible default as default choice. If you think that that
+default is so sensible that it should always be used without even
+offering other choices, then add that command here.
+
+Commands have to explicitly support this option. Currently only
+these commands do:
+ `magit-branch'
+ `magit-branch-and-checkout'
+ `magit-branch-orphan'
+ `magit-worktree-branch'
+ For these four commands `magit-branch-read-upstream-first'
+ must be non-nil, or adding them here has no effect.
+ `magit-branch-rename'
+ `magit-tag'"
+ :package-version '(magit . "2.9.0")
+ :group 'magit-commands
+ :type '(list :convert-widget custom-hook-convert-widget)
+ :options '(magit-branch
+ magit-branch-and-checkout
+ magit-branch-orphan
+ magit-branch-rename
+ magit-worktree-branch
+ magit-tag))
+
+(defconst magit--confirm-actions
+ '((const reverse) (const discard)
+ (const rename) (const resurrect)
+ (const trash) (const delete)
+ (const abort-rebase)
+ (const abort-merge) (const merge-dirty)
+ (const drop-stashes) (const resect-bisect)
+ (const kill-process) (const delete-unmerged-branch)
+ (const stage-all-changes) (const unstage-all-changes)
+ (const safe-with-wip)))
+
+(defcustom magit-no-confirm nil
+ "A list of symbols for actions Magit should not confirm, or t.
+
+Many potentially dangerous commands by default ask the user for
+confirmation. Each of the below symbols stands for an action
+which, when invoked unintentionally or without being fully aware
+of the consequences, could lead to tears. In many cases there
+are several commands that perform variations of a certain action,
+so we don't use the command names but more generic symbols.
+
+Applying changes:
+
+ `discard' Discarding one or more changes (i.e. hunks or the
+ complete diff for a file) loses that change, obviously.
+
+ `reverse' Reverting one or more changes can usually be undone
+ by reverting the reversion.
+
+ `stage-all-changes', `unstage-all-changes' When there are both
+ staged and unstaged changes, then un-/staging everything would
+ destroy that distinction. Of course that also applies when
+ un-/staging a single change, but then less is lost and one does
+ that so often that having to confirm every time would be
+ unacceptable.
+
+Files:
+
+ `delete' When a file that isn't yet tracked by Git is deleted
+ then it is completely lost, not just the last changes. Very
+ dangerous.
+
+ `trash' Instead of deleting a file it can also be move to the
+ system trash. Obviously much less dangerous than deleting it.
+
+ Also see option `magit-delete-by-moving-to-trash'.
+
+ `resurrect' A deleted file can easily be resurrected by
+ \"deleting\" the deletion, which is done using the same command
+ that was used to delete the same file in the first place.
+
+ `rename' Renaming a file can easily be undone.
+
+Sequences:
+
+ `reset-bisect' Aborting (known to Git as \"resetting\") a
+ bisect operation loses all information collected so far.
+
+ `abort-rebase' Aborting a rebase throws away all already
+ modified commits, but it's possible to restore those from the
+ reflog.
+
+ `abort-merge' Aborting a merge throws away all conflict
+ resolutions which has already been carried out by the user.
+
+ `merge-dirty' Merging with a dirty worktree can make it hard to
+ go back to the state before the merge was initiated.
+
+References:
+
+ `delete-unmerged-branch' Once a branch has been deleted it can
+ only be restored using low-level recovery tools provided by
+ Git. And even then the reflog is gone. The user always has
+ to confirm the deletion of a branch by accepting the default
+ choice (or selecting another branch), but when a branch has
+ not been merged yet, also make sure the user is aware of that.
+
+ `drop-stashes' Dropping a stash is dangerous because Git stores
+ stashes in the reflog. Once a stash is removed, there is no
+ going back without using low-level recovery tools provided by
+ Git. When a single stash is dropped, then the user always has
+ to confirm by accepting the default (or selecting another).
+ This action only concerns the deletion of multiple stashes at
+ once.
+
+Various:
+
+ `kill-process' There seldom is a reason to kill a process.
+
+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
+ 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
+ for confirmation for any of these actions, you are still better
+ of adding all of the respective symbols individually.
+
+ When `magit-wip-before-change-mode' is enabled then these actions
+ can fairly easily be undone: `discard', `reverse',
+ `stage-all-changes', and `unstage-all-changes'. If and only if
+ this mode is enabled then `safe-with-wip' has the same effect
+ as adding all of these symbols individually."
+ :package-version '(magit . "2.1.0")
+ :group 'magit
+ :group 'magit-commands
+ :type `(choice (const :tag "Always require confirmation" nil)
+ (const :tag "Never require confirmation" t)
+ (set :tag "Require confirmation only for"
+ ,@magit--confirm-actions)))
+
+(defcustom magit-slow-confirm '(drop-stashes)
+ "Whether to ask user \"y or n\" or \"yes or no\" questions.
+
+When this is nil, then `y-or-n-p' is used when the user has to
+confirm a potentially destructive action. When this is t, then
+`yes-or-no-p' is used instead. If this is a list of symbols
+identifying actions, then `yes-or-no-p' is used for those,
+`y-or-no-p' for all others. The list of actions is the same as
+for `magit-no-confirm' (which see)."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-commands
+ :type `(choice (const :tag "Always ask \"yes or no\" questions" t)
+ (const :tag "Always ask \"y or n\" questions" nil)
+ (set :tag "Ask yes or no questions only for"
+ ,@magit--confirm-actions)))
+
+(defcustom magit-no-message nil
+ "A list of messages Magit should not display.
+
+Magit displays most echo area messages using `message', but a few
+are displayed using `magit-message' instead, which takes the same
+arguments as the former, FORMAT-STRING and ARGS. `magit-message'
+forgoes printing a message if any member of this list is a prefix
+of the respective FORMAT-STRING.
+
+If Magit prints a message which causes you grief, then please
+first investigate whether there is another option which can be
+used to suppress it. If that is not the case, then ask the Magit
+maintainers to start using `magit-message' instead of `message'
+in that case. We are not proactively replacing all uses of
+`message' with `magit-message', just in case someone *might* find
+some of these messages useless.
+
+Messages which can currently be suppressed using this option are:
+* \"Turning on magit-auto-revert-mode...\""
+ :package-version '(magit . "2.8.0")
+ :group 'magit
+ :type '(repeat string))
+
+(defcustom magit-ellipsis ?…
+ "Character used to abbreviate text."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-modes
+ :type 'character)
+
+(defcustom magit-update-other-window-delay 0.2
+ "Delay before automatically updating the other window.
+
+When moving around in certain buffers certain other buffers,
+which are being displayed in another window, may optionally be
+updated to display information about the section at point.
+
+When holding down a key to move by more than just one section,
+then that would update that buffer for each section on the way.
+To prevent that, updating the revision buffer is delayed, and
+this option controls for how long. For optimal experience you
+might have to adjust this delay and/or the keyboard repeat rate
+and delay of your graphical environment or operating system."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'number)
+
+;;; User Input
+
+(defun magit-completing-read
+ (prompt collection &optional predicate require-match initial-input hist def)
+ "Magit wrapper around `completing-read' or an alternative function.
+
+Option `magit-completing-read-function' can be used to wrap
+around another `completing-read'-like function. Unless it
+doesn't have the exact same signature, an additional wrapper is
+required. Even if it has the same signature it might be a good
+idea to wrap it, so that `magit-prompt-with-default' can be used.
+
+See `completing-read' for the meanings of the arguments, but note
+that this wrapper makes the following changes:
+
+- If REQUIRE-MATCH is nil and the user exits without a choice,
+ then return nil instead of an empty string.
+
+- If REQUIRE-MATCH is non-nil and the users exits without a
+ choice, then raise an user-error.
+
+- \": \" is appended to PROMPT.
+
+- If a `magit-completing-read-function' is used which in turn
+ uses `magit-prompt-with-completion' and DEF is non-nil, then
+ PROMPT is modified to end with \" (default DEF): \".
+
+The use of another completing function and/or wrapper obviously
+results in additional differences."
+ (let ((reply (funcall magit-completing-read-function
+ (concat prompt ": ") collection predicate
+ require-match initial-input hist def)))
+ (if (string= reply "")
+ (if require-match
+ (user-error "Nothing selected")
+ nil)
+ reply)))
+
+(defun magit-builtin-completing-read
+ (prompt choices &optional predicate require-match initial-input hist def)
+ "Magit wrapper for standard `completing-read' function."
+ (completing-read (magit-prompt-with-default prompt def)
+ choices predicate require-match
+ initial-input hist def))
+
+(defun magit-ido-completing-read
+ (prompt choices &optional predicate require-match initial-input hist def)
+ "Ido-based `completing-read' almost-replacement.
+
+Unfortunately `ido-completing-read' is not suitable as a
+drop-in replacement for `completing-read', instead we use
+`ido-completing-read+' from the third-party package by the
+same name."
+ (if (require 'ido-completing-read+ nil t)
+ (ido-completing-read+ prompt choices predicate require-match
+ initial-input hist def)
+ (display-warning 'magit "ido-completing-read+ is not installed
+
+To use Ido completion with Magit you need to install the
+third-party `ido-completing-read+' packages. Falling
+back to built-in `completing-read' for now." :error)
+ (magit-builtin-completing-read prompt choices predicate require-match
+ initial-input hist def)))
+
+(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 magit-minibuffer-local-ns-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map minibuffer-local-map)
+ (define-key map "\s" 'magit-whitespace-disallowed)
+ (define-key map "\t" 'magit-whitespace-disallowed)
+ map))
+
+(defun magit-whitespace-disallowed ()
+ "Beep to tell the user that whitespace is not allowed."
+ (interactive)
+ (ding)
+ (message "Whitespace isn't allowed here")
+ (setq defining-kbd-macro nil)
+ (force-mode-line-update))
+
+(defun magit-read-string (prompt &optional initial-input history default-value
+ inherit-input-method no-whitespace)
+ "Read a string from the minibuffer, prompting with string PROMPT.
+
+This is similar to `read-string', but
+* empty input is only allowed if DEFAULT-VALUE is non-nil in
+ which case that is returned,
+* whitespace is not allowed if NO-WHITESPACE is non-nil,
+* \": \" is appended to PROMPT, and
+* an invalid DEFAULT-VALUE is silently ignored."
+ (when default-value
+ (when (consp default-value)
+ (setq default-value (car default-value)))
+ (unless (stringp default-value)
+ (setq default-value nil)))
+ (let* ((minibuffer-completion-table nil)
+ (val (read-from-minibuffer
+ (magit-prompt-with-default (concat prompt ": ") default-value)
+ initial-input (and no-whitespace magit-minibuffer-local-ns-map)
+ nil history default-value inherit-input-method)))
+ (when (and (string= val "") default-value)
+ (setq val default-value))
+ (cond ((string= val "")
+ (user-error "Need non-empty input"))
+ ((and no-whitespace (string-match-p "[\s\t\n]" val))
+ (user-error "Input contains whitespace"))
+ (t val))))
+
+(defun magit-read-string-ns (prompt &optional initial-input history
+ default-value inherit-input-method)
+ "Call `magit-read-string' with non-nil NO-WHITESPACE."
+ (magit-read-string prompt initial-input history default-value
+ inherit-input-method t))
+
+(defmacro magit-read-char-case (prompt verbose &rest clauses)
+ (declare (indent 2)
+ (debug (form form &rest (characterp form body))))
+ `(pcase (read-char-choice
+ (concat ,prompt
+ ,(concat (mapconcat 'cadr clauses ", ")
+ (and verbose ", or [C-g] to abort") " "))
+ ',(mapcar 'car clauses))
+ ,@(--map `(,(car it) ,@(cddr it)) clauses)))
+
+(defun magit-y-or-n-p (prompt &optional action)
+ "Ask user a \"y or n\" or a \"yes or no\" question using PROMPT.
+Which kind of question is used depends on whether
+ACTION is a member of option `magit-slow-confirm'."
+ (if (or (eq magit-slow-confirm t)
+ (and action (member action magit-slow-confirm)))
+ (yes-or-no-p prompt)
+ (y-or-n-p prompt)))
+
+(cl-defun magit-confirm (action &optional prompt prompt-n (items nil sitems))
+ (declare (indent defun))
+ (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items))
+ prompt (format (concat (or prompt (magit-confirm-make-prompt action))
+ "? ")
+ (car items)))
+ (cond ((and (not (eq action t))
+ (or (eq magit-no-confirm t)
+ (memq action
+ `(,@magit-no-confirm
+ ,@(and magit-wip-before-change-mode
+ (memq 'safe-with-wip magit-no-confirm)
+ `(discard reverse
+ stage-all-changes
+ unstage-all-changes))))))
+ (or (not sitems) items))
+ ((not sitems)
+ (magit-y-or-n-p prompt action))
+ ((= (length items) 1)
+ (and (magit-y-or-n-p prompt action) items))
+ ((> (length items) 1)
+ (let ((buffer (get-buffer-create " *Magit Confirm*")))
+ (with-current-buffer buffer
+ (with-current-buffer-window
+ buffer (cons 'display-buffer-below-selected
+ '((window-height . fit-window-to-buffer)))
+ (lambda (window _value)
+ (with-selected-window window
+ (unwind-protect (and (magit-y-or-n-p prompt-n action) items)
+ (when (window-live-p window)
+ (quit-restore-window window 'kill)))))
+ (dolist (item items)
+ (insert item "\n"))))))))
+
+(defun magit-confirm-files (action files &optional prompt)
+ (when files
+ (unless prompt
+ (setq prompt (magit-confirm-make-prompt action)))
+ (magit-confirm action
+ (concat prompt " %s")
+ (concat prompt " %i files")
+ files)))
+
+(defun magit-confirm-make-prompt (action)
+ (let ((prompt (symbol-name action)))
+ (replace-regexp-in-string
+ "-" " " (concat (upcase (substring prompt 0 1)) (substring prompt 1)))))
+
+;;; Text Utilities
+
+(defmacro magit-bind-match-strings (varlist string &rest body)
+ "Bind variables to submatches according to VARLIST then evaluate BODY.
+Bind the symbols in VARLIST to submatches of the current match
+data, starting with 1 and incrementing by 1 for each symbol. If
+the last match was against a string then that has to be provided
+as STRING."
+ (declare (indent 2) (debug (listp form body)))
+ (let ((s (cl-gensym "string"))
+ (i 0))
+ `(let ((,s ,string))
+ (let ,(save-match-data
+ (--map (list it (list 'match-string (cl-incf i) s)) varlist))
+ ,@body))))
+
+(defun magit-delete-line ()
+ "Delete the rest of the current line."
+ (delete-region (point) (1+ (line-end-position))))
+
+(defun magit-delete-match (&optional num)
+ "Delete text matched by last search.
+If optional NUM is specified only delete that subexpression."
+ (delete-region (match-beginning (or num 0))
+ (match-end (or num 0))))
+
+(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)))))
+
+(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)))))
+
+;;; Kludges
+
+(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)))
+
+(defun magit-message (format-string &rest args)
+ "Display a message at the bottom of the screen, or not.
+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)
+ (apply #'message format-string args)))
+
+(defvar whitespace-mode)
+
+(defun whitespace-dont-turn-on-in-magit-mode ()
+ "Prevent `whitespace-mode' from being turned on in Magit buffers.
+Because `whitespace-mode' uses font-lock and Magit does not,
+they are not compatible. See `magit-diff-paint-whitespace'
+for an alternative."
+ (when (derived-mode-p 'magit-mode)
+ (setq whitespace-mode nil)
+ (user-error
+ "Whitespace-Mode isn't compatible with Magit. %s"
+ "See `magit-diff-paint-whitespace' for an alternative.")))
+
+(advice-add 'whitespace-turn-on :before
+ 'whitespace-dont-turn-on-in-magit-mode)
+
+;;; magit-utils.el ends soon
+(provide 'magit-utils)
+;; Local Variables:
+;; coding: utf-8
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-utils.el ends here
--- /dev/null
+;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library defines tree global modes which automatically commit
+;; snapshots to branch specific work-in-progress refs before and after
+;; making changes, and two commands which can be used to do so on
+;; demand.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-log)
+
+;;; Options
+
+(defgroup magit-wip nil
+ "Automatically commit to work-in-progress refs."
+ :group 'magit-extensions)
+
+(defcustom magit-wip-after-save-local-mode-lighter " sWip"
+ "Lighter for Magit-Wip-After-Save-Local mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :type 'string)
+
+(defcustom magit-wip-after-apply-mode-lighter " aWip"
+ "Lighter for Magit-Wip-After-Apply mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :type 'string)
+
+(defcustom magit-wip-before-change-mode-lighter " cWip"
+ "Lighter for Magit-Wip-Before-Change mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :type 'string)
+
+(defcustom magit-wip-namespace "refs/wip/"
+ "Namespace used for work-in-progress refs.
+The wip refs are named \"<namespace/>index/<branchref>\"
+and \"<namespace/>wtree/<branchref>\". When snapshots
+are created while the `HEAD' is detached then \"HEAD\"
+is used as `branch-ref'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :type 'string)
+
+;;; Modes
+
+(define-minor-mode magit-wip-after-save-local-mode
+ "After saving, also commit to a worktree work-in-progress ref.
+
+After saving the current file-visiting buffer this mode also
+commits the changes to the worktree work-in-progress ref for
+the current branch.
+
+This mode should be enabled globally by turning on the globalized
+variant `magit-wip-after-save-mode'."
+ :package-version '(magit . "2.1.0")
+ :lighter magit-wip-after-save-local-mode-lighter
+ (if magit-wip-after-save-local-mode
+ (if (and buffer-file-name (magit-inside-worktree-p))
+ (add-hook 'after-save-hook 'magit-wip-commit-buffer-file t t)
+ (setq magit-wip-after-save-local-mode nil)
+ (user-error "Need a worktree and a file"))
+ (remove-hook 'after-save-hook 'magit-wip-commit-buffer-file t)))
+
+(defun magit-wip-after-save-local-mode-turn-on ()
+ (and buffer-file-name
+ (ignore-errors (magit-inside-worktree-p))
+ (magit-file-tracked-p buffer-file-name)
+ (magit-wip-after-save-local-mode)))
+
+;;;###autoload
+(define-globalized-minor-mode magit-wip-after-save-mode
+ magit-wip-after-save-local-mode magit-wip-after-save-local-mode-turn-on
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip)
+
+(defun magit-wip-commit-buffer-file ()
+ "Commit visited file to a worktree work-in-progress ref.
+
+Also see `magit-wip-after-save-mode' which calls this function
+automatically whenever a buffer visiting a tracked file is saved."
+ (interactive)
+ (--when-let (magit-wip-get-ref)
+ (magit-with-toplevel
+ (let ((file (file-relative-name buffer-file-name)))
+ (magit-wip-commit-worktree
+ it (list file) (if (called-interactively-p 'any)
+ (format "wip-save %s after save" file)
+ (format "autosave %s after save" file)))))))
+
+;;;###autoload
+(define-minor-mode magit-wip-after-apply-mode
+ "Commit to work-in-progress refs.
+
+After applying a change using any \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected files to the current wip refs. For each branch there
+may be two wip refs; one contains snapshots of the files as found
+in the worktree and the other contains snapshots of the entries
+in the index."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :lighter magit-wip-after-change-mode-lighter
+ :global t)
+
+(defun magit-wip-commit-after-apply (&optional files msg)
+ (when magit-wip-after-apply-mode
+ (magit-wip-commit files msg)))
+
+;;;###autoload
+(define-minor-mode magit-wip-before-change-mode
+ "Commit to work-in-progress refs before certain destructive changes.
+
+Before invoking a revert command or an \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected tracked files to the current wip refs. For each branch
+there may be two wip refs; one contains snapshots of the files
+as found in the worktree and the other contains snapshots of the
+entries in the index.
+
+Only changes to files which could potentially be affected by the
+command which is about to be called are committed."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :lighter magit-wip-before-change-mode-lighter
+ :global t)
+
+(defun magit-wip-commit-before-change (&optional files msg)
+ (when magit-wip-before-change-mode
+ (magit-with-toplevel
+ (magit-wip-commit files msg))))
+
+;;; Core
+
+(defun magit-wip-commit (&optional files msg)
+ "Commit all tracked files to the work-in-progress refs.
+
+Interactively, commit all changes to all tracked files using
+a generic commit message. With a prefix-argument the commit
+message is read in the minibuffer.
+
+Non-interactively, only commit changes to FILES using MSG as
+commit message."
+ (interactive (list nil (if current-prefix-arg
+ (magit-read-string "Wip commit message")
+ "wip-save tracked files")))
+ (--when-let (magit-wip-get-ref)
+ (magit-wip-commit-index it files msg)
+ (magit-wip-commit-worktree it files msg)))
+
+(defun magit-wip-commit-index (ref files msg &optional cached-only)
+ (let* ((wipref (concat magit-wip-namespace "index/" ref))
+ (parent (magit-wip-get-parent ref wipref)))
+ (when (magit-git-failure "diff-index" "--quiet"
+ (and cached-only "--cached")
+ parent "--" files)
+ (magit-wip-update-wipref wipref (magit-git-string "write-tree")
+ parent files msg "index"))))
+
+(defun magit-wip-commit-worktree (ref files msg)
+ (let* ((wipref (concat magit-wip-namespace "wtree/" ref))
+ (parent (magit-wip-get-parent ref wipref))
+ (tree (magit-with-temp-index parent "--reset"
+ (if files
+ (magit-call-git "add" "--" files)
+ (magit-with-toplevel
+ (magit-call-git "add" "-u" ".")))
+ (magit-git-string "write-tree"))))
+ (when (magit-git-failure "diff-tree" "--quiet" parent tree "--" files)
+ (magit-wip-update-wipref wipref tree parent files msg "worktree"))))
+
+(defun magit-wip-update-wipref (wipref tree parent files msg start-msg)
+ (let ((len (length files)))
+ (unless (and msg (not (= (aref msg 0) ?\s)))
+ (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)))))
+ msg)))
+ (unless (equal parent wipref)
+ (setq start-msg (concat "restart autosaving " start-msg))
+ (magit-update-ref wipref start-msg
+ (magit-git-string "commit-tree" "--no-gpg-sign"
+ "-p" parent "-m" start-msg
+ (concat parent "^{tree}")))
+ (setq parent wipref))
+ (magit-update-ref wipref msg
+ (magit-git-string "commit-tree" "--no-gpg-sign"
+ "-p" parent "-m" msg tree))))
+
+(defun magit-wip-get-ref ()
+ (let ((ref (or (magit-git-string "symbolic-ref" "HEAD") "HEAD")))
+ (when (magit-rev-verify ref)
+ ref)))
+
+(defun magit-wip-get-parent (ref wipref)
+ (if (and (magit-rev-verify wipref)
+ (equal (magit-git-string "merge-base" wipref ref)
+ (magit-rev-verify ref)))
+ wipref
+ ref))
+
+;;; Log
+
+(defun magit-wip-log-current (branch args files count)
+ "Show log for the current branch and its wip refs.
+With a negative prefix argument only show the worktree wip ref.
+The absolute numeric value of the prefix argument controls how
+many \"branches\" of each wip ref are shown."
+ (interactive
+ (nconc (list (or (magit-get-current-branch) "HEAD"))
+ (magit-log-arguments)
+ (list (prefix-numeric-value current-prefix-arg))))
+ (magit-wip-log branch args files count))
+
+(defun magit-wip-log (branch args files count)
+ "Show log for a branch and its wip refs.
+With a negative prefix argument only show the worktree wip ref.
+The absolute numeric value of the prefix argument controls how
+many \"branches\" of each wip ref are shown."
+ (interactive
+ (nconc (list (magit-completing-read
+ "Log branch and its wip refs"
+ (-snoc (magit-list-local-branch-names) "HEAD")
+ nil t nil 'magit-revision-history
+ (or (magit-branch-at-point)
+ (magit-get-current-branch)
+ "HEAD")))
+ (magit-log-arguments)
+ (list (prefix-numeric-value current-prefix-arg))))
+ (unless (equal branch "HEAD")
+ (setq branch (concat "refs/heads/" branch)))
+ (magit-log (nconc (list branch)
+ (magit-wip-log-get-tips
+ (concat magit-wip-namespace "wtree/" branch)
+ (abs count))
+ (and (>= count 0)
+ (magit-wip-log-get-tips
+ (concat magit-wip-namespace "index/" branch)
+ (abs count))))
+ args files))
+
+(defun magit-wip-log-get-tips (wipref count)
+ (-when-let (reflog (magit-git-lines "reflog" wipref))
+ (let (tips)
+ (while (and reflog (> count 1))
+ (setq reflog (cl-member "^[^ ]+ [^:]+: restart autosaving"
+ reflog :test #'string-match-p))
+ (when (and (cadr reflog)
+ (string-match "^[^ ]+ \\([^:]+\\)" (cadr reflog)))
+ (push (match-string 1 (cadr reflog)) tips))
+ (setq reflog (cddr reflog))
+ (cl-decf count))
+ (cons wipref (nreverse tips)))))
+
+;;; magit-wip.el ends soon
+(provide 'magit-wip)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-wip.el ends here
--- /dev/null
+;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Marius Vollmer <marius.vollmerNOSPAMgmail.com>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Kyle Meyer <kyleNOSPAMkyleam.com>
+;; Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
+;; Former-Maintainers:
+;; Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
+;; Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
+;; Phil Jackson <philNOSPAMshellarchive.co.uk>
+;; Rémi Vanicat <vanicatNOSPAMdebian.org>
+;; Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+
+;; Package-Requires: ((emacs "24.4") (async "20160711.223") (dash "20160820.501") (with-editor "20160929.734") (git-commit "20160929.801") (magit-popup "20160821.1338"))
+;; Keywords: git tools vc
+;; Homepage: https://github.com/magit/magit
+
+;; Magit requires at least GNU Emacs 24.4 and Git 1.9.4.
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Magit is an interface to the version control system Git,
+;; implemented as an Emacs package. Magit aspires to be a complete
+;; Git porcelain. While we cannot (yet) claim, that Magit wraps and
+;; improves upon each and every Git command, it is complete enough to
+;; allow even experienced Git users to perform almost all of their
+;; daily version control tasks directly from within Emacs. While many
+;; fine Git clients exist, only Magit and Git itself deserve to be
+;; called porcelains.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+
+(require 'with-editor)
+(require 'git-commit)
+(require 'magit-core)
+(require 'magit-diff)
+(require 'magit-apply)
+(require 'magit-log)
+
+(require 'format-spec)
+(require 'package nil t) ; used in `magit-version'
+
+(eval-when-compile (require 'dired-x))
+(declare-function dired-jump 'dired-x)
+(eval-when-compile (require 'eshell))
+(declare-function eshell-parse-arguments 'eshell)
+(eval-when-compile (require 'message))
+
+(defconst magit--minimal-git "1.9.4")
+(defconst magit--minimal-emacs "24.4")
+
+;;; Options
+;;;; Status Mode
+
+(defgroup magit-status nil
+ "Inspect and manipulate Git repositories."
+ :group 'magit-modes)
+
+(defcustom magit-status-mode-hook nil
+ "Hook run after entering Magit-Status mode."
+ :group 'magit-status
+ :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)
+ "Hook run to insert headers into the status buffer.
+
+This hook is run by `magit-insert-status-headers', which in turn
+has to be a member of `magit-status-sections-hook' to be used at
+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))
+
+(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-unpulled-from-upstream
+ magit-insert-unpulled-from-pushremote
+ magit-insert-unpushed-to-upstream
+ magit-insert-unpushed-to-pushremote)
+ "Hook run to insert sections into a status buffer."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-status
+ :type 'hook)
+
+(defvar magit-status-refresh-hook nil
+ "Hook run after a status buffer has been refreshed.")
+
+(defcustom magit-status-expand-stashes t
+ "Whether the list of stashes is expanded initially."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-status
+ :type 'boolean)
+
+(defcustom magit-status-show-hashes-in-headers nil
+ "Whether headers in the status buffer show hashes.
+The functions which respect this option are
+`magit-insert-head-branch-header',
+`magit-insert-upstream-branch-header', and
+`magit-insert-push-branch-header'."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-status
+ :type 'boolean)
+
+;;;; Refs Mode
+
+(defgroup magit-refs nil
+ "Inspect and manipulate Git branches and tags."
+ :group 'magit-modes)
+
+(defcustom magit-refs-mode-hook nil
+ "Hook run after entering Magit-Refs mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :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)
+ "Hook run to insert sections into a references buffer."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :type 'hook)
+
+(defcustom magit-refs-show-commit-count nil
+ "Whether to show commit counts in Magit-Refs mode buffers.
+
+all Show counts for branches and tags.
+branch Show counts for branches only.
+nil Never show counts.
+
+To change the value in an existing buffer use the command
+`magit-refs-show-commit-count'"
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :safe (lambda (val) (memq val '(all branch nil)))
+ :type '(choice (const all :tag "For branches and tags")
+ (const branch :tag "For branches only")
+ (const nil :tag "Never")))
+(put 'magit-refs-show-commit-count 'safe-local-variable 'symbolp)
+(put 'magit-refs-show-commit-count 'permanent-local t)
+
+(defcustom magit-refs-show-margin 'branch
+ "Whether to initially show the margin in refs buffers.
+
+When non-nil the committer name and date are initially displayed
+in the margin of refs buffers. The margin can be shown or hidden
+in the current buffer using the command `magit-toggle-margin'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :safe (lambda (val) (memq val '(all branch nil)))
+ :type '(choice (const all :tag "For branches and tags")
+ (const branch :tag "For branches only")
+ (const nil :tag "Never")))
+
+(defcustom magit-visit-ref-create nil
+ "Whether `magit-visit-ref' may create new branches.
+
+When this is non-nil, then \"visiting\" a remote branch in a
+refs buffer works by creating a new local branch which tracks
+the remote branch and then checking out the new local branch."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :group 'magit-commands
+ :type 'boolean)
+
+;;;; Miscellaneous
+
+(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.
+`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
+ new branch and continue by reading the upstream next."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "read branch name first" nil)
+ (const :tag "read upstream first" t)
+ (const :tag "read upstream first, with fallback" fallback)))
+
+(defcustom magit-branch-prefer-remote-upstream nil
+ "Whether to favor remote upstreams when creating new branches.
+
+When a new branch is created, Magit offers the branch, commit, or
+stash as the default starting point of the new branch. If there
+is no such thing at point, then it falls back to offer the
+current branch as starting-point. The user may then accept that
+default or pick something else.
+
+If the chosen starting-point is a branch, then it may also be set
+as the upstream of the new branch, depending on the value of the
+Git variable `branch.autoSetupMerge'. By default this is done
+for remote branches, but not for local branches.
+
+You might prefer to always use some remote branch as upstream.
+If the chosen starting-point is (1) a local branch, (2) whose
+name matches a member of the value of this option, (3) the
+upstream of that local branch is a remote branch with the same
+name, and (4) that remote branch can be fast-forwarded to the
+local branch, then the chosen branch is used as starting-point,
+but its own upstream is used as the upstream of the new branch.
+
+Members of this option's value are treated as branch names that
+have to match exactly unless they contain a character that makes
+them invalid as a branch name. Recommended characters to use
+to trigger interpretation as a regexp are \"*\" and \"^\". Some
+other characters which you might expect to be invalid, actually
+are not, e.g. \".+$\" are all perfectly valid. More precisely,
+if `git check-ref-format --branch STRING' exits with a non-zero
+status, then treat STRING as a regexp.
+
+Assuming the chosen branch matches these conditions you would end
+up with with e.g.:
+
+ feature --upstream--> origin/master
+
+instead of
+
+ feature --upstream--> master --upstream--> origin/master
+
+Which you prefer is a matter of personal preference. If you do
+prefer the former, then you should add branches such as \"master\",
+\"next\", and \"maint\" to the value of this options."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-commands
+ :type '(repeat string))
+
+(defcustom magit-branch-adjust-remote-upstream-alist nil
+ "Alist of upstreams to be used when branching from remote branches.
+
+When creating a local branch from an ephemeral branch located
+on a remote, e.g. a feature or hotfix branch, then that remote
+branch should usually not be used as the upstream branch, since
+the push-remote already allows accessing it and having both the
+upstream and the push-remote reference the same related branch
+would be wasteful. Instead a branch like \"maint\" or \"master\"
+should be used as the upstream.
+
+This option allows specifing the branch that should be used as
+the upstream when branching certain remote branches. The value
+is an alist of the form ((UPSTREAM . RULE)...). The first
+matching element is used, the following elements are ignored.
+
+UPSTREAM is the branch to be used as the upstream for branches
+specified by RULE. It can be a local or a remote branch.
+
+RULE can either be a regular expression, matching branches whose
+upstream should be the one specified by UPSTREAM. Or it can be
+a list of the only branches that should *not* use UPSTREAM; all
+other branches will. Matching is done after stripping the remote
+part of the name of the branch that is being branched from.
+
+If you use a finite set of non-ephemeral branches across all your
+repositories, then you might use something like:
+
+ ((\"origin/master\" \"master\" \"next\" \"maint\"))
+
+Or if the names of all your ephemeral branches contain a slash,
+at least in some repositories, then a good value could be:
+
+ ((\"origin/master\" . \"/\"))
+
+Of course you can also fine-tune:
+
+ ((\"origin/maint\" . \"\\`hotfix/\")
+ (\"origin/master\" . \"\\`feature/\"))"
+ :package-version '(magit . "2.9.0")
+ :group 'magit-commands
+ :type '(repeat (cons (string :tag "Use upstream")
+ (choice :tag "for branches"
+ (regexp :tag "matching")
+ (repeat :tag "except"
+ (string :tag "branch"))))))
+
+(defcustom magit-branch-popup-show-variables t
+ "Whether the `magit-branch-popup' shows Git variables.
+This defaults to t to avoid changing key bindings. When set to
+nil, no variables are displayed directly in this popup, instead
+the sub-popup `magit-branch-config-popup' has to be used to view
+and change branch related variables."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-repository-directories nil
+ "List of directories that are or contain Git repositories.
+Each element has the form (DIRECTORY . DEPTH) or, for backward
+compatibility, just DIRECTORY. DIRECTORY has to be a directory
+or a directory file-name, a string. DEPTH, an integer, specifies
+the maximum depth to look for Git repositories. If it is 0, then
+only add DIRECTORY itself. For elements that are strings, the
+value of option `magit-repository-directories-depth' specifies
+the depth."
+ :package-version '(magit . "2.8.0")
+ :group 'magit
+ :type '(repeat (choice (cons directory (integer :tag "Depth")) directory)))
+
+(defcustom magit-repository-directories-depth 3
+ "The maximum depth to look for Git repositories.
+This option is obsolete and only used for elements of the option
+`magit-repository-directories' (which see) that don't specify the
+depth directly."
+ :group 'magit
+ :type 'integer)
+
+(defcustom magit-repolist-columns
+ '(("Name" 25 magit-repolist-column-ident nil)
+ ("Version" 25 magit-repolist-column-version nil)
+ ("L<U" 3 magit-repolist-column-unpulled-from-upstream (:right-align t))
+ ("L>U" 3 magit-repolist-column-unpushed-to-upstream (:right-align t))
+ ("Path" 99 magit-repolist-column-path))
+ "List of columns displayed by `magit-list-repositories'.
+
+Each element has the form (HEADER WIDTH FORMAT PROPS).
+
+HEADER is the string displayed in the header. WIDTH is the width
+of the column. FORMAT is a function that is called with one
+argument, the repository identification (usually its basename),
+and with `default-directory' bound to the toplevel of its working
+tree. It has to return a string to be inserted or nil. PROPS is
+an alist that supports the keys `:right-align' and `:pad-right'."
+ :package-version '(magit . "2.8.0")
+ :group 'magit-commands
+ :type `(repeat (list :tag "Column"
+ (string :tag "Header Label")
+ (integer :tag "Column Width")
+ (function :tag "Inserter Function")
+ (repeat :tag "Properties"
+ (list (choice :tag "Property"
+ (const :right-align)
+ (const :pad-right)
+ (symbol))
+ (sexp :tag "Value"))))))
+
+;;;; Faces
+
+(defface magit-header-line
+ '((t :inherit magit-section-heading))
+ "Face for the `header-line'."
+ :group 'magit-faces)
+
+(defface magit-dimmed
+ '((((class color) (background light)) :foreground "grey50")
+ (((class color) (background dark)) :foreground "grey50"))
+ "Face for text that shouldn't stand out."
+ :group 'magit-faces)
+
+(defface magit-hash
+ '((((class color) (background light)) :foreground "grey60")
+ (((class color) (background dark)) :foreground "grey40"))
+ "Face for the sha1 part of the log output."
+ :group 'magit-faces)
+
+(defface magit-tag
+ '((((class color) (background light)) :foreground "Goldenrod4")
+ (((class color) (background dark)) :foreground "LightGoldenrod2"))
+ "Face for tag labels shown in log buffer."
+ :group 'magit-faces)
+
+(defface magit-branch-remote
+ '((((class color) (background light)) :foreground "DarkOliveGreen4")
+ (((class color) (background dark)) :foreground "DarkSeaGreen2"))
+ "Face for remote branch head labels shown in log buffer."
+ :group 'magit-faces)
+
+(defface magit-branch-local
+ '((((class color) (background light)) :foreground "SkyBlue4")
+ (((class color) (background dark)) :foreground "LightSkyBlue1"))
+ "Face for local branches."
+ :group 'magit-faces)
+
+(defface magit-branch-current
+ '((((class color) (background light)) :inherit magit-branch-local :box t)
+ (((class color) (background dark)) :inherit magit-branch-local :box t))
+ "Face for current branch."
+ :group 'magit-faces)
+
+(defface magit-head
+ '((((class color) (background light)) :inherit magit-branch-local)
+ (((class color) (background dark)) :inherit magit-branch-local))
+ "Face for the symbolic ref \"HEAD\"."
+ :group 'magit-faces)
+
+(defface magit-refname
+ '((((class color) (background light)) :foreground "grey30")
+ (((class color) (background dark)) :foreground "grey80"))
+ "Face for refnames without a dedicated face."
+ :group 'magit-faces)
+
+(defface magit-refname-stash
+ '((t :inherit magit-refname))
+ "Face for wip refnames."
+ :group 'magit-faces)
+
+(defface magit-refname-wip
+ '((t :inherit magit-refname))
+ "Face for wip refnames."
+ :group 'magit-faces)
+
+(defface magit-signature-good
+ '((t :foreground "green"))
+ "Face for good signatures."
+ :group 'magit-faces)
+
+(defface magit-signature-bad
+ '((t :foreground "red" :weight bold))
+ "Face for bad signatures."
+ :group 'magit-faces)
+
+(defface magit-signature-untrusted
+ '((t :foreground "cyan"))
+ "Face for good untrusted signatures."
+ :group 'magit-faces)
+
+(defface magit-signature-expired
+ '((t :foreground "orange"))
+ "Face for signatures that have expired."
+ :group 'magit-faces)
+
+(defface magit-signature-expired-key
+ '((t :inherit magit-signature-expired))
+ "Face for signatures made by an expired key."
+ :group 'magit-faces)
+
+(defface magit-signature-revoked
+ '((t :foreground "violet red"))
+ "Face for signatures made by a revoked key."
+ :group 'magit-faces)
+
+(defface magit-signature-error
+ '((t :foreground "firebrick3"))
+ "Face for signatures that cannot be checked (e.g. missing key)."
+ :group 'magit-faces)
+
+(defface magit-cherry-unmatched
+ '((t :foreground "cyan"))
+ "Face for unmatched cherry commits."
+ :group 'magit-faces)
+
+(defface magit-cherry-equivalent
+ '((t :foreground "magenta"))
+ "Face for equivalent cherry commits."
+ :group 'magit-faces)
+
+(defface magit-filename
+ '((t :weight normal))
+ "Face for filenames."
+ :group 'magit-faces)
+
+;;; Inspect
+;;;; Status Mode
+;;;;; Status Core
+
+(defvar magit-status-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "jz" 'magit-jump-to-stashes)
+ (define-key map "jt" 'magit-jump-to-tracked)
+ (define-key map "jn" 'magit-jump-to-untracked)
+ (define-key map "ju" 'magit-jump-to-unstaged)
+ (define-key map "js" 'magit-jump-to-staged)
+ (define-key map "jfu" 'magit-jump-to-unpulled-from-upstream)
+ (define-key map "jfp" 'magit-jump-to-unpulled-from-pushremote)
+ (define-key map "jpu" 'magit-jump-to-unpushed-to-upstream)
+ (define-key map "jpp" 'magit-jump-to-unpushed-to-pushremote)
+ map)
+ "Keymap for `magit-status-mode'.")
+
+(eval-after-load 'dired-x
+ '(define-key magit-status-mode-map [remap dired-jump] 'magit-dired-jump))
+
+(define-derived-mode magit-status-mode magit-mode "Magit"
+ "Mode for looking at Git status.
+
+This mode is documented in info node `(magit)Status buffer'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-section-toggle] to expand or hide the section at point.
+Type \\[magit-visit-thing] to visit the change or commit at point.
+
+Type \\[magit-dispatch-popup] to see available prefix popups.
+
+Staging and applying changes is documented in info node
+`(magit)Staging and unstaging' and info node `(magit)Applying'.
+
+\\<magit-hunk-section-map>Type \
+\\[magit-apply] to apply the change at point, \
+\\[magit-stage] to stage,
+\\[magit-unstage] to unstage, \
+\\[magit-discard] to discard, or \
+\\[magit-reverse] to reverse it.
+
+\\<magit-status-mode-map>\
+Type \\[magit-commit-popup] to create a commit.
+
+\\{magit-status-mode-map}"
+ :group 'magit-status
+ (hack-dir-local-variables-non-file-buffer)
+ ;; Avoid listing all files as deleted when visiting a bare repo.
+ (when (magit-bare-repo-p)
+ (make-local-variable 'magit-status-sections-hook)
+ (remove-hook 'magit-status-sections-hook #'magit-insert-staged-changes
+ 'local)))
+
+;;;###autoload
+(defun magit-status (&optional directory)
+ "Show the status of the current Git repository in a buffer.
+With a prefix argument prompt for a repository to be shown.
+With two prefix arguments prompt for an arbitrary directory.
+If that directory isn't the root of an existing repository
+then offer to initialize it as a new repository."
+ (interactive
+ (list (and (or current-prefix-arg (not (magit-toplevel)))
+ (magit-read-repository
+ (>= (prefix-numeric-value current-prefix-arg) 16)))))
+ (if directory
+ (let ((toplevel (magit-toplevel directory)))
+ (setq directory (file-name-as-directory (expand-file-name directory)))
+ (if (and toplevel (string-equal directory toplevel))
+ (magit-status-internal directory)
+ (when (y-or-n-p
+ (if toplevel
+ (format "%s is a repository. Create another in %s? "
+ toplevel directory)
+ (format "Create repository in %s? " directory)))
+ (magit-init directory))))
+ (magit-status-internal default-directory)))
+
+(put 'magit-status 'interactive-only 'magit-status-internal)
+
+;;;###autoload
+(defun magit-status-internal (directory)
+ (magit-tramp-asserts directory)
+ (let ((default-directory directory))
+ (magit-mode-setup #'magit-status-mode)))
+
+;;;;; Standard Status Sections
+
+(defvar magit-status-sections-hook-1 nil)
+
+(defun magit-status-refresh-buffer ()
+ (magit-git-exit-code "update-index" "--refresh")
+ (magit-insert-section (status)
+ (if (-all-p #'functionp magit-status-sections-hook)
+ (run-hooks 'magit-status-sections-hook)
+ (message "`magit-status-sections-hook' contains entries that are \
+no longer valid.\nUsing standard value instead. Please re-configure")
+ (sit-for 5)
+ (let ((magit-status-sections-hook-1
+ (eval (car (get 'magit-status-sections-hook 'standard-value)))))
+ (run-hooks 'magit-status-sections-hook-1))))
+ (run-hooks 'magit-status-refresh-hook))
+
+(defun magit-insert-status-headers ()
+ "Insert header sections appropriate for `magit-status-mode' buffers.
+The sections are inserted by running the functions on the hook
+`magit-status-headers-hook'."
+ (if (magit-rev-verify "HEAD")
+ (magit-insert-headers magit-status-headers-hook)
+ (insert "In the beginning there was darkness\n\n")))
+
+(defun magit-insert-error-header ()
+ "Insert the message about the Git error that just occured.
+
+This function is only aware of the last error that occur when Git
+was run for side-effects. If, for example, an error occurs while
+generating a diff, then that error won't be inserted. Refreshing
+the status buffer causes this section to disappear again."
+ (when magit-this-error
+ (magit-insert-section (error 'git)
+ (insert (propertize (format "%-10s" "GitError! ")
+ 'face 'magit-section-heading))
+ (insert (propertize magit-this-error 'face 'font-lock-warning-face))
+ (-when-let (key (car (where-is-internal 'magit-process-buffer)))
+ (insert (format " [Type `%s' for details]" (key-description key))))
+ (insert ?\n))
+ (setq magit-this-error nil)))
+
+(cl-defun magit-insert-head-branch-header
+ (&optional (branch (magit-get-current-branch)))
+ "Insert a header line about BRANCH.
+When BRANCH is nil, use the current branch or, if none, the
+detached `HEAD'."
+ (let ((output (magit-rev-format "%h %s" (or branch "HEAD"))))
+ (string-match "^\\([^ ]+\\) \\(.*\\)" output)
+ (magit-bind-match-strings (commit summary) output
+ (if branch
+ (magit-insert-section (branch branch)
+ (insert (format "%-10s" "Head: "))
+ (when magit-status-show-hashes-in-headers
+ (insert (propertize commit 'face 'magit-hash) ?\s))
+ (insert (propertize branch 'face 'magit-branch-local))
+ (insert ?\s summary ?\n))
+ (magit-insert-section (commit commit)
+ (insert (format "%-10s" "Head: "))
+ (insert (propertize commit 'face 'magit-hash))
+ (insert ?\s summary ?\n))))))
+
+(cl-defun magit-insert-upstream-branch-header
+ (&optional (branch (magit-get-current-branch))
+ (pull (magit-get-upstream-branch branch))
+ keyword)
+ "Insert a header line about branch usually pulled into current branch."
+ (when pull
+ (magit-insert-section (branch pull)
+ (let ((rebase (magit-git-string "config"
+ (format "branch.%s.rebase" branch))))
+ (if (equal rebase "false")
+ (setq rebase nil)
+ (setq rebase (magit-get-boolean "pull.rebase")))
+ (insert (format "%-10s" (or keyword (if rebase "Rebase: " "Merge: ")))))
+ (--when-let (and magit-status-show-hashes-in-headers
+ (magit-rev-format "%h" pull))
+ (insert (propertize it 'face 'magit-hash) ?\s))
+ (insert (propertize pull 'face
+ (if (string= (magit-get "branch" branch "remote") ".")
+ 'magit-branch-local
+ 'magit-branch-remote)))
+ (insert ?\s)
+ (if (magit-rev-verify pull)
+ (insert (or (magit-rev-format "%s" pull) ""))
+ (insert (propertize "is missing" 'face 'font-lock-warning-face)))
+ (insert ?\n))))
+
+(cl-defun magit-insert-push-branch-header
+ (&optional (branch (magit-get-current-branch))
+ (push (magit-get-push-branch branch)))
+ "Insert a header line about the branch the current branch is pushed to."
+ (when push
+ (magit-insert-section (branch push)
+ (insert (format "%-10s" "Push: "))
+ (--when-let (and magit-status-show-hashes-in-headers
+ (magit-rev-format "%h" push))
+ (insert (propertize it 'face 'magit-hash) ?\s))
+ (insert (propertize push 'face 'magit-branch-remote) ?\s)
+ (if (magit-rev-verify push)
+ (insert (or (magit-rev-format "%s" push) ""))
+ (insert (propertize "is missing" 'face 'font-lock-warning-face)))
+ (insert ?\n))))
+
+(defun magit-insert-tags-header ()
+ "Insert a header line about the current and/or next tag."
+ (let* ((this-tag (magit-get-current-tag nil t))
+ (next-tag (magit-get-next-tag nil t))
+ (this-cnt (cadr this-tag))
+ (next-cnt (cadr next-tag))
+ (this-tag (car this-tag))
+ (next-tag (car next-tag))
+ (both-tags (and this-tag next-tag t)))
+ (when (or this-tag next-tag)
+ (magit-insert-section (tag (or this-tag next-tag))
+ (insert (format "%-10s" (if both-tags "Tags: " "Tag: ")))
+ (when this-tag
+ (insert (magit-format-status-tag-sentence this-tag this-cnt nil)))
+ (when both-tags
+ (insert ", "))
+ (when next-tag
+ (insert (magit-format-status-tag-sentence next-tag next-cnt t)))
+ (insert ?\n)))))
+
+(defun magit-format-status-tag-sentence (tag count next)
+ (concat (propertize tag 'face 'magit-tag)
+ (and (> count 0)
+ (format " (%s)"
+ (propertize (format "%s" count) 'face
+ (if next 'magit-tag 'magit-branch-local))))))
+
+(defun magit-insert-diff-filter-header ()
+ "Insert a header line showing the effective diff filters."
+ (when magit-diff-section-file-args
+ (magit-insert-section (filter 'diff)
+ (insert (propertize (format "%-10s" "Filter! ")
+ 'face 'magit-section-heading))
+ (insert (mapconcat #'identity magit-diff-section-file-args " "))
+ (insert ?\n))))
+
+(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked)
+
+(defvar magit-untracked-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map "s" 'magit-stage)
+ map)
+ "Keymap for the `untracked' section.")
+
+(defun magit-insert-untracked-files ()
+ "Maybe insert a list or tree 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\"."
+ (let ((show (or (magit-get "status.showUntrackedFiles") "normal")))
+ (unless (equal show "no")
+ (if (equal show "all")
+ (-when-let (files (magit-untracked-files))
+ (magit-insert-section (untracked)
+ (magit-insert-heading "Untracked files:")
+ (magit-insert-un/tracked-files-1 files nil)
+ (insert ?\n)))
+ (-when-let
+ (files (--mapcat (and (eq (aref it 0) ??)
+ (list (substring it 3)))
+ (magit-git-items "status" "-z" "--porcelain")))
+ (magit-insert-section (untracked)
+ (magit-insert-heading "Untracked files:")
+ (dolist (file files)
+ (magit-insert-section (file file)
+ (insert (propertize file 'face 'magit-filename) ?\n)))
+ (insert ?\n)))))))
+
+(defun magit-insert-un/tracked-files-1 (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 'face 'magit-filename) ?\n)))
+ (magit-insert-section (file dir t)
+ (insert (propertize dir 'file 'magit-filename) ?\n)
+ (magit-insert-heading)
+ (setq files (magit-insert-un/tracked-files-1 files dir))))))
+ files)
+
+;;;;; Auxiliary Status Sections
+
+(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked)
+
+(defun magit-insert-tracked-files ()
+ "Insert a tree of tracked files."
+ (-when-let (files (magit-list-files))
+ (magit-insert-section (tracked nil t)
+ (magit-insert-heading "Tracked files:")
+ (magit-insert-un/tracked-files-1 files nil)
+ (insert ?\n))))
+
+(defun magit-insert-user-header ()
+ "Insert a header line about the current user."
+ (let ((name (magit-get "user.name"))
+ (email (magit-get "user.email")))
+ (when (and name email)
+ (magit-insert-section (user name)
+ (insert (format "%-10s" "User: "))
+ (insert (propertize name 'face 'magit-log-author))
+ (insert " <" email ">\n")))))
+
+(defun magit-insert-repo-header ()
+ "Insert a header line showing the path to the repository top-level."
+ (let ((topdir (magit-toplevel)))
+ (magit-insert-section (repo topdir)
+ (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir))))))
+
+(defun magit-insert-remote-header ()
+ "Insert a header line about the remote of the current branch.
+
+If no remote is configured for the current branch, then fall back
+showing the \"origin\" remote, or if that does not exist the first
+remote in alphabetic order."
+ (-when-let* ((name (or (magit-get-remote)
+ (let ((remotes (magit-list-remotes)))
+ (or (car (member "origin" remotes))
+ (car remotes)))))
+ ;; Under certain configurations it's possible for url
+ ;; to be nil, when name is not, see #2858.
+ (url (magit-get "remote" name "url")))
+ (magit-insert-section (remote name)
+ (insert (format "%-10s" "Remote: "))
+ (insert (propertize name 'face 'magit-branch-remote) ?\s)
+ (insert url ?\n))))
+
+;;;;; Status Miscellaneous
+
+(defun ido-enter-magit-status ()
+ "Drop into `magit-status' from file switching.
+
+To make this command available use something like:
+
+ (add-hook \\='ido-setup-hook
+ (lambda ()
+ (define-key ido-completion-map
+ (kbd \"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:
+
+ (define-key ido-common-completion-map
+ (kbd \"C-x g\") 'ido-enter-magit-status)"
+ (interactive)
+ (with-no-warnings ; FIXME these are internal variables
+ (setq ido-exit 'fallback fallback 'magit-status))
+ (exit-minibuffer))
+
+(defun magit-status-maybe-update-revision-buffer (&optional _)
+ "When moving in the status buffer, update the revision buffer.
+If there is no revision buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-status-mode)
+ (magit-log-maybe-update-revision-buffer-1)))
+
+(defun magit-status-maybe-update-blob-buffer (&optional _)
+ "When moving in the status buffer, update the blob buffer.
+If there is no blob buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-status-mode)
+ (magit-log-maybe-update-blob-buffer-1)))
+
+;;;; Refs Mode
+
+(defvar magit-refs-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "\C-y" 'magit-refs-set-show-commit-count)
+ map)
+ "Keymap for `magit-refs-mode'.")
+
+(define-derived-mode magit-refs-mode magit-mode "Magit Refs"
+ "Mode which lists and compares references.
+
+This mode is documented in info node `(magit)References buffer'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-section-toggle] to expand or hide the section at point.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit or branch at point.
+
+Type \\[magit-branch-popup] to see available branch commands.
+Type \\[magit-merge-popup] to merge the branch or commit at point.
+Type \\[magit-cherry-pick-popup] to apply the commit at point.
+Type \\[magit-reset] to reset HEAD to the commit at point.
+
+\\{magit-refs-mode-map}"
+ :group 'magit-refs
+ (hack-dir-local-variables-non-file-buffer))
+
+;;;###autoload (autoload 'magit-show-refs-popup "magit" nil t)
+(magit-define-popup magit-show-refs-popup
+ "Popup console for `magit-show-refs'."
+ 'magit-refs
+ :man-page "git-branch"
+ :switches '((?m "Merged to HEAD" "--merged")
+ (?M "Merged to master" "--merged=master")
+ (?n "Not merged to HEAD" "--no-merged")
+ (?N "Not merged to master" "--no-merged=master"))
+ :options '((?c "Contains" "--contains=" magit-read-branch-or-commit)
+ (?m "Merged" "--merged=" magit-read-branch-or-commit)
+ (?n "Not merged" "--no-merged=" magit-read-branch-or-commit)
+ (?s "Sort" "--sort=" magit-read-ref-sort))
+ :actions '((?y "Show refs, comparing them with HEAD"
+ magit-show-refs-head)
+ (?c "Show refs, comparing them with current branch"
+ magit-show-refs-current)
+ (?o "Show refs, comparing them with other branch"
+ magit-show-refs))
+ :default-action 'magit-show-refs-head
+ :use-prefix 'popup)
+
+(defun magit-read-ref-sort (prompt initial-input)
+ (magit-completing-read prompt
+ '("-committerdate" "-authordate"
+ "committerdate" "authordate")
+ nil nil initial-input))
+
+;;;###autoload
+(defun magit-show-refs-head (&optional args)
+ "List and compare references in a dedicated buffer.
+Refs are compared with `HEAD'."
+ (interactive (list (magit-show-refs-arguments)))
+ (magit-show-refs nil args))
+
+;;;###autoload
+(defun magit-show-refs-current (&optional args)
+ "List and compare references in a dedicated buffer.
+Refs are compared with the current branch or `HEAD' if
+it is detached."
+ (interactive (list (magit-show-refs-arguments)))
+ (magit-show-refs (magit-get-current-branch) args))
+
+;;;###autoload
+(defun magit-show-refs (&optional ref args)
+ "List and compare references in a dedicated buffer.
+Refs are compared with a branch read form the user."
+ (interactive (list (magit-read-other-branch "Compare with")
+ (magit-show-refs-arguments)))
+ (magit-mode-setup #'magit-refs-mode ref args))
+
+(defun magit-refs-refresh-buffer (&rest _ignore)
+ (setq magit-set-buffer-margin-refresh (not magit-show-margin))
+ (unless (magit-rev-verify (or (car magit-refresh-args) "HEAD"))
+ (setq magit-refs-show-commit-count nil))
+ (magit-insert-section (branchbuf)
+ (run-hooks 'magit-refs-sections-hook)))
+
+(defun magit-insert-branch-description ()
+ "Insert header containing the description of the current branch.
+Insert a header line with the name and description of the
+current branch. The description is taken from the Git variable
+`branch.<NAME>.description'; if that is undefined then no header
+line is inserted at all."
+ (let ((branch (magit-get-current-branch)))
+ (--when-let (magit-git-lines
+ "config" (format "branch.%s.description" branch))
+ (magit-insert-section (branchdesc branch t)
+ (magit-insert-heading branch ": " (car it))
+ (insert (mapconcat 'identity (cdr it) "\n"))
+ (insert "\n\n")))))
+
+(defconst magit-refs-branch-line-re
+ (concat "^"
+ "\\(?:[ \\*]\\) "
+ "\\(?1:([^)]+)\\|[^ ]+?\\)" ; branch
+ "\\(?: +\\)"
+ "\\(?2:[0-9a-fA-F]+\\) " ; sha1
+ "\\(?:\\["
+ "\\(?4:[^:]+\\)" ; upstream
+ "\\(?:: \\(?:"
+ "\\(?7:gone\\)\\|" ; gone
+ "\\(?:ahead \\(?5:[0-9]+\\)\\)?" ; ahead
+ "\\(?:, \\)?"
+ "\\(?:behind \\(?6:[0-9]+\\)\\)?" ; behind
+ "\\)\\)?"
+ "\\] \\)?"
+ "\\(?3:.*\\)")) ; message
+
+(defconst magit-refs-symref-line-re "^ \\([^ ]+\\) +-> \\(.+\\)")
+
+(defvar magit-refs-local-branch-format "%4c %-25n %U%m\n"
+ "Format used for local branches in refs buffers.")
+(defvar magit-refs-remote-branch-format "%4c %-25n %m\n"
+ "Format used for remote branches in refs buffers.")
+(defvar magit-refs-symref-format "%4c %-25n -> %m\n"
+ "Format used for symrefs in refs buffers.")
+(defvar magit-refs-tags-format "%4c %-25n %m\n"
+ "Format used for tags in refs buffers.")
+(defvar magit-refs-indent-cherry-lines 3
+ "Indentation of cherries in refs buffers.")
+
+(defvar magit-branch-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-visit-ref)
+ (define-key map [remap magit-delete-thing] 'magit-branch-delete)
+ (define-key map "R" 'magit-branch-rename)
+ map)
+ "Keymap for `branch' sections.")
+
+(defvar magit-remote-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-delete-thing] 'magit-remote-remove)
+ (define-key map "R" 'magit-remote-rename)
+ map)
+ "Keymap for `remote' sections.")
+
+(defun magit-refs-set-show-commit-count ()
+ "Change for which refs the commit count is shown."
+ (interactive)
+ (setq-local magit-refs-show-commit-count
+ (magit-read-char-case "Show commit counts for " nil
+ (?a "[a]ll refs" 'all)
+ (?b "[b]ranches only" t)
+ (?n "[n]othing" nil)))
+ (magit-refresh))
+
+(defun magit-visit-ref ()
+ "Visit the reference or revision at point.
+
+In most places use `magit-show-commit' to visit the reference or
+revision at point.
+
+In `magit-refs-mode', when there is a reference at point, instead
+checkout that reference. When option `magit-visit-ref-create' is
+non-nil and point is on remote branch, then create a local branch
+with the same name and check it out.
+
+With a prefix argument only focus on the reference at point, i.e.
+the commit counts and cherries are updated to be relative to that
+reference, but it is not checked out."
+ (interactive)
+ (if (derived-mode-p 'magit-refs-mode)
+ (magit-section-case
+ (([branch * branchbuf]
+ [tag * branchbuf])
+ (let ((ref (magit-section-value (magit-current-section))))
+ (if current-prefix-arg
+ (magit-show-refs ref)
+ (if (magit-section-match [branch remote])
+ (let ((start ref)
+ (arg "-b"))
+ (string-match "^[^/]+/\\(.+\\)" ref)
+ (setq ref (match-string 1 ref))
+ (when (magit-branch-p ref)
+ (if (yes-or-no-p
+ (format "Branch %s already exists. Recreate it?" ref))
+ (setq arg "-B")
+ (user-error "Abort")))
+ (magit-run-git "checkout" arg ref start))
+ (magit-run-git "checkout" ref))
+ (setcar magit-refresh-args ref)
+ (magit-refresh))))
+ ([commit * branchbuf]
+ (call-interactively #'magit-show-commit)))
+ (call-interactively #'magit-show-commit)))
+
+(defun magit-insert-local-branches ()
+ "Insert sections showing all local branches."
+ (magit-insert-section (local nil)
+ (magit-insert-heading "Branches:")
+ (let ((current (magit-get-current-branch))
+ (branches (magit-list-local-branch-names)))
+ (dolist (line (magit-git-lines "branch" "-vv"
+ (cadr magit-refresh-args)))
+ (cond
+ ((string-match magit-refs-branch-line-re line)
+ (magit-bind-match-strings
+ (branch hash message upstream ahead behind gone) line
+ (when (string-match-p "(HEAD detached" branch)
+ (setq branch nil))
+ (magit-insert-branch
+ branch magit-refs-local-branch-format current branches
+ 'magit-branch-local hash message upstream ahead behind gone)))
+ ((string-match magit-refs-symref-line-re line)
+ (magit-bind-match-strings (symref ref) line
+ (magit-insert-symref symref ref 'magit-branch-local))))))
+ (insert ?\n)))
+
+(defun magit-insert-remote-branches ()
+ "Insert sections showing all remote-tracking branches."
+ (dolist (remote (magit-list-remotes))
+ (magit-insert-section (remote remote)
+ (magit-insert-heading
+ (let ((pull (magit-get "remote" remote "url"))
+ (push (magit-get "remote" remote "pushurl")))
+ (format "%s (%s):" (capitalize remote)
+ (concat pull (and pull push ", ") push))))
+ (let ((current (magit-get-current-branch))
+ (branches (magit-list-local-branch-names)))
+ (dolist (line (magit-git-lines "branch" "-vvr"
+ (cadr magit-refresh-args)))
+ (cond
+ ((string-match magit-refs-branch-line-re line)
+ (magit-bind-match-strings (branch hash message) line
+ (when (string-match-p (format "^%s/" remote) branch)
+ (magit-insert-branch
+ branch magit-refs-remote-branch-format current branches
+ 'magit-branch-remote hash message))))
+ ((string-match magit-refs-symref-line-re line)
+ (magit-bind-match-strings (symref ref) line
+ (magit-insert-symref symref ref 'magit-branch-remote))))))
+ (insert ?\n))))
+
+(defun magit-insert-branch (branch format &rest args)
+ "For internal use, don't add to a hook."
+ (unless magit-refs-show-commit-count
+ (setq format (replace-regexp-in-string "%[0-9]\\([cC]\\)" "%1\\1" format t)))
+ (if (equal branch "HEAD")
+ (magit-insert-section it (commit (magit-rev-parse "HEAD") t)
+ (apply #'magit-insert-branch-1 it nil format args))
+ (magit-insert-section it (branch branch t)
+ (apply #'magit-insert-branch-1 it branch format args))))
+
+(defun magit-insert-branch-1
+ (section branch format current branches face
+ &optional hash message upstream ahead behind gone)
+ "For internal use, don't add to a hook."
+ (let* ((head (or (car magit-refresh-args) current "HEAD"))
+ (count (and branch
+ (magit-refs-format-commit-count branch head format)))
+ (mark (cond ((or (equal branch head)
+ (and (not branch) (equal head "HEAD")))
+ (if (equal branch current)
+ (propertize "@" 'face 'magit-head)
+ (propertize "#" 'face 'magit-tag)))
+ ((equal branch current)
+ (propertize "." 'face 'magit-head)))))
+ (when upstream
+ (setq upstream (propertize upstream 'face
+ (if (member upstream branches)
+ 'magit-branch-local
+ 'magit-branch-remote))))
+ (magit-insert-heading
+ (format-spec
+ format
+ `((?a . ,(or ahead ""))
+ (?b . ,(or behind ""))
+ (?c . ,(or mark count ""))
+ (?C . ,(or mark " "))
+ (?h . ,(or (propertize hash 'face 'magit-hash) ""))
+ (?m . ,(or message ""))
+ (?n . ,(propertize (or branch "(detached)") 'face face))
+ (?u . ,(or upstream ""))
+ (?U . ,(if upstream
+ (format (propertize "[%s%s] " 'face 'magit-dimmed)
+ upstream
+ (cond
+ (gone
+ (concat ": " (propertize gone 'face 'error)))
+ ((or ahead behind)
+ (concat ": "
+ (and ahead (format "ahead %s" ahead))
+ (and ahead behind ", ")
+ (and behind (format "behind %s" behind))))
+ (t "")))
+ "")))))
+ (when magit-show-margin
+ (magit-refs-format-margin branch))
+ (magit-refs-insert-cherry-commits head branch section)))
+
+(defun magit-insert-symref (symref ref face)
+ "For internal use, don't add to a hook."
+ (magit-insert-section (commit symref)
+ (insert
+ (format-spec (if magit-refs-show-commit-count
+ magit-refs-symref-format
+ (replace-regexp-in-string "%[0-9]\\([cC]\\)" "%1\\1"
+ magit-refs-symref-format t))
+ `((?c . "")
+ (?n . ,(propertize symref 'face face))
+ (?m . ,(propertize ref 'face face)))))))
+
+(defvar magit-tag-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-visit-ref)
+ (define-key map [remap magit-delete-thing] 'magit-tag-delete)
+ map)
+ "Keymap for `tag' sections.")
+
+(defun magit-insert-tags ()
+ "Insert sections showing all tags."
+ (-when-let (tags (magit-git-lines "tag" "-l" "-n"))
+ (magit-insert-section (tags)
+ (magit-insert-heading "Tags:")
+ (let ((head (or (car magit-refresh-args)
+ (magit-get-current-branch)
+ "HEAD"))
+ (format (if magit-refs-show-commit-count
+ magit-refs-tags-format
+ (replace-regexp-in-string
+ "%[0-9]\\([cC]\\)" "%1\\1" magit-refs-tags-format t))))
+ (dolist (tag (nreverse tags))
+ (string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag)
+ (let* ((message (match-string 2 tag))
+ (tag (match-string 1 tag))
+ (count (magit-refs-format-commit-count tag head format t))
+ (mark (and (equal tag head)
+ (propertize "#" 'face 'magit-tag))))
+ (magit-insert-section section (tag tag t)
+ (magit-insert-heading
+ (format-spec format
+ `((?n . ,(propertize tag 'face 'magit-tag))
+ (?c . ,(or mark count ""))
+ (?m . ,(or message "")))))
+ (when (and magit-show-margin
+ (eq magit-refs-show-margin 'all))
+ (magit-refs-format-margin (concat tag "^{commit}")))
+ (magit-refs-insert-cherry-commits head tag section)))))
+ (insert ?\n))))
+
+(defun magit-refs-insert-cherry-commits (head ref section)
+ (if (magit-section-hidden section)
+ (setf (magit-section-washer section)
+ (apply-partially #'magit-refs-insert-cherry-commits-1
+ head ref section))
+ (magit-refs-insert-cherry-commits-1 head ref section)))
+
+(defun magit-refs-insert-cherry-commits-1 (head ref section)
+ (let ((start (point)))
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" "--abbrev" head ref magit-refresh-args)
+ (unless (= (point) start)
+ (insert (propertize "\n" 'magit-section section)))))
+
+(defun magit-refs-format-commit-count (ref head format &optional tag-p)
+ (and (string-match-p "%-?[0-9]+c" format)
+ (if tag-p
+ (eq magit-refs-show-commit-count 'all)
+ magit-refs-show-commit-count)
+ (let ((count (cadr (magit-rev-diff-count head ref))))
+ (and (> count 0)
+ (propertize (number-to-string count) 'face 'magit-dimmed)))))
+
+(defun magit-refs-format-margin (commit)
+ (save-excursion
+ (goto-char (line-beginning-position 0))
+ (let ((line (magit-rev-format "%ct%cN" commit)))
+ (magit-format-log-margin (substring line 10)
+ (substring line 0 10)))))
+
+;;;; Files
+
+;;;###autoload
+(defun magit-find-file (rev file)
+ "View FILE from REV.
+Switch to a buffer visiting blob REV:FILE,
+creating one if none already exists."
+ (interactive (magit-find-file-read-args "Find file"))
+ (switch-to-buffer (magit-find-file-noselect rev file)))
+
+;;;###autoload
+(defun magit-find-file-other-window (rev file)
+ "View FILE from REV, in another window.
+Like `magit-find-file', but create a new window or reuse an
+existing one."
+ (interactive (magit-find-file-read-args "Find file in other window"))
+ (switch-to-buffer-other-window (magit-find-file-noselect rev file)))
+
+(defun magit-find-file-read-args (prompt)
+ (let ((rev (magit-read-branch-or-commit "Find file from revision")))
+ (list rev (magit-read-file-from-rev rev prompt))))
+
+(defvar magit-read-file-hist nil)
+
+(defun magit-read-file-from-rev (rev prompt &optional default)
+ (let ((files (magit-revision-files rev)))
+ (magit-completing-read
+ prompt files nil t nil 'magit-read-file-hist
+ (car (member (or default (magit-current-file)) files)))))
+
+(defun magit-read-changed-file (rev-or-range prompt &optional default)
+ (magit-read-file-choice
+ prompt
+ (magit-changed-files rev-or-range)
+ default
+ (concat "No file changed in " rev-or-range)))
+
+(defun magit-get-revision-buffer (rev file &optional create)
+ (funcall (if create 'get-buffer-create 'get-buffer)
+ (format "%s.~%s~" file (if (equal rev "") "index"
+ (subst-char-in-string ?/ ?_ rev)))))
+
+(defun magit-get-revision-buffer-create (rev file)
+ (magit-get-revision-buffer rev file t))
+
+(defun magit-revert-rev-file-buffer (_ignore-auto noconfirm)
+ (when (or noconfirm
+ (and (not (buffer-modified-p))
+ (catch 'found
+ (dolist (regexp revert-without-query)
+ (when (string-match regexp magit-buffer-file-name)
+ (throw 'found t)))))
+ (yes-or-no-p (format "Revert buffer from git %s? "
+ (if (equal magit-buffer-refname "") "{index}"
+ (concat "revision " magit-buffer-refname)))))
+ (let* ((inhibit-read-only t)
+ (default-directory (magit-toplevel))
+ (file (file-relative-name magit-buffer-file-name))
+ (coding-system-for-read (or coding-system-for-read 'undecided)))
+ (erase-buffer)
+ (magit-git-insert "cat-file" "-p" (concat magit-buffer-refname ":" file))
+ (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)))
+ (normal-mode t))
+ (setq buffer-read-only t)
+ (set-buffer-modified-p nil)
+ (goto-char (point-min))))
+
+(defun magit-find-file-noselect-1 (rev file hookvar &optional revert)
+ "Read FILE from REV into a buffer and return the buffer.
+FILE must be relative to the top directory of the repository.
+An empty REV stands for index."
+ (let ((topdir (magit-toplevel)))
+ (when (file-name-absolute-p file)
+ (setq file (file-relative-name file topdir)))
+ (with-current-buffer (magit-get-revision-buffer-create rev file)
+ (when (or (not magit-buffer-file-name)
+ (if (eq revert 'ask-revert)
+ (y-or-n-p (format "%s already exists; revert it? "
+ (buffer-name))))
+ revert)
+ (setq magit-buffer-revision
+ (if (string= rev "") "{index}" (magit-rev-format "%H" rev))
+ magit-buffer-refname rev
+ magit-buffer-file-name (expand-file-name file topdir))
+ (setq default-directory (file-name-directory magit-buffer-file-name))
+ (setq-local revert-buffer-function #'magit-revert-rev-file-buffer)
+ (revert-buffer t t)
+ (run-hooks hookvar))
+ (current-buffer))))
+
+(defvar magit-find-file-hook nil)
+(add-hook 'magit-find-file-hook #'magit-blob-mode)
+
+(defun magit-find-file-noselect (rev file)
+ "Read FILE from REV into a buffer and return the buffer.
+FILE must be relative to the top directory of the repository."
+ (magit-find-file-noselect-1 rev file 'magit-find-file-hook))
+
+(defvar magit-find-index-hook nil)
+
+(defun magit-find-file-index-noselect (file &optional revert)
+ "Read FILE from the index into a buffer and return the buffer.
+FILE must to be relative to the top directory of the repository."
+ (magit-find-file-noselect-1 "" file 'magit-find-index-hook
+ (or revert 'ask-revert)))
+
+(defun magit-update-index ()
+ "Update the index with the contents of the current buffer.
+The current buffer has to be visiting a file in the index, which
+is done using `magit-find-index-noselect'."
+ (interactive)
+ (let ((file (magit-file-relative-name)))
+ (unless (equal magit-buffer-refname "")
+ (user-error "%s isn't visiting the index" file))
+ (if (y-or-n-p (format "Update index with contents of %s" (buffer-name)))
+ (let ((index (make-temp-file "index"))
+ (buffer (current-buffer)))
+ (when magit-wip-before-change-mode
+ (magit-wip-commit-before-change (list file) " before un-/stage"))
+ (let ((coding-system-for-write buffer-file-coding-system))
+ (with-temp-file index
+ (insert-buffer-substring buffer)))
+ (magit-with-toplevel
+ (magit-call-git "update-index" "--cacheinfo"
+ (substring (magit-git-string "ls-files" "-s" file)
+ 0 6)
+ (magit-git-string "hash-object" "-t" "blob" "-w"
+ (concat "--path=" file)
+ "--" index)
+ file))
+ (set-buffer-modified-p nil)
+ (when magit-wip-after-apply-mode
+ (magit-wip-commit-after-apply (list file) " after un-/stage")))
+ (message "Abort")))
+ (--when-let (magit-mode-get-buffer 'magit-status-mode)
+ (with-current-buffer it (magit-refresh)))
+ t)
+
+;;;###autoload
+(defun magit-dired-jump (&optional other-window)
+ "Visit file at point using Dired.
+With a prefix argument, visit in another window. If there
+is no file at point then instead visit `default-directory'."
+ (interactive "P")
+ (dired-jump other-window (-if-let (file (magit-file-at-point))
+ (progn (setq file (expand-file-name file))
+ (if (file-directory-p file)
+ (concat file "/.")
+ file))
+ (concat default-directory "/."))))
+
+;;;###autoload
+(defun magit-checkout-file (rev file)
+ "Checkout FILE from REV."
+ (interactive
+ (let ((rev (magit-read-branch-or-commit
+ "Checkout from revision" magit-buffer-revision)))
+ (list rev (magit-read-file-from-rev rev "Checkout file"))))
+ (magit-with-toplevel
+ (magit-run-git "checkout" rev "--" file)))
+
+;;; Manipulate
+;;;; Init
+
+;;;###autoload
+(defun magit-init (directory)
+ "Initialize a Git repository, then show its status.
+
+If the directory is below an existing repository, then the user
+has to confirm that a new one should be created inside. If the
+directory is the root of the existing repository, then the user
+has to confirm that it should be reinitialized.
+
+Non-interactively DIRECTORY is (re-)initialized unconditionally."
+ (interactive
+ (let ((directory (file-name-as-directory
+ (expand-file-name
+ (read-directory-name "Create repository in: ")))))
+ (-when-let (toplevel (magit-toplevel directory))
+ (setq toplevel (expand-file-name toplevel))
+ (unless (y-or-n-p (if (string-equal toplevel directory)
+ (format "Reinitialize existing repository %s? "
+ directory)
+ (format "%s is a repository. Create another in %s? "
+ toplevel directory)))
+ (user-error "Abort")))
+ (list directory)))
+ ;; `git init' does not understand the meaning of "~"!
+ (magit-call-git "init" (magit-convert-filename-for-git
+ (expand-file-name directory)))
+ (magit-status-internal directory))
+
+;;;; Branch
+;;;;; Branch Popup
+
+;;;###autoload (autoload 'magit-branch-popup "magit" nil t)
+(magit-define-popup magit-branch-popup
+ "Popup console for branch commands."
+ 'magit-commands
+ :man-page "git-branch"
+ :actions '((?b "Checkout" magit-checkout)
+ (?n "Create new branch" magit-branch)
+ (?C "Configure..." magit-branch-config-popup)
+ (?c "Checkout new branch" magit-branch-and-checkout)
+ (?s "Create new spin-off" magit-branch-spinoff)
+ (?m "Rename" magit-branch-rename)
+ (?w "Checkout new worktree" magit-worktree-checkout)
+ (?W "Create new worktree" magit-worktree-branch)
+ (?x "Reset" magit-branch-reset) nil nil
+ (?k "Delete" magit-branch-delete))
+ :default-action 'magit-checkout
+ :max-action-columns 3
+ :setup-function 'magit-branch-popup-setup)
+
+(defvar magit-branch-config-variables)
+
+(defun magit-branch-popup-setup (val def)
+ (magit-popup-default-setup val def)
+ (when magit-branch-popup-show-variables
+ (magit-popup-put :variables (magit-popup-convert-variables
+ val magit-branch-config-variables))
+ (use-local-map (copy-keymap magit-popup-mode-map))
+ (dolist (ev (-filter #'magit-popup-event-p (magit-popup-get :variables)))
+ (local-set-key (vector (magit-popup-event-key ev))
+ 'magit-invoke-popup-action))))
+
+;;;###autoload
+(defun magit-checkout (revision)
+ "Checkout REVISION, updating the index and the working tree.
+If REVISION is a local branch then that becomes the current
+branch. If it is something else then `HEAD' becomes detached.
+Checkout fails if the working tree or the staging area contain
+changes.
+\n(git checkout REVISION)."
+ (interactive (list (magit-read-other-branch-or-commit "Checkout")))
+ (magit-run-git "checkout" revision))
+
+;;;###autoload
+(defun magit-branch (branch start-point &optional args)
+ "Create BRANCH at branch or revision START-POINT.
+\n(git branch [ARGS] BRANCH START-POINT)."
+ (interactive (magit-branch-read-args "Create branch"))
+ (magit-call-git "branch" args branch start-point)
+ (magit-branch-maybe-adjust-upstream branch start-point)
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-branch-and-checkout (branch start-point &optional args)
+ "Create and checkout BRANCH at branch or revision START-POINT.
+\n(git checkout [ARGS] -b BRANCH START-POINT)."
+ (interactive (magit-branch-read-args "Create and checkout branch"))
+ (if (string-match-p "^stash@{[0-9]+}$" start-point)
+ (magit-run-git "stash" "branch" branch start-point)
+ (magit-call-git "checkout" args "-b" branch start-point)
+ (magit-branch-maybe-adjust-upstream branch start-point)
+ (magit-refresh)))
+
+(defun magit-branch-maybe-adjust-upstream (branch start-point)
+ (--when-let
+ (or (and (magit-get-upstream-branch branch)
+ (magit-get-indirect-upstream-branch start-point))
+ (and (magit-remote-branch-p start-point)
+ (let ((name (cdr (magit-split-branch-name start-point))))
+ (car (--first (if (listp (cdr it))
+ (not (member name (cdr it)))
+ (string-match-p (cdr it) name))
+ magit-branch-adjust-remote-upstream-alist)))))
+ (magit-call-git "branch" (concat "--set-upstream-to=" it) branch)))
+
+;;;###autoload
+(defun magit-branch-orphan (branch start-point &optional args)
+ "Create and checkout an orphan BRANCH with contents from revision START-POINT.
+\n(git checkout --orphan [ARGS] BRANCH START-POINT)."
+ (interactive (magit-branch-read-args "Create and checkout orphan branch"))
+ (magit-run-git "checkout" "--orphan" args branch start-point))
+
+(defun magit-branch-read-args (prompt)
+ (let ((args (magit-branch-arguments)))
+ (if magit-branch-read-upstream-first
+ (let* ((default (and (or (memq this-command magit-no-confirm-default)
+ (memq magit-current-popup-action
+ magit-no-confirm-default))
+ (magit--default-starting-point)))
+ (choice (or default
+ (magit-read-starting-point prompt))))
+ (if (magit-rev-verify choice)
+ (list (magit-read-string-ns
+ (if default
+ (format "%s (starting at %s)" prompt choice)
+ "Branch name")
+ (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 args)
+ (if (eq magit-branch-read-upstream-first 'fallback)
+ (list choice
+ (magit-read-starting-point (concat prompt " " choice))
+ args)
+ (user-error "Not a valid starting-point: %s" choice))))
+ (let ((branch (magit-read-string-ns (concat prompt " named"))))
+ (list branch
+ (magit-read-starting-point (concat prompt " " branch))
+ args)))))
+
+;;;###autoload
+(defun magit-branch-spinoff (branch &optional from &rest args)
+ "Create new branch from the unpushed commits.
+
+Create and checkout a new branch starting at and tracking the
+current branch. That branch in turn is reset to the last commit
+it shares with its upstream. If the current branch has no
+upstream or no unpushed commits, then the new branch is created
+anyway and the previously current branch is not touched.
+
+This is useful to create a feature branch after work has already
+began on the old branch (likely but not necessarily \"master\").
+
+If the current branch is a member of the value of option
+`magit-branch-prefer-remote-upstream' (which see), then the
+current branch will be used as the starting point as usual, but
+the upstream of the starting-point may be used as the upstream
+of the new branch, instead of the starting-point itself.
+
+If optional FROM is non-nil, then the source branch is reset to
+that commit, instead of to the last commit it shares with its
+upstream. Interactively, FROM is non-nil, when the region
+selects some commits, and among those commits, FROM it is the
+commit that is the fewest commits ahead of the source branch.
+
+The commit at the other end of the selection actually does not
+matter, all commits between FROM and `HEAD' are moved to the new
+branch. If FROM is not reachable from `HEAD' or is reachable
+from the source branch's upstream, then an error is raised."
+ (interactive (list (magit-read-string "Spin off branch")
+ (car (last (magit-region-values 'commit)))
+ (magit-branch-arguments)))
+ (when (magit-branch-p branch)
+ (user-error "Cannot spin off %s. It already exists" branch))
+ (-if-let (current (magit-get-current-branch))
+ (let ((tracked (magit-get-upstream-branch current))
+ base)
+ (when from
+ (unless (magit-rev-ancestor-p from current)
+ (user-error "Cannot spin off %s. %s is not reachable from %s"
+ branch from current))
+ (when (and tracked
+ (magit-rev-ancestor-p from tracked))
+ (user-error "Cannot spin off %s. %s is ancestor of upstream %s"
+ branch from tracked)))
+ (magit-call-git "checkout" args "-b" branch current)
+ (--when-let (magit-get-indirect-upstream-branch current)
+ (magit-call-git "branch" "--set-upstream-to" it branch))
+ (when (and tracked
+ (setq base
+ (if from
+ (concat from "^")
+ (magit-git-string "merge-base" current tracked)))
+ (not (magit-rev-eq base current)))
+ (magit-call-git "update-ref" "-m"
+ (format "reset: moving to %s" base)
+ (concat "refs/heads/" current) base))
+ (magit-refresh))
+ (magit-run-git "checkout" "-b" branch)))
+
+;;;###autoload
+(defun magit-branch-reset (branch to &optional args set-upstream)
+ "Reset a branch to the tip of another branch or any other commit.
+
+When the branch being reset is the current branch, then do a
+hard reset. If there are any uncommitted changes, then the user
+has to confirming the reset because those changes would be lost.
+
+This is useful when you have started work on a feature branch but
+realize it's all crap and want to start over.
+
+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-branch-at-point))
+ (branch (magit-read-local-branch "Reset branch" atpoint)))
+ (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-branch-arguments)
+ current-prefix-arg)))
+ (unless (member "--force" args)
+ (setq args (cons "--force" args)))
+ (if (equal branch (magit-get-current-branch))
+ (if (and (magit-anything-modified-p)
+ (not (yes-or-no-p "Uncommitted changes will be lost. Proceed?")))
+ (user-error "Abort")
+ (magit-reset-hard to)
+ (when (and set-upstream (magit-branch-p to))
+ (magit-set-branch*merge/remote branch to)))
+ (magit-branch branch to args)))
+
+;;;###autoload
+(defun magit-branch-delete (branches &optional force)
+ "Delete one or multiple branches.
+If the region marks multiple branches, then offer to delete
+those, otherwise prompt for a single branch to be deleted,
+defaulting to the branch at point."
+ ;; One would expect this to be a command as simple as, for example,
+ ;; `magit-branch-rename'; but it turns out everyone wants to squeeze
+ ;; a bit of extra functionality into this one. And once it's there,
+ ;; you cannot remove it anymore. (I tried, it causes protests.)
+ (interactive
+ (let ((branches (magit-region-values 'branch))
+ (force current-prefix-arg))
+ (if (if (> (length branches) 1)
+ (magit-confirm t nil "Delete %i branches" branches)
+ (setq branches
+ (list (magit-read-branch (if current-prefix-arg
+ "Force delete branch"
+ "Delete branch")
+ (magit-get-previous-branch)))))
+ (unless force
+ (--when-let (-intersection
+ (-union (magit-list-unmerged-branches)
+ (magit-list-unmerged-to-upstream-branches))
+ branches)
+ (if (magit-confirm 'delete-unmerged-branch
+ "Delete unmerged branch %s"
+ "Delete %i unmerged branches" it)
+ (setq force t)
+ (or (setq branches (-difference branches it))
+ (user-error "Abort")))))
+ (user-error "Abort"))
+ (list branches force)))
+ (let* ((refs (-map #'magit-ref-fullname branches))
+ (ambiguous (--filter (not it) refs)))
+ (when ambiguous
+ (user-error
+ "%s ambiguous. Please cleanup using git directly."
+ (let ((len (length ambiguous)))
+ (cond
+ ((= len 1)
+ (format "%s is" (--first (not (magit-ref-fullname it)) branches)))
+ ((= len (length refs))
+ (format "These %s names are" len))
+ (t
+ (format "%s of these names are" len))))))
+ (cond
+ ((string-match "^refs/remotes/\\([^/]+\\)" (car refs))
+ (let* ((remote (match-string 1 (car refs)))
+ (offset (1+ (length remote))))
+ ;; Assume the branches actually still exists on the remote.
+ (magit-run-git-async
+ "push" remote (--map (concat ":" (substring it offset)) branches))
+ ;; If that is not the case, then this deletes the tracking branches.
+ (set-process-sentinel
+ magit-this-process
+ (apply-partially 'magit-delete-remote-branch-sentinel refs))))
+ ((> (length branches) 1)
+ (magit-run-git "branch" (if force "-D" "-d")
+ (delete (magit-get-current-branch) branches)))
+ (t ; And now for something completely different.
+ (let* ((branch (car branches))
+ (prompt (format "Branch %s is checked out. " branch)))
+ (when (equal branch (magit-get-current-branch))
+ (pcase (if (or (equal branch "master")
+ (not (magit-rev-verify "master")))
+ (magit-read-char-case prompt nil
+ (?d "[d]etach HEAD & delete" 'detach)
+ (?a "[a]bort" 'abort))
+ (magit-read-char-case prompt nil
+ (?d "[d]etach HEAD & delete" 'detach)
+ (?c "[c]heckout master & delete" 'master)
+ (?a "[a]bort" 'abort)))
+ (`detach (magit-call-git "checkout" "--detach"))
+ (`master (magit-call-git "checkout" "master"))
+ (`abort (user-error "Abort")))
+ (setq force t))
+ (magit-run-git "branch" (if force "-D" "-d") branch))))))
+
+(put 'magit-branch-delete 'interactive-only t)
+
+(defun magit-delete-remote-branch-sentinel (refs process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (= (process-exit-status process) 0)
+ (magit-process-sentinel process event)
+ (-if-let (rest (-filter #'magit-ref-exists-p refs))
+ (progn
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (setq magit-this-error nil)
+ (message "Some remote branches no longer exist. %s"
+ "Deleting just the local tracking refs instead...")
+ (--each rest (magit-call-git "update-ref" "-d" it))
+ (magit-refresh)
+ (message "Deleting local remote-tracking refs...done"))
+ (magit-process-sentinel process event)))))
+
+;;;###autoload
+(defun magit-branch-rename (old new &optional force)
+ "Rename branch OLD to NEW.
+With prefix, forces the rename even if NEW already exists.
+\n(git branch -m|-M OLD NEW)."
+ (interactive
+ (let ((branch (or (and (memq 'magit-branch-rename magit-no-confirm-default)
+ (or (magit-local-branch-at-point)
+ (magit-get-current-branch)))
+ (magit-read-local-branch "Rename branch"))))
+ (list branch
+ (magit-read-string-ns (format "Rename branch '%s' to" branch)
+ nil 'magit-revision-history)
+ current-prefix-arg)))
+ (unless (string= old new)
+ (magit-run-git "branch" (if force "-M" "-m") old new)))
+
+;;;;; Branch Config Popup
+
+(defvar magit-branch-config-branch nil)
+
+;;;###autoload
+(defun magit-branch-config-popup (branch)
+ "Popup console for setting branch variables."
+ (interactive
+ (list (if (or current-prefix-arg
+ (and (eq magit-current-popup 'magit-branch-popup)
+ magit-branch-popup-show-variables))
+ (magit-read-local-branch "Configure branch")
+ (magit-get-current-branch))))
+ (let ((magit-branch-config-branch branch))
+ (magit-invoke-popup 'magit-branch-config-popup nil nil)))
+
+(defvar magit-branch-config-variables
+ '((lambda ()
+ (concat
+ (propertize "Configure " 'face 'magit-popup-heading)
+ (propertize (magit-branch-config-branch) 'face 'magit-branch-local)))
+ (?d "branch.%s.description"
+ magit-edit-branch*description
+ magit-format-branch*description)
+ (?u "branch.%s.merge"
+ magit-set-branch*merge/remote
+ magit-format-branch*merge/remote)
+ (?r "branch.%s.rebase"
+ magit-cycle-branch*rebase
+ magit-format-branch*rebase)
+ (?p "branch.%s.pushRemote"
+ magit-cycle-branch*pushRemote
+ magit-format-branch*pushRemote)
+ "Configure repository defaults"
+ (?\M-r "pull.rebase"
+ magit-cycle-pull.rebase
+ magit-format-pull.rebase)
+ (?\M-p "remote.pushDefault"
+ magit-cycle-remote.pushDefault
+ magit-format-remote.pushDefault)
+ "Configure branch creation"
+ (?U "branch.autoSetupMerge"
+ magit-cycle-branch*autoSetupMerge
+ magit-format-branch*autoSetupMerge)
+ (?R "branch.autoSetupRebase"
+ magit-cycle-branch*autoSetupRebase
+ magit-format-branch*autoSetupRebase)))
+
+(defvar magit-branch-config-popup
+ `(:man-page "git-branch"
+ :variables ,magit-branch-config-variables
+ :default-action magit-checkout
+ :setup-function magit-branch-config-popup-setup))
+
+(defun magit-branch-config-popup-setup (val def)
+ (magit-popup-default-setup val def)
+ (setq-local magit-branch-config-branch magit-branch-config-branch)
+ (use-local-map (copy-keymap magit-popup-mode-map))
+ (dolist (ev (-filter #'magit-popup-event-p (magit-popup-get :variables)))
+ (local-set-key (vector (magit-popup-event-key ev))
+ 'magit-invoke-popup-action)))
+
+(defun magit-branch-config-branch (&optional prompt)
+ (if prompt
+ (or (and (not current-prefix-arg)
+ (or magit-branch-config-branch
+ (magit-get-current-branch)))
+ (magit-read-local-branch prompt))
+ (or magit-branch-config-branch
+ (magit-get-current-branch)
+ "<name>")))
+
+;;;###autoload
+(defun magit-edit-branch*description (branch)
+ "Edit the description of the current branch.
+With a prefix argument edit the description of another branch.
+
+The description for the branch named NAME is stored in the Git
+variable `branch.<name>.description'."
+ (interactive (list (magit-branch-config-branch "Edit branch description")))
+ (magit-run-git-with-editor "branch" "--edit-description" branch))
+
+(defun magit-edit-branch*description-check-buffers ()
+ (and buffer-file-name
+ (string-match-p "/BRANCH_DESCRIPTION\\'" buffer-file-name)
+ (add-hook 'with-editor-post-finish-hook
+ (lambda ()
+ (when (derived-mode-p 'magit-popup-mode)
+ (magit-refresh-popup-buffer)))
+ nil t)))
+
+(add-hook 'find-file-hook 'magit-edit-branch*description-check-buffers)
+
+(defun magit-format-branch*description ()
+ (let* ((branch (magit-branch-config-branch))
+ (width (+ (length branch) 19))
+ (var (format "branch.%s.description" branch)))
+ (concat var " " (make-string (- width (length var)) ?\s)
+ (-if-let (value (magit-get var))
+ (propertize value 'face 'magit-popup-option-value)
+ (propertize "unset" 'face 'magit-popup-disabled-argument)))))
+
+;;;###autoload
+(defun magit-set-branch*merge/remote (branch upstream)
+ "Set or unset the upstream of the current branch.
+With a prefix argument do so for another branch.
+
+When the branch in question already has an upstream then simply
+unsets it. Invoke this command again to set another upstream.
+
+Together the Git variables `branch.<name>.remote' and
+`branch.<name>.merge' define the upstream branch of the local
+branch named NAME. The value of `branch.<name>.remote' is the
+name of the upstream remote. The value of `branch.<name>.merge'
+is the full reference of the upstream branch, on the remote.
+
+Non-interactively, when UPSTREAM is non-nil, then always set it
+as the new upstream, regardless of whether another upstream was
+already set. When nil, then always unset."
+ (interactive
+ (let ((branch (magit-branch-config-branch "Change upstream of branch")))
+ (list branch (and (not (magit-get-upstream-branch branch))
+ (magit-read-upstream-branch)))))
+ (if upstream
+ (-let (((remote . merge) (magit-split-branch-name upstream)))
+ (setf (magit-get (format "branch.%s.remote" branch)) remote)
+ (setf (magit-get (format "branch.%s.merge" branch))
+ (concat "refs/heads/" merge)))
+ (magit-call-git "branch" "--unset-upstream" branch))
+ (when (called-interactively-p 'any)
+ (magit-refresh)))
+
+(defun magit-format-branch*merge/remote ()
+ (let* ((branch (magit-branch-config-branch))
+ (width (+ (length branch) 20))
+ (varM (format "branch.%s.merge" branch))
+ (varR (format "branch.%s.remote" branch))
+ (face (if (equal (magit-get varR) ".")
+ 'magit-branch-local
+ 'magit-branch-remote)))
+ (concat varM (make-string (- width (length varM)) ?\s)
+ (-if-let (value (magit-get varM))
+ (propertize value 'face face)
+ (propertize "unset" 'face 'magit-popup-disabled-argument))
+ "\n " varR (make-string (- width (length varR)) ?\s)
+ (-if-let (value (magit-get varR))
+ (propertize value 'face face)
+ (propertize "unset" 'face 'magit-popup-disabled-argument)))))
+
+;;;###autoload
+(defun magit-cycle-branch*rebase (branch)
+ "Cycle the value of `branch.<name>.rebase' for the current branch.
+With a prefix argument cycle the value for another branch.
+
+The Git variables `branch.<name>.rebase' controls whether pulling
+into the branch named NAME is done by rebasing that branch onto
+the fetched branch or by merging that branch.
+
+When `true' then pulling is done by rebasing.
+When `false' then pulling is done by merging.
+
+When that variable is undefined then the value of `pull.rebase'
+is used instead. It defaults to `false'."
+ (interactive (list (magit-branch-config-branch
+ "Cycle branch.<name>.rebase for")))
+ (magit-popup-set-variable (format "branch.%s.rebase" branch)
+ '("true" "false")
+ "false" "pull.rebase"))
+
+(defun magit-format-branch*rebase ()
+ (let ((branch (magit-branch-config-branch)))
+ (magit-popup-format-variable (format "branch.%s.rebase" branch)
+ '("true" "false")
+ "false" "pull.rebase"
+ (+ (length branch) 20))))
+
+;;;###autoload
+(defun magit-cycle-branch*pushRemote (branch)
+ "Cycle the value of `branch.<name>.pushRemote' for the current branch.
+With a prefix argument cycle the value for another branch.
+
+The Git variable `branch.<name>.pushRemote' specifies the remote
+that the branch named NAME is usually pushed to. The value has
+to be the name of an existing remote.
+
+If that variable is undefined, then the value of the Git variable
+`remote.pushDefault' is used instead, provided that it is defined,
+which by default it is not."
+ (interactive (list (magit-branch-config-branch
+ "Cycle branch.<name>.pushRemote for")))
+ (magit-popup-set-variable (format "branch.%s.pushRemote" branch)
+ (magit-list-remotes)
+ "remote.pushDefault"))
+
+(defun magit-format-branch*pushRemote ()
+ (let ((branch (magit-branch-config-branch)))
+ (magit-popup-format-variable (format "branch.%s.pushRemote" branch)
+ (magit-list-remotes)
+ nil "remote.pushDefault"
+ (+ (length branch) 20))))
+
+;;;###autoload
+(defun magit-cycle-pull.rebase ()
+ "Cycle the repository-local value of `pull.rebase'.
+
+The Git variable `pull.rebase' specifies whether pulling is done
+by rebasing or by merging. It can be overwritten using the Git
+variable `branch.<name>.rebase'.
+
+When `true' then pulling is done by rebasing.
+When `false' (the default) then pulling is done by merging."
+ (interactive)
+ (magit-popup-set-variable "pull.rebase" '("true" "false") "false"))
+
+(defun magit-format-pull.rebase ()
+ (magit-popup-format-variable "pull.rebase" '("true" "false") "false" nil 19))
+
+;;;###autoload
+(defun magit-cycle-remote.pushDefault ()
+ "Cycle the repository-local value of `remote.pushDefault'.
+
+The Git variable `remote.pushDefault' specifies the remote that
+local branches are usually pushed to. It can be overwritten
+using the Git variable `branch.<name>.pushRemote'."
+ (interactive)
+ (magit-popup-set-variable "remote.pushDefault" (magit-list-remotes)))
+
+(defun magit-format-remote.pushDefault ()
+ (magit-popup-format-variable "remote.pushDefault"
+ (magit-list-remotes) nil nil 19))
+
+;;;###autoload
+(defun magit-cycle-branch*autoSetupMerge ()
+ "Cycle the repository-local value of `branch.autoSetupMerge'.
+
+The Git variable `branch.autoSetupMerge' under what circumstances
+creating a branch (named NAME) should result in the variables
+`branch.<name>.merge' and `branch.<name>.remote' being set
+according to the starting point used to create the branch. If
+the starting point isn't a branch, then these variables are never
+set.
+
+When `always' then the variables are set regardless of whether
+the starting point is a local or a remote branch.
+
+When `true' (the default) then the variable are set when the
+starting point is a remote branch, but not when it is a local
+branch.
+
+When `false' then the variables are never set."
+ (interactive)
+ (magit-popup-set-variable "branch.autoSetupMerge"
+ '("always" "true" "false") "true"))
+
+(defun magit-format-branch*autoSetupMerge ()
+ (magit-popup-format-variable "branch.autoSetupMerge"
+ '("always" "true" "false") "true" nil 23))
+
+;;;###autoload
+(defun magit-cycle-branch*autoSetupRebase ()
+ "Cycle the repository-local value of `branch.autoSetupRebase'.
+
+The Git variable `branch.autoSetupRebase' specifies whether
+creating a branch (named NAME) should result in the variable
+`branch.<name>.rebase' being set to `true'.
+
+When `always' then the variable is set regardless of whether the
+starting point is a local or a remote branch.
+
+When `local' then the variable are set when the starting point
+is a local branch, but not when it is a remote branch.
+
+When `remote' then the variable are set when the starting point
+is a remote branch, but not when it is a local branch.
+
+When `never' (the default) then the variable is never set."
+ (interactive)
+ (magit-popup-set-variable "branch.autoSetupRebase"
+ '("always" "local" "remote" "never") "never"))
+
+(defun magit-format-branch*autoSetupRebase ()
+ (magit-popup-format-variable "branch.autoSetupRebase"
+ '("always" "local" "remote" "never")
+ "never" nil 23))
+
+;;;; Merge
+
+;;;###autoload (autoload 'magit-merge-popup "magit" nil t)
+(magit-define-popup magit-merge-popup
+ "Popup console for merge commands."
+ 'magit-commands
+ :man-page "git-merge"
+ :switches '((?f "Fast-forward only" "--ff-only")
+ (?n "No fast-forward" "--no-ff")
+ (?s "Squash" "--squash"))
+ :options '((?s "Strategy" "--strategy="))
+ :actions '((?m "Merge" magit-merge)
+ (?e "Merge and edit message" magit-merge-editmsg)
+ (?p "Preview merge" magit-merge-preview)
+ (?n "Merge but don't commit" magit-merge-nocommit))
+ :sequence-actions '((?m "Commit merge" magit-commit)
+ (?a "Abort merge" magit-merge-abort))
+ :sequence-predicate 'magit-merge-state
+ :default-action 'magit-merge
+ :max-action-columns 2)
+
+;;;###autoload
+(defun magit-merge (rev &optional args nocommit)
+ "Merge commit REV into the current branch; using default message.
+
+Unless there are conflicts or a prefix argument is used create a
+merge commit using a generic commit message and without letting
+the user inspect the result. With a prefix argument pretend the
+merge failed to give the user the opportunity to inspect the
+merge.
+
+\(git merge --no-edit|--no-commit [ARGS] REV)"
+ (interactive (list (magit-read-other-branch-or-commit "Merge")
+ (magit-merge-arguments)
+ current-prefix-arg))
+ (magit-merge-assert)
+ (magit-run-git-async "merge" (if nocommit "--no-commit" "--no-edit") args rev))
+
+;;;###autoload
+(defun magit-merge-editmsg (rev &optional args)
+ "Merge commit REV into the current branch; and edit message.
+Perform the merge and prepare a commit message but let the user
+edit it.
+\n(git merge --edit --no-ff [ARGS] rev)"
+ (interactive (list (magit-read-other-branch-or-commit "Merge")
+ (magit-merge-arguments)))
+ (magit-merge-assert)
+ (cl-pushnew "--no-ff" args :test #'equal)
+ (apply #'magit-run-git-with-editor "merge" "--edit"
+ (append args (list rev))))
+
+;;;###autoload
+(defun magit-merge-nocommit (rev &optional args)
+ "Merge commit REV into the current branch; pretending it failed.
+Pretend the merge failed to give the user the opportunity to
+inspect the merge and change the commit message.
+\n(git merge --no-commit --no-ff [ARGS] rev)"
+ (interactive (list (magit-read-other-branch-or-commit "Merge")
+ (magit-merge-arguments)))
+ (magit-merge-assert)
+ (cl-pushnew "--no-ff" args :test #'equal)
+ (magit-run-git-async "merge" "--no-commit" args rev))
+
+;;;###autoload
+(defun magit-merge-preview (rev)
+ "Preview result of merging REV into the current branch."
+ (interactive (list (magit-read-other-branch-or-commit "Preview merge")))
+ (magit-mode-setup #'magit-merge-preview-mode rev))
+
+(define-derived-mode magit-merge-preview-mode magit-diff-mode "Magit Merge"
+ "Mode for previewing a merge."
+ :group 'magit-diff
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-merge-preview-refresh-buffer (rev)
+ (let* ((branch (magit-get-current-branch))
+ (head (or branch (magit-rev-verify "HEAD"))))
+ (setq header-line-format
+ (propertize (format "Preview merge of %s into %s"
+ rev (or branch "HEAD"))
+ 'face 'magit-header-line))
+ (magit-insert-section (diffbuf)
+ (magit-git-wash #'magit-diff-wash-diffs
+ "merge-tree" (magit-git-string "merge-base" head rev) head rev))))
+
+;;;###autoload
+(defun magit-merge-abort ()
+ "Abort the current merge operation.
+\n(git merge --abort)"
+ (interactive)
+ (if (file-exists-p (magit-git-dir "MERGE_HEAD"))
+ (when (magit-confirm 'abort-merge)
+ (magit-run-git-async "merge" "--abort"))
+ (user-error "No merge in progress")))
+
+(defun magit-checkout-stage (file arg)
+ "During a conflict checkout and stage side, or restore conflict."
+ (interactive
+ (let ((file (magit-completing-read "Checkout file"
+ (magit-tracked-files) nil nil nil
+ 'magit-read-file-hist
+ (magit-current-file))))
+ (cond ((member file (magit-unmerged-files))
+ (list file (magit-checkout-read-stage file)))
+ ((yes-or-no-p (format "Restore conflicts in %s? " file))
+ (list file "--merge"))
+ (t
+ (user-error "Quit")))))
+ (pcase (cons arg (cddr (car (magit-file-status file))))
+ ((or `("--ours" ?D ,_)
+ `("--theirs" ,_ ?D))
+ (magit-run-git "rm" "--" file))
+ (_ (if (equal arg "--merge")
+ ;; This fails if the file was deleted on one
+ ;; side. And we cannot do anything about it.
+ (magit-run-git "checkout" "--merge" "--" file)
+ (magit-call-git "checkout" arg "--" file)
+ (magit-run-git "add" "-u" "--" file)))))
+
+(defun magit-merge-state ()
+ (file-exists-p (magit-git-dir "MERGE_HEAD")))
+
+(defun magit-merge-assert ()
+ (or (not (magit-anything-modified-p))
+ (magit-confirm 'merge-dirty
+ "Merging with dirty worktree is risky. Continue")
+ (user-error "Abort")))
+
+(defun magit-checkout-read-stage (file)
+ (magit-read-char-case (format "For %s checkout: " file) t
+ (?o "[o]ur stage" "--ours")
+ (?t "[t]heir stage" "--theirs")
+ (?c "[c]onflict" "--merge")))
+
+(defun magit-insert-merge-log ()
+ "Insert section for the on-going merge.
+Display the heads that are being merged.
+If no merge is in progress, do nothing."
+ (-when-let (heads (mapcar 'magit-get-shortname
+ (magit-file-lines (magit-git-dir "MERGE_HEAD"))))
+ (magit-insert-section (commit (car heads))
+ (magit-insert-heading
+ (format "Merging %s:" (mapconcat 'identity heads ", ")))
+ (magit-insert-log
+ (concat (magit-git-string "merge-base" "--octopus" "HEAD" (car heads))
+ ".." (car heads))
+ (let ((args magit-log-section-arguments))
+ (unless (member "--decorate=full" magit-log-section-arguments)
+ (push "--decorate=full" args))
+ args)))))
+
+;;;; Reset
+
+;;;###autoload (autoload 'magit-reset-popup "magit" nil t)
+(magit-define-popup magit-reset-popup
+ "Popup console for reset commands."
+ 'magit-commands
+ :man-page "git-reset"
+ :actions '((?m "reset mixed (HEAD and index)" magit-reset-head)
+ (?s "reset soft (HEAD only)" magit-reset-soft)
+ (?h "reset hard (HEAD, index, and files)" magit-reset-hard)
+ (?i "reset index (index only)" magit-reset-index))
+ :max-action-columns 1)
+
+;;;###autoload
+(defun magit-reset-index (commit)
+ "Reset the index to COMMIT.
+Keep the head and working tree as-is, so if COMMIT refers to the
+head this effectively unstages all changes.
+\n(git reset COMMIT .)"
+ (interactive (list (magit-read-branch-or-commit "Reset index to")))
+ (magit-reset-internal nil commit "."))
+
+;;;###autoload
+(defun magit-reset (commit &optional hard)
+ "Reset the head and index to COMMIT, but not the working tree.
+With a prefix argument also reset the working tree.
+\n(git reset --mixed|--hard COMMIT)"
+ (interactive (list (magit-read-branch-or-commit
+ (if current-prefix-arg
+ "Hard reset to"
+ "Reset head to"))
+ current-prefix-arg))
+ (magit-reset-internal (if hard "--hard" "--mixed") commit))
+
+;;;###autoload
+(defun magit-reset-head (commit)
+ "Reset the head and index to COMMIT, but not the working tree.
+\n(git reset --mixed COMMIT)"
+ (interactive (list (magit-read-branch-or-commit "Reset head to")))
+ (magit-reset-internal "--mixed" commit))
+
+;;;###autoload
+(defun magit-reset-soft (commit)
+ "Reset the head to COMMIT, but not the index and working tree.
+\n(git reset --soft REVISION)"
+ (interactive (list (magit-read-branch-or-commit "Soft reset to")))
+ (magit-reset-internal "--soft" commit))
+
+;;;###autoload
+(defun magit-reset-hard (commit)
+ "Reset the head, index, and working tree to COMMIT.
+\n(git reset --hard REVISION)"
+ (interactive (list (magit-read-branch-or-commit "Hard reset to")))
+ (magit-reset-internal "--hard" commit))
+
+(defun magit-reset-internal (arg commit &optional path)
+ (when (and (not (member arg '("--hard" nil)))
+ (equal (magit-rev-parse commit)
+ (magit-rev-parse "HEAD~")))
+ (with-temp-buffer
+ (magit-git-insert "show" "-s" "--format=%B" "HEAD")
+ (when git-commit-major-mode
+ (funcall git-commit-major-mode))
+ (git-commit-setup-font-lock)
+ (git-commit-save-message)))
+ (let ((cmd (if (and (equal commit "HEAD") (not arg)) "unstage" "reset")))
+ (magit-wip-commit-before-change nil (concat " before " cmd))
+ (magit-run-git "reset" arg commit "--" path)
+ (when (equal cmd "unstage")
+ (magit-wip-commit-after-apply nil " after unstage"))))
+
+;;;; Files
+
+(defun magit-file-rename (file newname)
+ "Rename the FILE to NEWNAME.
+If FILE isn't tracked in Git fallback to using `rename-file'."
+ (interactive
+ (let* ((file (magit-read-file "Rename file"))
+ (newname (read-file-name (format "Rename %s to file: " file))))
+ (list (expand-file-name file (magit-toplevel))
+ (expand-file-name newname))))
+ (if (magit-file-tracked-p file)
+ (let ((oldbuf (get-file-buffer file)))
+ (when (and oldbuf (buffer-modified-p oldbuf))
+ (user-error "Save %s before moving it" file))
+ (when (file-exists-p newname)
+ (user-error "%s already exists" newname))
+ (magit-run-git "mv" file newname)
+ (when oldbuf
+ (with-current-buffer oldbuf
+ (let ((buffer-read-only buffer-read-only))
+ (set-visited-file-name newname))
+ (if (fboundp 'vc-refresh-state)
+ (vc-refresh-state)
+ (with-no-warnings
+ (vc-find-file-hook))))))
+ (rename-file file newname current-prefix-arg)
+ (magit-refresh)))
+
+(defun magit-file-untrack (file)
+ "Untrack FILE.
+Stop tracking FILE in Git but do not remove it from the working
+tree."
+ (interactive (list (magit-read-tracked-file "Untrack file")))
+ (magit-run-git "rm" "--cached" "--" file))
+
+(defun magit-file-delete (file &optional force)
+ "Delete FILE.
+With a prefix argument FORCE do so even when FILE has uncommitted
+changes.
+
+If FILE isn't tracked in Git fallback to using `delete-file'."
+ (interactive (list (magit-read-file "Delete file")))
+ (if (magit-file-tracked-p file)
+ (magit-run-git "rm" (and force "--force") "--" file)
+ (delete-file (expand-file-name file (magit-toplevel)) t)
+ (magit-refresh)))
+
+(defun magit-read-tracked-file (prompt)
+ (magit-read-file prompt t))
+
+(defun magit-read-file (prompt &optional tracked-only)
+ (let ((choices (nconc (magit-list-files)
+ (unless tracked-only (magit-untracked-files)))))
+ (magit-completing-read prompt choices nil t nil nil
+ (car (member (or (magit-section-when (file submodule))
+ (magit-file-relative-name
+ nil tracked-only))
+ choices)))))
+
+(defun magit-read-files (prompt initial-contents)
+ (mapconcat 'identity
+ (completing-read-multiple (or prompt "File,s: ")
+ (magit-list-files)
+ nil nil initial-contents) ","))
+
+(defun magit-read-file-choice (prompt files &optional error default)
+ "Read file from FILES.
+
+If FILES has only one member, return that instead of prompting.
+If FILES has no members, give a user error. ERROR can be given
+to provide a more informative error.
+
+If DEFAULT is non-nil, use this as the default value instead of
+`magit-current-file'."
+ (pcase (length files)
+ (0 (user-error (or error "No file choices")))
+ (1 (car files))
+ (_ (magit-completing-read
+ prompt files nil t nil 'magit-read-file-hist
+ (car (member (or default (magit-current-file)) files))))))
+
+;;; Miscellaneous
+;;;; Worktree
+
+;;;###autoload
+(defun magit-worktree-checkout (path branch)
+ "Checkout BRANCH in a new worktree at PATH."
+ (interactive
+ (let ((branch (magit-read-local-branch "Checkout")))
+ (list (read-directory-name (format "Checkout %s in new worktree: " branch))
+ branch)))
+ (magit-run-git "worktree" "add" (expand-file-name path) branch)
+ (magit-diff-visit-directory path))
+
+;;;###autoload
+(defun magit-worktree-branch (path branch start-point &optional force)
+ "Create a new BRANCH and check it out in a new worktree at PATH."
+ (interactive
+ `(,(read-directory-name "Create worktree: ")
+ ,@(butlast (magit-branch-read-args "Create and checkout branch"))
+ ,current-prefix-arg))
+ (magit-run-git "worktree" "add" (if force "-B" "-b")
+ branch (expand-file-name path) start-point)
+ (magit-diff-visit-directory path))
+
+(defun magit-worktree-delete (worktree)
+ "Delete a worktree, defaulting to the worktree at point.
+The primary worktree cannot be deleted."
+ (interactive
+ (list (magit-completing-read "Delete worktree"
+ (cdr (magit-list-worktrees))
+ nil t nil nil
+ (magit-section-when (worktree)))))
+ (if (file-directory-p (expand-file-name ".git" worktree))
+ (user-error "Deleting %s would delete the shared .git directory" worktree)
+ (let ((primary (file-name-as-directory (caar (magit-list-worktrees)))))
+ (when (if magit-delete-by-moving-to-trash
+ (magit-confirm-files 'trash (list "worktree"))
+ (magit-confirm-files 'delete (list "worktree")))
+ (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
+ (delete-directory worktree t magit-delete-by-moving-to-trash))
+ (if (file-exists-p default-directory)
+ (magit-run-git "worktree" "prune")
+ (let ((default-directory primary))
+ (magit-run-git "worktree" "prune")))))))
+
+(defun magit-worktree-status (worktree)
+ "Show the status for the worktree at point.
+If there is no worktree at point, then read one in the
+minibuffer. If the worktree at point is the one whose
+status is already being displayed in the current buffer,
+then show it in Dired instead."
+ (interactive
+ (list (or (magit-section-when (worktree))
+ (magit-completing-read
+ "Show status for worktree"
+ (cl-delete (directory-file-name (magit-toplevel))
+ (magit-list-worktrees)
+ :test #'equal :key #'car)))))
+ (magit-diff-visit-directory worktree))
+
+(defvar magit-worktree-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-worktree-status)
+ (define-key map [remap magit-delete-thing] 'magit-worktree-delete)
+ map)
+ "Keymap for `worktree' sections.")
+
+(defun magit-insert-worktrees ()
+ "Insert sections for all worktrees.
+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:")
+ (let* ((cols
+ (mapcar (-lambda ((path barep commit branch))
+ (cons (cond
+ (branch (propertize branch
+ 'face 'magit-branch-local))
+ (commit (propertize (magit-rev-abbrev commit)
+ 'face 'magit-hash))
+ (barep "(bare)"))
+ path))
+ worktrees))
+ (align (1+ (-max (--map (string-width (car it)) cols)))))
+ (pcase-dolist (`(,head . ,path) cols)
+ (magit-insert-section (worktree path)
+ (insert head)
+ (indent-to align)
+ (insert (let ((r (file-relative-name path))
+ (a (abbreviate-file-name path)))
+ (if (< (string-width r) (string-width a)) r a)))
+ (insert ?\n))))
+ (insert ?\n)))))
+
+;;;; Tag
+
+;;;###autoload (autoload 'magit-tag-popup "magit" nil t)
+(magit-define-popup magit-tag-popup
+ "Popup console for tag commands."
+ 'magit-commands
+ :man-page "git-tag"
+ :switches '((?a "Annotate" "--annotate")
+ (?s "Sign" "--sign")
+ (?f "Force" "--force"))
+ :actions '((?t "Create" magit-tag)
+ (?k "Delete" magit-tag-delete)
+ (?p "Prune" magit-tag-prune))
+ :default-action 'magit-tag)
+
+;;;###autoload
+(defun magit-tag (name rev &optional args)
+ "Create a new tag with the given NAME at REV.
+With a prefix argument annotate the tag.
+\n(git tag [--annotate] NAME REV)"
+ (interactive (list (magit-read-tag "Tag name")
+ (or (and (memq 'magit-tag magit-no-confirm-default)
+ (or (magit-branch-or-commit-at-point)
+ (magit-get-current-branch)))
+ (magit-read-branch-or-commit "Place tag on"))
+ (let ((args (magit-tag-arguments)))
+ (when current-prefix-arg
+ (cl-pushnew "--annotate" args))
+ args)))
+ (magit-run-git-with-editor "tag" args name rev))
+
+;;;###autoload
+(defun magit-tag-delete (tags)
+ "Delete one or more tags.
+If the region marks multiple tags (and nothing else), then offer
+to delete those, otherwise prompt for a single tag to be deleted,
+defaulting to the tag at point.
+\n(git tag -d TAGS)"
+ (interactive (list (--if-let (magit-region-values 'tag)
+ (magit-confirm t nil "Delete %i tags" it)
+ (magit-read-tag "Delete tag" t))))
+ (magit-run-git "tag" "-d" tags))
+
+(defun magit-tag-prune (tags remote-tags remote)
+ "Offer to delete tags missing locally from REMOTE, and vice versa."
+ (interactive
+ (let* ((remote (magit-read-remote "Prune tags using remote"))
+ (tags (magit-list-tags))
+ (rtags (prog2 (message "Determining remote tags...")
+ (magit-remote-list-tags remote)
+ (message "Determining remote tags...done")))
+ (ltags (-difference tags rtags))
+ (rtags (-difference rtags tags)))
+ (unless (or ltags rtags)
+ (message "Same tags exist locally and remotely"))
+ (unless (magit-confirm t "Delete %s locally"
+ "Delete %i tags locally" ltags)
+ (setq ltags nil))
+ (unless (magit-confirm t "Delete %s from remote"
+ "Delete %i tags from remote" rtags)
+ (setq rtags nil))
+ (list ltags rtags remote)))
+ (when tags
+ (magit-call-git "tag" "-d" tags))
+ (when remote-tags
+ (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags))))
+
+;;;; Notes
+
+;;;###autoload (autoload 'magit-notes-popup "magit" nil t)
+(magit-define-popup magit-notes-popup
+ "Popup console for notes commands."
+ 'magit-commands
+ :man-page "git-tag"
+ :switches '("Switch for prune"
+ (?n "Dry run" "--dry-run"))
+ :options '("Option for edit and remove"
+ (?r "Manipulate ref" "--ref=" magit-notes-popup-read-ref)
+ "Option for merge"
+ (?s "Merge strategy" "--strategy="))
+ :actions '((?T "Edit" magit-notes-edit)
+ (?r "Remove" magit-notes-remove)
+ (?m "Merge" magit-notes-merge)
+ (?p "Prune" magit-notes-prune)
+ (?s "Set ref" magit-notes-set-ref)
+ (?S "Set display refs" magit-notes-set-display-refs))
+ :sequence-actions '((?c "Commit merge" magit-notes-merge-commit)
+ (?a "Abort merge" magit-notes-merge-abort))
+ :sequence-predicate 'magit-notes-merging-p
+ :default-action 'magit-notes-edit)
+
+(defun magit-notes-edit (commit &optional ref)
+ "Edit the note attached to COMMIT.
+REF is the notes ref used to store the notes.
+
+Interactively or when optional REF is nil use the value of Git
+variable `core.notesRef' or \"refs/notes/commits\" if that is
+undefined."
+ (interactive (magit-notes-read-args "Edit notes"))
+ (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
+ "edit" commit))
+
+(defun magit-notes-remove (commit &optional ref)
+ "Remove the note attached to COMMIT.
+REF is the notes ref from which the note is removed.
+
+Interactively or when optional REF is nil use the value of Git
+variable `core.notesRef' or \"refs/notes/commits\" if that is
+undefined."
+ (interactive (magit-notes-read-args "Remove notes"))
+ (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
+ "remove" commit))
+
+(defun magit-notes-merge (ref)
+ "Merge the notes ref REF into the current notes ref.
+
+The current notes ref is the value of Git variable
+`core.notesRef' or \"refs/notes/commits\" if that is undefined.
+
+When there are conflict, then they have to resolved in the
+temporary worktree \".git/NOTES_MERGE_WORKTREE\". When
+done use `magit-notes-merge-commit' to finish. To abort
+use `magit-notes-merge-abort'."
+ (interactive (list (magit-read-string-ns "Merge reference")))
+ (magit-run-git-with-editor "notes" "merge" ref))
+
+(defun magit-notes-merge-commit ()
+ "Commit the current notes ref merge.
+Also see `magit-notes-merge'."
+ (interactive)
+ (magit-run-git-with-editor "notes" "merge" "--commit"))
+
+(defun magit-notes-merge-abort ()
+ "Abort the current notes ref merge.
+Also see `magit-notes-merge'."
+ (interactive)
+ (magit-run-git-with-editor "notes" "merge" "--abort"))
+
+(defun magit-notes-prune (&optional dry-run)
+ "Remove notes about unreachable commits."
+ (interactive (list (and (member "--dry-run" (magit-notes-arguments)) t)))
+ (when dry-run
+ (magit-process-buffer))
+ (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run")))
+
+(defun magit-notes-set-ref (ref &optional global)
+ "Set the current notes ref to REF.
+The ref is made current by setting the value of the Git variable
+`core.notesRef'. With a prefix argument GLOBAL change the global
+value, else the value in the current repository. When this is
+undefined, then \"refs/notes/commit\" is used.
+
+Other `magit-notes-*' commands, as well as the sub-commands
+of Git's `note' command, default to operate on that ref."
+ (interactive
+ (list (magit-completing-read "Set notes ref"
+ (nconc (list "refs/" "refs/notes/")
+ (magit-list-notes-refnames))
+ nil nil
+ (--when-let (magit-get "core.notesRef")
+ (if (string-match "^refs/notes/\\(.+\\)" it)
+ (match-string 1 it)
+ it)))
+ current-prefix-arg))
+ (if ref
+ (magit-run-git "config" (and global "--global") "core.notesRef"
+ (if (string-prefix-p "refs/" ref)
+ ref
+ (concat "refs/notes/" ref)))
+ (magit-run-git "config" (and global "--global")
+ "--unset" "core.notesRef")))
+
+(defun magit-notes-set-display-refs (refs &optional global)
+ "Set notes refs to be display in addition to \"core.notesRef\".
+REFS is a colon separated list of notes refs. The values are
+stored in the Git variable `notes.displayRef'. With a prefix
+argument GLOBAL change the global values, else the values in
+the current repository."
+ (interactive
+ (list (magit-completing-read "Set additional notes ref(s)"
+ (nconc (list "refs/" "refs/notes/")
+ (magit-list-notes-refnames))
+ nil nil
+ (mapconcat #'identity
+ (magit-get-all "notes.displayRef")
+ ":"))
+ current-prefix-arg))
+ (when (and refs (atom refs))
+ (setq refs (split-string refs ":")))
+ (when global
+ (setq global "--global"))
+ (magit-git-success "config" "--unset-all" global "notes.displayRef")
+ (dolist (ref refs)
+ (magit-call-git "config" "--add" global "notes.displayRef" ref))
+ (magit-refresh))
+
+(defun magit-notes-read-args (prompt)
+ (list (magit-read-branch-or-commit prompt)
+ (--when-let (--first (string-match "^--ref=\\(.+\\)" it)
+ (magit-notes-arguments))
+ (match-string 1 it))))
+
+(defun magit-notes-popup-read-ref (prompt &optional initial-input)
+ (magit-completing-read prompt (nconc (list "refs/" "refs/notes/")
+ (magit-list-notes-refnames))
+ nil nil initial-input))
+
+(defun magit-notes-merging-p ()
+ (let ((dir (magit-git-dir "NOTES_MERGE_WORKTREE")))
+ (and (file-directory-p dir)
+ (directory-files dir nil "^[^.]"))))
+
+;;;; Config Files
+
+(defun magit-find-git-config-file (filename &optional wildcards)
+ "Edit a located in the current repository's git directory.
+
+When \".git\", located at the root of the working tree, is a
+regular file, then that makes it cumbersome to open a file
+located in the actual git directory.
+
+This command is like `find-file', except that it temporarily
+binds `default-directory' to the actual git directory, while
+reading the FILENAME."
+ (interactive
+ (let ((default-directory (magit-git-dir)))
+ (find-file-read-args "Find file: "
+ (confirm-nonexistent-file-or-buffer))))
+ (find-file filename wildcards))
+
+(defun magit-find-git-config-file-other-window (filename &optional wildcards)
+ "Edit a located in the current repository's git directory, in another window.
+
+When \".git\", located at the root of the working tree, is a
+regular file, then that makes it cumbersome to open a file
+located in the actual git directory.
+
+This command is like `find-file-other-window', except that it
+temporarily binds `default-directory' to the actual git
+directory, while reading the FILENAME."
+ (interactive
+ (let ((default-directory (magit-git-dir)))
+ (find-file-read-args "Find file in other window: "
+ (confirm-nonexistent-file-or-buffer))))
+ (find-file-other-window filename wildcards))
+
+(defun magit-find-git-config-file-other-frame (filename &optional wildcards)
+ "Edit a located in the current repository's git directory, in another frame.
+
+When \".git\", located at the root of the working tree, is a
+regular file, then that makes it cumbersome to open a file
+located in the actual git directory.
+
+This command is like `find-file-other-frame', except that it
+temporarily binds `default-directory' to the actual git
+directory, while reading the FILENAME."
+ (interactive
+ (let ((default-directory (magit-git-dir)))
+ (find-file-read-args "Find file in other frame: "
+ (confirm-nonexistent-file-or-buffer))))
+ (find-file-other-frame filename wildcards))
+
+;;;; File Mode
+
+(defvar magit-file-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\C-xg" 'magit-status)
+ (define-key map "\C-x\M-g" 'magit-dispatch-popup)
+ (define-key map "\C-c\M-g" 'magit-file-popup)
+ map)
+ "Keymap for `magit-file-mode'.")
+
+;;;###autoload (autoload 'magit-file-popup "magit" nil t)
+(magit-define-popup magit-file-popup
+ "Popup console for Magit commands in file-visiting buffers."
+ :actions '((?s "Stage" magit-stage-file)
+ (?d "Diff" magit-diff-buffer-file)
+ (?l "Log" magit-log-buffer-file)
+ (?b "Blame" magit-blame-popup)
+ (?u "Unstage" magit-unstage-file)
+ (?D "Diff..." magit-diff-buffer-file-popup)
+ (?L "Log..." magit-log-buffer-file-popup)
+ (?p "Find blob" magit-blob-previous)
+ (?c "Commit" magit-commit-popup))
+ :max-action-columns 4)
+
+(defvar magit-file-mode-lighter "")
+
+(define-minor-mode magit-file-mode
+ "Enable some Magit features in file-visiting buffers.
+
+Currently this only adds the following key bindings.
+\n\\{magit-file-mode-map}"
+ :package-version '(magit . "2.2.0")
+ :lighter magit-file-mode-lighter
+ :keymap magit-file-mode-map)
+
+(defun magit-file-mode-turn-on ()
+ (and buffer-file-name
+ (ignore-errors (magit-inside-worktree-p))
+ (magit-file-mode)))
+
+;;;###autoload
+(define-globalized-minor-mode global-magit-file-mode
+ magit-file-mode magit-file-mode-turn-on
+ :package-version '(magit . "2.2.0")
+ :group 'magit-modes)
+
+;;;; Blob Mode
+
+(defvar magit-blob-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "n" 'magit-blob-next)
+ (define-key map "p" 'magit-blob-previous)
+ (define-key map "q" 'magit-kill-this-buffer)
+ map)
+ "Keymap for `magit-blob-mode'.")
+
+(define-minor-mode magit-blob-mode
+ "Enable some Magit features in blob-visiting buffers.
+
+Currently this only adds the following key bindings.
+\n\\{magit-blob-mode-map}"
+ :package-version '(magit . "2.3.0"))
+
+(defun magit-blob-next ()
+ "Visit the next blob which modified the current file."
+ (interactive)
+ (if magit-buffer-file-name
+ (magit-blob-visit (or (magit-blob-successor magit-buffer-revision
+ magit-buffer-file-name)
+ magit-buffer-file-name)
+ (line-number-at-pos))
+ (if (buffer-file-name (buffer-base-buffer))
+ (user-error "You have reached the end of time")
+ (user-error "Buffer isn't visiting a file or blob"))))
+
+(defun magit-blob-previous ()
+ "Visit the previous blob which modified the current file."
+ (interactive)
+ (-if-let (file (or magit-buffer-file-name
+ (buffer-file-name (buffer-base-buffer))))
+ (--if-let (magit-blob-ancestor magit-buffer-revision file)
+ (magit-blob-visit it (line-number-at-pos))
+ (user-error "You have reached the beginning of time"))
+ (user-error "Buffer isn't visiting a file or blob")))
+
+(defun magit-blob-visit (blob-or-file line)
+ (if (stringp blob-or-file)
+ (find-file blob-or-file)
+ (-let [(rev file) blob-or-file]
+ (magit-find-file rev file)
+ (let ((str (magit-rev-format "%ct%s" rev)))
+ (message "%s (%s ago)" (substring str 10)
+ (magit-format-duration
+ (abs (truncate (- (float-time)
+ (string-to-number
+ (substring str 0 10)))))
+ magit-duration-spec)))))
+ (goto-char (point-min))
+ (forward-line (1- line)))
+
+(defun magit-blob-ancestor (rev file)
+ (let ((lines (magit-with-toplevel
+ (magit-git-lines "log" "-2" "--format=%H" "--name-only"
+ "--follow" (or rev "HEAD") "--" file))))
+ (if rev (cddr lines) (butlast lines 2))))
+
+(defun magit-blob-successor (rev file)
+ (let ((lines (magit-with-toplevel
+ (magit-git-lines "log" "--format=%H" "--name-only" "--follow"
+ "HEAD" "--" file))))
+ (catch 'found
+ (while lines
+ (if (equal (nth 2 lines) rev)
+ (throw 'found (list (nth 0 lines) (nth 1 lines)))
+ (setq lines (nthcdr 2 lines)))))))
+
+(defun magit-kill-this-buffer ()
+ "Kill the current buffer."
+ (interactive)
+ (kill-buffer (current-buffer)))
+
+;;;; Dispatch Popup
+
+;;;###autoload (autoload 'magit-dispatch-popup "magit" nil t)
+(magit-define-popup magit-dispatch-popup
+ "Popup console for dispatching other popups."
+ 'magit-commands nil nil
+ :actions '("Popup and dwim commands"
+ (?A "Cherry-picking" magit-cherry-pick-popup)
+ (?b "Branching" magit-branch-popup)
+ (?B "Bisecting" magit-bisect-popup)
+ (?c "Committing" magit-commit-popup)
+ (?d "Diffing" magit-diff-popup)
+ (?D "Change diffs" magit-diff-refresh-popup)
+ (?e "Ediff dwimming" magit-ediff-dwim)
+ (?E "Ediffing" magit-ediff-popup)
+ (?f "Fetching" magit-fetch-popup)
+ (?F "Pulling" magit-pull-popup)
+ (?l "Logging" magit-log-popup)
+ (?L "Change logs" magit-log-refresh-popup)
+ (?m "Merging" magit-merge-popup)
+ (?M "Remoting" magit-remote-popup)
+ (?o "Submodules" magit-submodule-popup)
+ (?O "Subtrees" magit-subtree-popup)
+ (?P "Pushing" magit-push-popup)
+ (?r "Rebasing" magit-rebase-popup)
+ (?t "Tagging" magit-tag-popup)
+ (?T "Notes" magit-notes-popup)
+ (?V "Reverting" magit-revert-popup)
+ (?w "Apply patches" magit-am-popup)
+ (?W "Format patches" magit-patch-popup)
+ (?X "Resetting" magit-reset-popup)
+ (?y "Show Refs" magit-show-refs-popup)
+ (?z "Stashing" magit-stash-popup)
+ (?! "Running" magit-run-popup)
+ "Applying changes"
+ (?a "Apply" magit-apply)
+ (?s "Stage" magit-stage)
+ (?u "Unstage" magit-unstage)
+ nil
+ (?v "Reverse" magit-reverse)
+ (?S "Stage all" magit-stage-modified)
+ (?U "Unstage all" magit-unstage-all)
+ nil
+ (?k "Discard" magit-discard)
+ "\
+ g refresh current buffer
+ TAB toggle section at point
+ RET visit thing at point
+
+ C-h m show all key bindings" nil)
+ :max-action-columns 4)
+
+;;;; Git Popup
+
+(defvar magit-git-command-history nil)
+
+;;;###autoload (autoload 'magit-run-popup "magit" nil t)
+(magit-define-popup magit-run-popup
+ "Popup console for running raw Git commands."
+ 'magit-commands nil nil
+ :actions '((?! "Git Subcommand (in topdir)" magit-git-command-topdir)
+ (?k "Gitk" magit-run-gitk)
+ (?p "Git Subcommand (in pwd)" magit-git-command)
+ (?a "Gitk --all" magit-run-gitk-all)
+ (?s "Shell command (in topdir)" magit-shell-command-topdir)
+ (?b "Gitk --branches" magit-run-gitk-branches)
+ (?S "Shell command (in pwd)" magit-shell-command)
+ (?g "Git Gui" magit-run-git-gui))
+ :default-action 'magit-git-command
+ :max-action-columns 2)
+
+;;;###autoload
+(defun magit-git-command (args directory)
+ "Execute a Git subcommand asynchronously, displaying the output.
+With a prefix argument run Git in the root of the current
+repository, otherwise in `default-directory'."
+ (interactive (magit-read-shell-command "Git subcommand (pwd: %s)"))
+ (require 'eshell)
+ (with-temp-buffer
+ (insert args)
+ (setq args (mapcar 'eval (eshell-parse-arguments (point-min)
+ (point-max))))
+ (setq default-directory directory)
+ (let ((magit-git-global-arguments
+ ;; A human will want globbing by default.
+ (remove "--literal-pathspecs"
+ magit-git-global-arguments)))
+ (magit-run-git-async args)))
+ (magit-process-buffer))
+
+;;;###autoload
+(defun magit-git-command-topdir (args directory)
+ "Execute a Git subcommand asynchronously, displaying the output.
+Run Git in the top-level directory of the current repository.
+\n(fn)" ; arguments are for internal use
+ (interactive (magit-read-shell-command "Git subcommand (pwd: %s)" t))
+ (magit-git-command args directory))
+
+;;;###autoload
+(defun magit-shell-command (args directory)
+ "Execute a shell command asynchronously, displaying the output.
+With a prefix argument run the command in the root of the current
+repository, otherwise in `default-directory'."
+ (interactive (magit-read-shell-command "Shell command (pwd: %s)"))
+ (require 'eshell)
+ (with-temp-buffer
+ (insert args)
+ (setq args (mapcar 'eval (eshell-parse-arguments (point-min)
+ (point-max))))
+ (setq default-directory directory)
+ (apply #'magit-start-process (car args) nil (cdr args)))
+ (magit-process-buffer))
+
+;;;###autoload
+(defun magit-shell-command-topdir (args directory)
+ "Execute a shell command asynchronously, displaying the output.
+Run the command in the top-level directory of the current repository.
+\n(fn)" ; arguments are for internal use
+ (interactive (magit-read-shell-command "Shell command (pwd: %s)" t))
+ (magit-shell-command args directory))
+
+(defun magit-read-shell-command (prompt &optional root)
+ (let ((dir (if (or root current-prefix-arg)
+ (or (magit-toplevel)
+ (user-error "Not inside a Git repository"))
+ default-directory)))
+ (list (magit-read-string (format prompt (abbreviate-file-name dir))
+ nil 'magit-git-command-history)
+ dir)))
+
+;;;; Repository List
+
+;;;###autoload
+(defun magit-list-repositories ()
+ "Display a list of repositories.
+
+Use the options `magit-repository-directories'
+and `magit-repository-directories-depth' to
+control which repositories are displayed."
+ (interactive)
+ (if magit-repository-directories
+ (with-current-buffer (get-buffer-create "*Magit Repositories*")
+ (magit-repolist-mode)
+ (setq tabulated-list-entries
+ (mapcar (-lambda ((id . path))
+ (let ((default-directory path))
+ (list path
+ (vconcat (--map (or (funcall (nth 2 it) id) "")
+ magit-repolist-columns)))))
+ (magit-list-repos-uniquify
+ (--map (cons (file-name-nondirectory (directory-file-name it))
+ it)
+ (magit-list-repos)))))
+ (tabulated-list-print)
+ (switch-to-buffer (current-buffer)))
+ (message "You need to customize `magit-repository-directories' %s"
+ "before you can list repositories")))
+
+(defvar magit-repolist-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map tabulated-list-mode-map)
+ (define-key map "g" 'magit-list-repositories)
+ (define-key map "\r" 'magit-repolist-status)
+ map)
+ "Local keymap for Magit-Repolist mode buffers.")
+
+(defun magit-repolist-status (&optional _button)
+ "Show the status for the repository at point."
+ (interactive)
+ (--if-let (tabulated-list-get-id)
+ (magit-status-internal (expand-file-name it))
+ (user-error "There is no repository at point")))
+
+(define-derived-mode magit-repolist-mode tabulated-list-mode "Repos"
+ "Major mode for browsing a list of Git repositories."
+ (setq x-stretch-cursor nil)
+ (setq tabulated-list-padding 0)
+ (setq tabulated-list-sort-key (cons "Name" nil))
+ (setq tabulated-list-format
+ (vconcat (mapcar (-lambda ((title width _fn props))
+ (nconc (list title width t)
+ (-flatten props)))
+ magit-repolist-columns)))
+ (tabulated-list-init-header))
+
+(defun magit-repolist-column-ident (id)
+ "Insert the identification of the repository.
+Usually this is just its basename."
+ id)
+
+(defun magit-repolist-column-path (_id)
+ "Insert the absolute path of the repository."
+ (abbreviate-file-name default-directory))
+
+(defun magit-repolist-column-version (_id)
+ "Insert a description of the repository's `HEAD' revision."
+ (let ((v (or (magit-git-string "describe" "--tags")
+ ;; If there are no tags, use the date in MELPA format.
+ (magit-git-string "show" "--no-patch" "--format=%cd-g%h"
+ "--date=format:%Y%m%d.%H%M"))))
+ (if (and v (string-match-p "\\`[0-9]" v))
+ (concat " " v)
+ v)))
+
+(defun magit-repolist-column-branch (_id)
+ "Insert the current branch."
+ (magit-get-current-branch))
+
+(defun magit-repolist-column-upstream (_id)
+ "Insert the upstream branch of the current branch."
+ (magit-get-current-branch))
+
+(defun magit-repolist-column-unpulled-from-upstream (_id)
+ "Insert number of upstream commits not in the current branch."
+ (--when-let (magit-get-upstream-branch)
+ (let ((n (cadr (magit-rev-diff-count "HEAD" it))))
+ (propertize (number-to-string n) 'face (if (> n 0) 'bold 'shadow)))))
+
+(defun magit-repolist-column-unpulled-from-pushremote (_id)
+ "Insert number of commits in the push branch but not the current branch."
+ (--when-let (magit-get-push-branch)
+ (when (magit-rev-verify it)
+ (let ((n (cadr (magit-rev-diff-count "HEAD" it))))
+ (propertize (number-to-string n) 'face (if (> n 0) 'bold 'shadow))))))
+
+(defun magit-repolist-column-unpushed-to-upstream (_id)
+ "Insert number of commits in the current branch but not its upstream."
+ (--when-let (magit-get-upstream-branch)
+ (let ((n (car (magit-rev-diff-count "HEAD" it))))
+ (propertize (number-to-string n) 'face (if (> n 0) 'bold 'shadow)))))
+
+(defun magit-repolist-column-unpushed-to-pushremote (_id)
+ "Insert number of commits in the current branch but not its push branch."
+ (--when-let (magit-get-push-branch)
+ (when (magit-rev-verify it)
+ (let ((n (car (magit-rev-diff-count "HEAD" it))))
+ (propertize (number-to-string n) 'face (if (> n 0) 'bold 'shadow))))))
+
+(defun magit-read-repository (&optional read-directory-name)
+ "Read a Git repository in the minibuffer, with completion.
+
+The completion choices are the basenames of top-levels of
+repositories found in the directories specified by option
+`magit-repository-directories'. In case of name conflicts
+the basenames are prefixed with the name of the respective
+parent directories. The returned value is the actual path
+to the selected repository.
+
+With prefix argument simply read a directory name using
+`read-directory-name'."
+ (if (and (not read-directory-name) magit-repository-directories)
+ (let* ((repos (magit-list-repos-uniquify
+ (--map (cons (file-name-nondirectory
+ (directory-file-name it))
+ it)
+ (magit-list-repos))))
+ (reply (magit-completing-read "Git repository" repos)))
+ (file-name-as-directory
+ (or (cdr (assoc reply repos))
+ (if (file-directory-p reply)
+ (expand-file-name reply)
+ (user-error "Not a repository or a directory: %s" reply)))))
+ (file-name-as-directory
+ (read-directory-name "Git repository: "
+ (or (magit-toplevel) default-directory)))))
+
+(defun magit-list-repos ()
+ (--mapcat (if (consp it)
+ (magit-list-repos-1 (car it) (cdr it))
+ (magit-list-repos-1 it magit-repository-directories-depth))
+ magit-repository-directories))
+
+(defun magit-list-repos-1 (directory depth)
+ (cond ((file-readable-p (expand-file-name ".git" directory))
+ (list 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)))))
+
+(defun magit-list-repos-uniquify (alist)
+ (let (result (dict (make-hash-table :test 'equal)))
+ (dolist (a (delete-dups alist))
+ (puthash (car a) (cons (cdr a) (gethash (car a) dict)) dict))
+ (maphash
+ (lambda (key value)
+ (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))))))
+ dict)
+ result))
+
+;;;; Revision Stack
+
+(defvar magit-revision-stack nil)
+
+(defcustom magit-pop-revision-stack-format
+ '("[%N: %h] " "%N: %H\n %s\n" "\\[\\([0-9]+\\)[]:]")
+ "Control how `magit-pop-revision-stack' inserts a revision.
+
+The command `magit-pop-revision-stack' inserts a representation
+of the revision last pushed to the `magit-revision-stack' into
+the current buffer. It inserts text at point and/or near the end
+of the buffer, and removes the consumed revision from the stack.
+
+The entries on the stack have the format (HASH TOPLEVEL) and this
+option has the format (POINT-FORMAT EOB-FORMAT INDEX-REGEXP), all
+of which may be nil or a string (though either one of EOB-FORMAT
+or POINT-FORMAT should be a string, and if INDEX-REGEXP is
+non-nil, then the two formats should be too).
+
+First INDEX-REGEXP is used to find the previously inserted entry,
+by searching backward from point. The first submatch must match
+the index number. That number is incremented by one, and becomes
+the index number of the entry to be inserted. If you don't want
+to number the inserted revisions, then use nil for INDEX-REGEXP.
+
+If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
+should contain \"%N\", which is replaced with the number that was
+determined in the previous step.
+
+Both formats, if non-nil and after removing %N, are then expanded
+using `git show --format=FORMAT ...' inside TOPLEVEL.
+
+The expansion of POINT-FORMAT is inserted at point, and the
+expansion of EOB-FORMAT is inserted at the end of the buffer (if
+the buffer ends with a comment, then it is inserted right before
+that)."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type '(list (choice (string :tag "Insert at point format")
+ (cons (string :tag "Insert at point format")
+ (repeat (string :tag "Argument to git show")))
+ (const :tag "Don't insert at point" nil))
+ (choice (string :tag "Insert at eob format")
+ (cons (string :tag "Insert at eob format")
+ (repeat (string :tag "Argument to git show")))
+ (const :tag "Don't insert at eob" nil))
+ (choice (regexp :tag "Find index regexp")
+ (const :tag "Don't number entries" nil))))
+
+(defun magit-pop-revision-stack (rev toplevel)
+ "Insert a representation of a revision into the current buffer.
+
+Pop a revision from the `magit-revision-stack' and insert it into
+the current buffer according to `magit-pop-revision-stack-format'.
+Revisions can be put on the stack using `magit-copy-section-value'
+and `magit-copy-buffer-revision'.
+
+If the stack is empty or with a prefix argument instead read a
+revision in the minibuffer. By using the minibuffer history this
+allows selecting an item which was popped earlier or to insert an
+arbitrary reference or revision without first pushing it onto the
+stack.
+
+When reading the revision from the minibuffer, then it might not
+be possible to guess the correct repository. When this command
+is called inside a repository (e.g. while composing a commit
+message), then that repository is used. Otherwise (e.g. while
+composing an email) then the repository recorded for the top
+element of the stack is used (even though we insert another
+revision). If not called inside a repository and with an empty
+stack, or with two prefix arguments, then read the repository in
+the minibuffer too."
+ (interactive
+ (if (or current-prefix-arg (not magit-revision-stack))
+ (let ((default-directory
+ (or (and (not (= (prefix-numeric-value current-prefix-arg) 16))
+ (or (magit-toplevel)
+ (cadr (car magit-revision-stack))))
+ (magit-read-repository))))
+ (list (magit-read-branch-or-commit "Insert revision")
+ default-directory))
+ (push (caar magit-revision-stack) magit-revision-history)
+ (pop magit-revision-stack)))
+ (if rev
+ (-let [(pnt-format eob-format idx-format) magit-pop-revision-stack-format]
+ (let ((default-directory toplevel)
+ (idx (and idx-format
+ (save-excursion
+ (if (re-search-backward idx-format nil t)
+ (number-to-string
+ (1+ (string-to-number (match-string 1))))
+ "1"))))
+ pnt-args eob-args)
+ (when (listp pnt-format)
+ (setq pnt-args (cdr pnt-format)
+ pnt-format (car pnt-format)))
+ (when (listp eob-format)
+ (setq eob-args (cdr eob-format)
+ eob-format (car eob-format)))
+ (when pnt-format
+ (when idx-format
+ (setq pnt-format
+ (replace-regexp-in-string "%N" idx pnt-format t t)))
+ (magit-rev-insert-format pnt-format rev pnt-args)
+ (backward-delete-char 1))
+ (when eob-format
+ (when idx-format
+ (setq eob-format
+ (replace-regexp-in-string "%N" idx eob-format t t)))
+ (save-excursion
+ (goto-char (point-max))
+ (skip-syntax-backward ">s-")
+ (beginning-of-line)
+ (if (and comment-start (looking-at comment-start))
+ (while (looking-at comment-start)
+ (forward-line -1))
+ (forward-line)
+ (unless (= (current-column) 0)
+ (insert ?\n)))
+ (insert ?\n)
+ (magit-rev-insert-format eob-format rev eob-args)
+ (backward-delete-char 1)))))
+ (user-error "Revision stack is empty")))
+
+(define-key git-commit-mode-map
+ (kbd "C-c C-w") 'magit-pop-revision-stack)
+
+(defun magit-copy-section-value ()
+ "Save the value of the current section for later use.
+
+Save the section value to the `kill-ring', and, provided that
+the current section is a commit, branch, or tag section, push
+the (referenced) revision to the `magit-revision-stack' for use
+with `magit-pop-revision-stack'.
+
+When the current section is a branch or a tag, and a prefix
+argument is used, then save the revision at its tip to the
+`kill-ring' instead of the reference name.
+
+When the region is active, then save that to the `kill-ring',
+like `kill-ring-save' would, instead of behaving as described
+above."
+ (interactive)
+ (if (use-region-p)
+ (copy-region-as-kill nil nil 'region)
+ (-when-let* ((section (magit-current-section))
+ (value (magit-section-value section)))
+ (magit-section-case
+ ((branch commit module-commit tag)
+ (let ((default-directory default-directory) ref)
+ (magit-section-case
+ ((branch tag)
+ (setq ref value))
+ (module-commit
+ (setq default-directory
+ (file-name-as-directory
+ (expand-file-name (magit-section-parent-value section)
+ (magit-toplevel))))))
+ (setq value (magit-rev-parse value))
+ (push (list value default-directory) magit-revision-stack)
+ (kill-new (message "%s" (or (and current-prefix-arg ref)
+ value)))))
+ (t (kill-new (message "%s" value)))))))
+
+(defun magit-copy-buffer-revision ()
+ "Save the revision of the current buffer for later use.
+
+Save the revision shown in the current buffer to the `kill-ring'
+and push it to the `magit-revision-stack'.
+
+This command is mainly intended for use in `magit-revision-mode'
+buffers, the only buffers where it is always unambiguous exactly
+which revision should be saved.
+
+Most other Magit buffers usually show more than one revision, in
+some way or another, so this command has to select one of them,
+and that choice might not always be the one you think would have
+been the best pick.
+
+In such buffers it is often more useful to save the value of
+the current section instead, using `magit-copy-section-value'.
+
+When the region is active, then save that to the `kill-ring',
+like `kill-ring-save' would, instead of behaving as described
+above."
+ (interactive)
+ (if (use-region-p)
+ (copy-region-as-kill nil nil 'region)
+ (-when-let (rev (cond ((memq major-mode '(magit-cherry-mode
+ magit-log-select-mode
+ magit-reflog-mode
+ magit-refs-mode
+ magit-revision-mode
+ magit-stash-mode
+ magit-stashes-mode))
+ (car magit-refresh-args))
+ ((memq major-mode '(magit-diff-mode
+ magit-log-mode))
+ (let ((r (caar magit-refresh-args)))
+ (if (string-match "\\.\\.\\.?\\(.+\\)" r)
+ (match-string 1 r)
+ r)))
+ ((eq major-mode 'magit-status-mode) "HEAD")))
+ (when (magit-rev-verify-commit rev)
+ (setq rev (magit-rev-parse rev))
+ (push (list rev default-directory) magit-revision-stack)
+ (kill-new (message "%s" rev))))))
+
+;;; magit.el ends soon
+
+(defconst magit-font-lock-keywords
+ (eval-when-compile
+ `((,(concat "(\\(magit-define-section-jumper\\)\\_>"
+ "[ \t'\(]*"
+ "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
+ (1 'font-lock-keyword-face)
+ (2 'font-lock-function-name-face nil t))
+ (,(concat "(" (regexp-opt '("magit-insert-section"
+ "magit-section-case"
+ "magit-section-when"
+ "magit-bind-match-strings"
+ "magit-with-temp-index"
+ "magit-with-blob"
+ "magit-with-toplevel") t)
+ "\\_>")
+ . 1))))
+
+(font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords)
+
+(defvar magit-version 'undefined
+ "The version of Magit that you're using.
+Use the function by the same name instead of this variable.")
+
+;;;###autoload
+(defun magit-version ()
+ "Return the version of Magit currently in use.
+When called interactive also show the used versions of Magit,
+Git, and Emacs in the echo area."
+ (interactive)
+ (let ((magit-git-global-arguments nil)
+ (toplib (or load-file-name buffer-file-name))
+ debug)
+ (unless (and toplib
+ (equal (file-name-nondirectory toplib) "magit.el"))
+ (setq toplib (locate-library "magit.el")))
+ (push toplib debug)
+ (when toplib
+ (let* ((topdir (file-name-directory toplib))
+ (gitdir (expand-file-name
+ ".git" (file-name-directory
+ (directory-file-name topdir))))
+ (static (locate-library "magit-version.el" nil (list topdir))))
+ (or (progn
+ (push 'repo debug)
+ (when (and (file-exists-p gitdir)
+ ;; It is a repo, but is it the Magit repo?
+ (file-exists-p
+ (expand-file-name "../lisp/magit.el" gitdir)))
+ (push t debug)
+ ;; Inside the repo the version file should only exist
+ ;; while running make.
+ (when (and static (not noninteractive))
+ (ignore-errors (delete-file static)))
+ (setq magit-version
+ (let ((default-directory topdir))
+ (magit-git-string "describe" "--tags" "--dirty")))))
+ (progn
+ (push 'static debug)
+ (when (and static (file-exists-p static))
+ (push t debug)
+ (load-file static)
+ magit-version))
+ (when (featurep 'package)
+ (push 'elpa debug)
+ (ignore-errors
+ (--when-let (assq 'magit package-alist)
+ (push t debug)
+ (setq magit-version
+ (and (fboundp 'package-desc-version)
+ (package-version-join
+ (package-desc-version (cadr it))))))))
+ (progn
+ (push 'debug debug)
+ (let ((dirname (file-name-nondirectory
+ (directory-file-name topdir))))
+ (when (string-match "\\`magit-\\([0-9]\\{8\\}\\.[0-9]*\\)"
+ dirname)
+ (setq magit-version (match-string 1 dirname))))))))
+ (if (stringp magit-version)
+ (when (called-interactively-p 'any)
+ (message "Magit %s, Git %s, Emacs %s, %s"
+ (or magit-version "(unknown)")
+ (or (magit-git-version t) "(unknown)")
+ emacs-version
+ system-type))
+ (setq debug (reverse debug))
+ (setq magit-version 'error)
+ (when magit-version
+ (push magit-version debug))
+ (unless (equal (getenv "TRAVIS") "true")
+ ;; The repository is a sparse clone.
+ (message "Cannot determine Magit's version %S" debug)))
+ magit-version))
+
+(defun magit-startup-asserts ()
+ (let ((version (magit-git-version)))
+ (when (and version
+ (version< version magit--minimal-git)
+ (not (equal (getenv "TRAVIS") "true")))
+ (display-warning 'magit (format "\
+Magit requires Git >= %s, you are using %s.
+
+If this comes as a surprise to you, because you do actually have
+a newer version installed, then that probably means that the
+older version happens to appear earlier on the `$PATH'. If you
+always start Emacs from a shell, then that can be fixed in the
+shell's init file. If you start Emacs by clicking on an icon,
+or using some sort of application launcher, then you probably
+have to adjust the environment as seen by graphical interface.
+For X11 something like ~/.xinitrc should work.
+
+If you use Tramp to work inside remote Git repositories, then you
+have to make sure a suitable Git is used on the remote machines
+too.\n" magit--minimal-git version) :error)))
+ (when (version< emacs-version magit--minimal-emacs)
+ (display-warning 'magit (format "\
+Magit requires Emacs >= %s, you are using %s.
+
+If this comes as a surprise to you, because you do actually have
+a newer version installed, then that probably means that the
+older version happens to appear earlier on the `$PATH'. If you
+always start Emacs from a shell, then that can be fixed in the
+shell's init file. If you start Emacs by clicking on an icon,
+or using some sort of application launcher, then you probably
+have to adjust the environment as seen by graphical interface.
+For X11 something like ~/.xinitrc should work.\n"
+ magit--minimal-emacs emacs-version)
+ :error))
+ (--each '((magit-log-edit . git-commit)
+ (git-commit-mode . git-commit)
+ (git-rebase-mode . git-rebase))
+ (when (or (featurep (car it)) (locate-library (symbol-name (car it))))
+ (display-warning 'magit (format "%s has to be removed
+
+Magit is no longer compatible with the library `%s',
+which was used in earlier releases. Please remove it, so that
+Magit can use the successor `%s' without the obsolete
+library getting in the way. Then restart Emacs.\n"
+ (car it) (car it) (cdr it)) :error))))
+
+(defvar magit--remotes-using-recent-git nil)
+
+(defun magit-tramp-asserts (directory)
+ (-when-let (remote (file-remote-p directory))
+ (unless (member remote magit--remotes-using-recent-git)
+ (-if-let (version (let ((default-directory directory))
+ (magit-git-version)))
+ (if (version<= magit--minimal-git version)
+ (push version magit--remotes-using-recent-git)
+ (display-warning 'magit (format "\
+Magit requires Git >= %s, but on %s the version is %s.
+
+If multiple Git versions are installed on the host then the
+problem might be that TRAMP uses the wrong executable.
+
+First check the value of `magit-git-executable'. Its value is
+used when running git locally as well as when running it on a
+remote host. The default value is \"git\", except on Windows
+where an absolute path is used for performance reasons.
+
+If the value already is just \"git\" but TRAMP never-the-less
+doesn't use the correct executable, then consult the info node
+`(tramp)Remote programs'.\n" magit--minimal-git remote version) :error))
+ (display-warning 'magit (format "\
+Magit cannot find Git on %s.
+
+First check the value of `magit-git-executable'. Its value is
+used when running git locally as well as when running it on a
+remote host. The default value is \"git\", except on Windows
+where an absolute path is used for performance reasons.
+
+If the value already is just \"git\" but TRAMP never-the-less
+doesn't find the executable, then consult the info node
+`(tramp)Remote programs'.\n" remote) :error)))))
+
+(make-obsolete-variable 'magit-status-refresh-hook "\
+use `magit-pre-refresh-hook', `magit-post-refresh-hook',
+ `magit-refresh-buffer-hook', or `magit-status-mode-hook' instead.
+
+ If you want to run a function every time the status buffer is
+ refreshed, in order to do something with that buffer, then use:
+
+ (add-hook 'magit-refresh-buffer-hook
+ (lambda ()
+ (when (derived-mode-p 'magit-status-mode)
+ ...)))
+
+ If your hook function should run regardless of whether the
+ status buffer exists or not, then use `magit-pre-refresh-hook'
+ or `magit-post-refresh-hook'.
+
+ If your hook function only has to be run once, when the buffer
+ is first created, then `magit-status-mode-hook' instead.
+" "Magit 2.4.0")
+
+(define-obsolete-function-alias 'global-magit-file-buffer-mode
+ 'global-magit-file-mode "Magit 2.3.0")
+(define-obsolete-function-alias 'magit-insert-head-header
+ 'magit-insert-head-branch-header "Magit 2.4.0")
+(define-obsolete-function-alias 'magit-insert-upstream-header
+ 'magit-insert-upstream-branch-header "Magit 2.4.0")
+(define-obsolete-function-alias 'magit-insert-pull-branch-header
+ 'magit-insert-upstream-branch-header "Magit 2.4.0")
+
+(provide 'magit)
+
+(cl-eval-when (load eval)
+ (require 'magit-sequence)
+ (require 'magit-commit)
+ (require 'magit-remote)
+ (require 'magit-bisect)
+ (require 'magit-stash)
+ (require 'magit-blame)
+ (unless (load "magit-autoloads" t t)
+ (require 'magit-submodule)
+ (require 'magit-subtree)
+ (require 'magit-ediff)
+ (require 'magit-extras)
+ (require 'git-rebase)))
+
+(if after-init-time
+ (progn (magit-startup-asserts)
+ (magit-version))
+ (add-hook 'after-init-hook #'magit-startup-asserts t)
+ (add-hook 'after-init-hook #'magit-version t))
+
+;; Local Variables:
+;; coding: utf-8
+;; indent-tabs-mode: nil
+;; End:
+;;; magit.el ends here
--- /dev/null
+This is magit.info, produced by makeinfo version 5.2 from magit.texi.
+
+Magit is an interface to the version control system Git, implemented as
+an Emacs package. Magit aspires to be a complete Git porcelain. While
+we cannot (yet) claim that Magit wraps and improves upon each and every
+Git command, it is complete enough to allow even experienced Git users
+to perform almost all of their daily version control tasks directly from
+within Emacs. While many fine Git clients exist, only Magit and Git
+itself deserve to be called porcelains.
+
+ Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* Magit: (magit). Using Git from Emacs with Magit.
+END-INFO-DIR-ENTRY
+
+\1f
+Indirect:
+magit.info-1: 1222
+magit.info-2: 321649
+\1f
+Tag Table:
+(Indirect)
+Node: Top\7f1222
+Node: Introduction\7f6446
+Node: Installation\7f11169
+Node: Updating from an older release\7f11544
+Node: Installing from an Elpa archive\7f13139
+Node: Installing from the Git repository\7f14478
+Node: Post-installation tasks\7f17325
+Node: Getting started\7f18714
+Node: Interface concepts\7f24443
+Node: Modes and Buffers\7f24717
+Node: Switching Buffers\7f26462
+Node: Naming Buffers\7f31003
+Node: Quitting Windows\7f33838
+Node: Automatic Refreshing of Magit Buffers\7f35470
+Node: Automatic Saving of File-Visiting Buffers\7f38238
+Node: Automatic Reverting of File-Visiting Buffers\7f39423
+Node: Risk of Reverting Automatically\7f44419
+Node: Sections\7f46802
+Node: Section movement\7f47743
+Node: Section visibility\7f51670
+Node: Section hooks\7f55261
+Node: Section types and values\7f57542
+Node: Section options\7f58812
+Node: Popup buffers and prefix commands\7f59284
+Node: Completion and confirmation\7f60598
+Node: Running Git\7f63504
+Node: Viewing Git output\7f63740
+Node: Running Git manually\7f64740
+Node: Git executable\7f66866
+Node: Global Git arguments\7f68873
+Node: Inspecting\7f69680
+Node: Status buffer\7f70827
+Node: Status sections\7f73692
+Node: Status header sections\7f79571
+Node: Status options\7f82128
+Node: Repository list\7f82852
+Node: Logging\7f85010
+Node: Refreshing logs\7f87748
+Node: Log Buffer\7f89133
+Node: Select from log\7f92429
+Node: Reflog\7f93369
+Node: Diffing\7f93847
+Node: Refreshing diffs\7f96867
+Node: Diff buffer\7f99848
+Node: Diff options\7f102442
+Node: Revision buffer\7f105808
+Node: Ediffing\7f106763
+Node: References buffer\7f110353
+Node: References sections\7f115063
+Node: Bisecting\7f115938
+Node: Visiting blobs\7f117677
+Node: Blaming\7f118186
+Node: Manipulating\7f121616
+Node: Repository setup\7f121932
+Node: Staging and unstaging\7f122972
+Node: Staging from file-visiting buffers\7f127061
+Node: Applying\7f128229
+Node: Committing\7f130122
+Node: Initiating a commit\7f130705
+Node: Editing commit messages\7f134017
+Node: Branching\7f144413
+Node: The two remotes\7f144613
+Node: The branch popup\7f147157
+Node: The branch config popup\7f156393
+Node: Merging\7f162299
+Node: Resolving conflicts\7f164467
+Node: Rebasing\7f169472
+Node: Editing rebase sequences\7f173113
+Node: Information about in-progress rebase\7f176143
+Ref: Information about in-progress rebase-Footnote-1\7f182979
+Node: Cherry picking\7f183565
+Node: Reverting\7f185171
+Node: Resetting\7f186534
+Node: Stashing\7f188046
+Node: Transferring\7f191220
+Node: Remotes\7f191458
+Node: Fetching\7f192744
+Node: Pulling\7f194110
+Node: Pushing\7f194956
+Node: Creating and sending patches\7f199700
+Node: Applying patches\7f200395
+Node: Miscellaneous\7f201393
+Node: Tagging\7f201696
+Node: Notes\7f202481
+Node: Submodules\7f205006
+Node: Listing submodules\7f205221
+Node: Submodule popup\7f207040
+Node: Subtree\7f208323
+Node: Common commands\7f209571
+Node: Wip modes\7f211316
+Node: Minor mode for buffers visiting files\7f218052
+Node: Minor mode for buffers visiting blobs\7f221526
+Node: Customizing\7f222331
+Node: Per-repository configuration\7f224003
+Node: Essential settings\7f225637
+Node: Safety\7f225961
+Node: Performance\7f227794
+Node: Plumbing\7f235756
+Node: Calling Git\7f236580
+Node: Getting a value from Git\7f238103
+Node: Calling Git for effect\7f241207
+Node: Section plumbing\7f247711
+Node: Creating sections\7f247939
+Node: Section selection\7f251838
+Node: Matching sections\7f253518
+Node: Refreshing buffers\7f258950
+Node: Conventions\7f262085
+Node: Confirmation and completion\7f262262
+Node: Theming Faces\7f263160
+Node: FAQ\7f271311
+Node: Magit is slow\7f272924
+Node: I changed several thousand files at once and now Magit is unusable\7f273125
+Node: I am having problems committing\7f273841
+Node: Diffs are collapsed after un-/staging\7f274287
+Node: I don't understand how branching and pushing work\7f275765
+Node: I don't like the key binding in v24\7f276140
+Node: I cannot install the pre-requisites for Magit v2\7f276479
+Node: I am using an Emacs release older than v244\7f276944
+Node: I am using a Git release older than v194\7f278557
+Node: I am using MS Windows and cannot push with Magit\7f279544
+Node: I am using OS X and SOMETHING works in shell but not in Magit\7f280148
+Node: How to install the gitman info manual?\7f280939
+Node: How can I show Git's output?\7f283480
+Node: Diffs contain control sequences\7f284267
+Node: Expanding a file to show the diff causes it to disappear\7f285272
+Node: Point is wrong in the ‘COMMIT_EDITMSG’ buffer\7f285807
+Node: The mode-line information isn't always up-to-date\7f286837
+Node: Can Magit be used as ‘ediff-version-control-package’?\7f287905
+Node: How to show diffs for gpg-encrypted files?\7f289949
+Node: Emacs 245 hangs when loading Magit\7f290546
+Node: Symbol's value as function is void ‘--some’\7f291121
+Node: Where is the branch manager\7f291455
+Node: Keystroke Index\7f291746
+Node: Command Index\7f321649
+Node: Function Index\7f351658
+Node: Variable Index\7f365552
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End:
--- /dev/null
+This is magit.info, produced by makeinfo version 5.2 from magit.texi.
+
+Magit is an interface to the version control system Git, implemented as
+an Emacs package. Magit aspires to be a complete Git porcelain. While
+we cannot (yet) claim that Magit wraps and improves upon each and every
+Git command, it is complete enough to allow even experienced Git users
+to perform almost all of their daily version control tasks directly from
+within Emacs. While many fine Git clients exist, only Magit and Git
+itself deserve to be called porcelains.
+
+ Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* Magit: (magit). Using Git from Emacs with Magit.
+END-INFO-DIR-ENTRY
+
+\1f
+File: magit.info, Node: Top, Next: Introduction, Up: (dir)
+
+Magit User Manual
+*****************
+
+Magit is an interface to the version control system Git, implemented as
+an Emacs package. Magit aspires to be a complete Git porcelain. While
+we cannot (yet) claim that Magit wraps and improves upon each and every
+Git command, it is complete enough to allow even experienced Git users
+to perform almost all of their daily version control tasks directly from
+within Emacs. While many fine Git clients exist, only Magit and Git
+itself deserve to be called porcelains.
+
+ Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+* Menu:
+
+* Introduction::
+* Installation::
+* Getting started::
+* Interface concepts::
+* Inspecting::
+* Manipulating::
+* Transferring::
+* Miscellaneous::
+* Customizing::
+* Plumbing::
+* FAQ::
+* Keystroke Index::
+* Command Index::
+* Function Index::
+* Variable Index::
+
+— The Detailed Node Listing —
+
+
+Installation
+
+* Updating from an older release::
+* Installing from an Elpa archive::
+* Installing from the Git repository::
+* Post-installation tasks::
+
+
+
+
+Interface concepts
+
+* Modes and Buffers::
+* Sections::
+* Popup buffers and prefix commands::
+* Completion and confirmation::
+* Running Git::
+
+Modes and Buffers
+
+* Switching Buffers::
+* Naming Buffers::
+* Quitting Windows::
+* Automatic Refreshing of Magit Buffers::
+* Automatic Saving of File-Visiting Buffers::
+* Automatic Reverting of File-Visiting Buffers::
+
+
+Sections
+
+* Section movement::
+* Section visibility::
+* Section hooks::
+* Section types and values::
+* Section options::
+
+
+
+
+Running Git
+
+* Viewing Git output::
+* Running Git manually::
+* Git executable::
+* Global Git arguments::
+
+Inspecting
+
+* Status buffer::
+* Repository list::
+* Logging::
+* Diffing::
+* Ediffing::
+* References buffer::
+* Bisecting::
+* Visiting blobs::
+* Blaming::
+
+Status buffer
+
+* Status sections::
+* Status header sections::
+* Status options::
+
+
+
+Logging
+
+* Refreshing logs::
+* Log Buffer::
+* Select from log::
+* Reflog::
+
+
+Diffing
+
+* Refreshing diffs::
+* Diff buffer::
+* Diff options::
+* Revision buffer::
+
+
+
+References buffer
+
+* References sections::
+
+Manipulating
+
+* Repository setup::
+* Staging and unstaging::
+* Applying::
+* Committing::
+* Branching::
+* Merging::
+* Resolving conflicts::
+* Rebasing::
+* Cherry picking::
+* Resetting::
+* Stashing::
+
+
+Staging and unstaging
+
+* Staging from file-visiting buffers::
+
+
+
+Committing
+
+* Initiating a commit::
+* Editing commit messages::
+
+
+Branching
+
+* The two remotes::
+* The branch popup::
+* The branch config popup::
+
+
+
+
+Rebasing
+
+* Editing rebase sequences::
+* Information about in-progress rebase::
+
+
+Cherry picking
+
+* Reverting::
+
+Transferring
+
+* Remotes::
+* Fetching::
+* Pulling::
+* Pushing::
+* Creating and sending patches::
+* Applying patches::
+
+
+
+Miscellaneous
+
+* Tagging::
+* Notes::
+* Submodules::
+* Subtree::
+* Common commands::
+* Wip modes::
+* Minor mode for buffers visiting files::
+* Minor mode for buffers visiting blobs::
+
+
+
+Submodules
+
+* Listing submodules::
+* Submodule popup::
+
+Customizing
+
+* Per-repository configuration::
+* Essential settings::
+
+
+Essential settings
+
+* Safety::
+* Performance::
+
+Plumbing
+
+* Calling Git::
+* Section plumbing::
+* Refreshing buffers::
+* Conventions::
+
+Calling Git
+
+* Getting a value from Git::
+* Calling Git for effect::
+
+
+Section plumbing
+
+* Creating sections::
+* Section selection::
+* Matching sections::
+
+
+
+Conventions
+
+* Confirmation and completion::
+* Theming Faces::
+
+FAQ
+
+* Magit is slow::
+* I changed several thousand files at once and now Magit is unusable::
+* I am having problems committing::
+* Diffs are collapsed after un-/staging::
+* I don't understand how branching and pushing work::
+* I don’t like the key binding in v2.4: I don't like the key binding in v24.
+* I cannot install the pre-requisites for Magit v2::
+* I am using an Emacs release older than v24.4: I am using an Emacs release older than v244.
+* I am using a Git release older than v1.9.4: I am using a Git release older than v194.
+* I am using MS Windows and cannot push with Magit::
+* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
+* How to install the gitman info manual?::
+* How can I show Git's output?::
+* Diffs contain control sequences::
+* Expanding a file to show the diff causes it to disappear::
+* Point is wrong in the ‘COMMIT_EDITMSG’ buffer::
+* The mode-line information isn't always up-to-date::
+* Can Magit be used as ‘ediff-version-control-package’?::
+* How to show diffs for gpg-encrypted files?::
+* Emacs 24.5 hangs when loading Magit: Emacs 245 hangs when loading Magit.
+* Symbol's value as function is void ‘--some’::
+* Where is the branch manager::
+
+\1f
+File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
+
+1 Introduction
+**************
+
+Magit is an interface to the version control system Git, implemented as
+an Emacs package. Magit aspires to be a complete Git porcelain. While
+we cannot (yet) claim that Magit wraps and improves upon each and every
+Git command, it is complete enough to allow even experienced Git users
+to perform almost all of their daily version control tasks directly from
+within Emacs. While many fine Git clients exist, only Magit and Git
+itself deserve to be called porcelains.
+
+ Staging and otherwise applying changes is one of the most important
+features in a Git porcelain and here Magit outshines anything else,
+including Git itself. Git’s own staging interface (‘git add --patch’)
+is so cumbersome that many users only use it in exceptional cases. In
+Magit staging a hunk or even just part of a hunk is as trivial as
+staging all changes made to a file.
+
+ The most visible part of Magit’s interface is the status buffer,
+which displays information about the current repository. Its content is
+created by running several Git commands and making their output
+actionable. Among other things, it displays information about the
+current branch, lists unpulled and unpushed changes and contains
+sections displaying the staged and unstaged changes. That might sound
+noisy, but, since sections are collapsible, it’s not.
+
+ To stage or unstage a change one places the cursor on the change and
+then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the
+region is active (i.e. when there is a selection) several files or
+hunks, or even just part of a hunk. The change or changes that these
+commands - and many others - would act on are highlighted.
+
+ Magit also implements several other "apply variants" in addition to
+staging and unstaging. One can discard or reverse a change, or apply it
+to the working tree. Git’s own porcelain only supports this for staging
+and unstaging and you would have to do something like ‘git diff ... |
+??? | git apply ...’ to discard, revert, or apply a single hunk on the
+command line. In fact that’s exactly what Magit does internally (which
+is what lead to the term "apply variants").
+
+ Magit isn’t just for Git experts, but it does assume some prior
+experience with Git as well as Emacs. That being said, many users have
+reported that using Magit was what finally taught them what Git is
+capable of and how to use it to its fullest. Other users wished they
+had switched to Emacs sooner so that they would have gotten their hands
+on Magit earlier.
+
+ While one has to know the basic features of Emacs to be able to make
+full use of Magit, acquiring just enough Emacs skills doesn’t take long
+and is worth it, even for users who prefer other editors. Vim users are
+advised to give Evil (https://bitbucket.org/lyro/evil/wiki/Home), the
+"Extensible VI Layer for Emacs", and Spacemacs
+(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused
+on Evil" a try.
+
+ Magit provides a consistent and efficient Git porcelain. After a
+short learning period, you will be able to perform most of your daily
+version control tasks faster than you would on the command line. You
+will likely also start using features that seemed too daunting in the
+past.
+
+ Magit fully embraces Git. It exposes many advanced features using a
+simple but flexible interface instead of only wrapping the trivial ones
+like many GUI clients do. Of course Magit supports logging, cloning,
+pushing, and other commands that usually don’t fail in spectacular ways;
+but it also supports tasks that often cannot be completed in a single
+step. Magit fully supports tasks such as merging, rebasing,
+cherry-picking, reverting, and blaming by not only providing a command
+to initiate these tasks but also by displaying context sensitive
+information along the way and providing commands that are useful for
+resolving conflicts and resuming the sequence after doing so.
+
+ Magit wraps and in many cases improves upon at least the following
+Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’,
+‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’,
+‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’,
+‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’,
+‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’,
+‘submodule’, ‘subtree’, ‘tag’, and ‘worktree.’ Many more Magit porcelain
+commands are implemented on top of Git plumbing commands.
+
+\1f
+File: magit.info, Node: Installation, Next: Getting started, Prev: Introduction, Up: Top
+
+2 Installation
+**************
+
+Magit can be installed using Emacs’ package manager or manually from its
+development repository.
+
+* Menu:
+
+* Updating from an older release::
+* Installing from an Elpa archive::
+* Installing from the Git repository::
+* Post-installation tasks::
+
+\1f
+File: magit.info, Node: Updating from an older release, Next: Installing from an Elpa archive, Up: Installation
+
+2.1 Updating from an older release
+==================================
+
+When updating from ‘1.2.*’ or ‘1.4.*’, you should first uninstall Magit
+and some of its dependencies and restart Emacs before installing the
+latest release.
+
+ • The old Magit installation has to be removed because some macros
+ have changed and using the old definitions when building the new
+ release would lead to very strange results, including compile
+ errors. This is due to a limitation in Emacs’ package manager or
+ rather Emacs itself: it’s not possible to reliably unload a feature
+ or even all features belonging to a package.
+
+ • Furthermore the old dependencies ‘git-commit-mode’ and
+ ‘git-rebase-mode’ have to be removed because they are no longer
+ used by the ‘2.1.0’ release and later, and get in the way of their
+ successors ‘git-commit’ and ‘git-rebase’.
+
+ So please uninstall the packages ‘magit’, ‘git-commit-mode’, and
+‘git-rebase-mode’. Then quit Emacs and start a new instance. Only then
+follow the instructions in either one of the next two sections.
+
+ Also note that starting with the ‘2.1.0’ release, Magit requires at
+least Emacs ‘24.4’ and Git ‘1.9.4’. You should make sure you have at
+least these releases installed before updating Magit. And if you
+connect to remote hosts using Tramp, then you should also make sure to
+install a recent enough Git version on these hosts.
+
+\1f
+File: magit.info, Node: Installing from an Elpa archive, Next: Installing from the Git repository, Prev: Updating from an older release, Up: Installation
+
+2.2 Installing from an Elpa archive
+===================================
+
+If you are updating from a release older than ‘2.1.0’, then you have to
+first uninstall the old version. See *note Updating from an older
+release: Updating from an older release.
+
+ Magit is available from Melpa and Melpa-Stable. If you haven’t used
+Emacs’ package manager before, then it is high time you familiarize
+yourself with it by reading the documentation in the Emacs manual, see
+*note (emacs)Packages::. Then add one of the archives to
+‘package-archives’:
+
+ • To use Melpa:
+
+ (require 'package)
+ (add-to-list 'package-archives
+ '("melpa" . "http://melpa.org/packages/") t)
+
+ • To use Melpa-Stable:
+
+ (require 'package)
+ (add-to-list 'package-archives
+ '("melpa-stable" . "http://stable.melpa.org/packages/") t)
+
+ Once you have added your preferred archive, you need to update the
+local package list using:
+
+ M-x package-refresh-contents RET
+
+ Once you have done that, you can install Magit and its dependencies
+using:
+
+ M-x package-install RET magit RET
+
+ Now see *note Post-installation tasks: Post-installation tasks.
+
+\1f
+File: magit.info, Node: Installing from the Git repository, Next: Post-installation tasks, Prev: Installing from an Elpa archive, Up: Installation
+
+2.3 Installing from the Git repository
+======================================
+
+If you are updating from a release older than ‘2.1.0’, then you have to
+first uninstall the old version. See *note Updating from an older
+release: Updating from an older release.
+
+ Magit depends on the ‘dash’ and ‘with-editor’ library which are
+available from Melpa and Melpa-Stable. Install them using ‘M-x
+package-install RET <package> RET’. Of course you may also install them
+manually from their development repository, but I won’t cover that here.
+
+ (An older release of Magit is also available from Marmalade, but no
+new versions will be uploaded in the future. Marmalade’s maintainer has
+stopped responding to requests from package maintainers who are having
+difficulties or require him to create an account so that they can upload
+their packages in the first place.)
+
+ Then clone the Magit repository:
+
+ $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit
+ $ cd ~/.emacs.d/site-lisp/magit
+
+ Then compile the libraries and generate the info manuals:
+
+ $ make
+
+ If you haven’t installed ‘dash’ and ‘with-editor’ using Elpa or at
+‘/path/to/magit/../<package>’, then you have to tell ‘make’ where to
+find them. To do so create ‘/path/to/magit/config.mk’ with the
+following content before running ‘make’:
+
+ LOAD_PATH = -L /path/to/magit/lisp
+ LOAD_PATH += -L /path/to/dash
+ LOAD_PATH += -L /path/to/with-editor
+
+ Finally add this to your init file:
+
+ (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp")
+ (require 'magit)
+
+ (with-eval-after-load 'info
+ (info-initialize)
+ (add-to-list 'Info-directory-list
+ "~/.emacs.d/site-lisp/magit/Documentation/"))
+
+ Note that you have to add the ‘lisp’ subdirectory to the ‘load-path’,
+not the top-level of the repository, and that elements of ‘load-path’
+should not end with a slash, while those of ‘Info-directory-list’
+should.
+
+ Instead of requiring the feature ‘magit’, you could load just the
+autoload definitions, by loading the file ‘magit-autoloads.el’.
+
+ (load "/path/to/magit/lisp/magit-autoloads")
+
+ Instead of running Magit directly from the repository by adding that
+to the ‘load-path’, you might want to instead install it in some other
+directory using ‘sudo make install’ and setting ‘load-path’ accordingly.
+
+ To update Magit use:
+
+ $ git pull
+ $ make
+
+ At times it might be necessary to run ‘make clean all’ instead.
+
+ To view all available targets use ‘make help’.
+
+ Now see *note Post-installation tasks: Post-installation tasks.
+
+\1f
+File: magit.info, Node: Post-installation tasks, Prev: Installing from the Git repository, Up: Installation
+
+2.4 Post-installation tasks
+===========================
+
+After installing Magit you should verify that you are indeed using the
+Magit, Git, and Emacs releases you think you are using. It’s best to
+restart Emacs before doing so, to make sure you are not using an
+outdated value for ‘load-path’.
+
+ M-x magit-version RET
+
+ should display something like
+
+ Magit 2.8.0, Git 2.9.0, Emacs 24.5.1
+
+ Then you might also want to read about options that many users likely
+want to customize. See *note Essential settings: Essential settings.
+
+ To be able to follow cross references to Git manpages found in this
+manual, you might also have to manually install the ‘gitman’ info
+manual, or advice ‘Info-follow-nearest-node’ to instead open the actual
+manpage. See *note How to install the gitman info manual?: How to
+install the gitman info manual?.
+
+ If you are completely new to Magit then see *note Getting started:
+Getting started.
+
+ If you have used an older Magit release before, then you should have
+a look at the release notes <https://github.com/magit/magit/releases>.
+
+ And last but not least please consider making a donation, to ensure
+that I can keep working on Magit. See <http://magit.vc/donations.html>
+for various donation options.
+
+\1f
+File: magit.info, Node: Getting started, Next: Interface concepts, Prev: Installation, Up: Top
+
+3 Getting started
+*****************
+
+This section describes the most essential features that many Magitians
+use on a daily basis. It only scratches the surface but should be
+enough to get you started.
+
+ (You might want to create a repository just for this walk-through,
+e.g. by cloning an existing repository. If you don’t use a separate
+repository then make sure you create a snapshot as described below).
+
+ To display information about the current Git repository, type ‘M-x
+magit-status’. You will be doing that so often that it is best to bind
+this command globally:
+
+ (global-set-key (kbd "C-x g") 'magit-status)
+
+ Most Magit commands are commonly invoked from this buffer. It should
+be considered the primary interface to interact with Git using Magit.
+There are many other Magit buffers, but they are usually created from
+this buffer.
+
+ Depending on what state your repository is in, this buffer will
+contain sections titled "Staged changes", "Unstaged changes", "Unpulled
+commits", "Unpushed commits", and/or some others.
+
+ If some staged and/or unstaged changes exist, you should back them up
+now. Type ‘z’ to show the stashing popup buffer featuring various stash
+variants and arguments that can be passed to these commands. Do not
+worry about those for now, just type ‘Z’ (uppercase) to create a stash
+while also keeping the index and work tree intact. The status buffer
+should now also contain a section titled "Stashes".
+
+ Otherwise, if there are no uncommitted changes, you should create
+some now by editing and saving some of the tracked files. Then go back
+to the status buffer, while at the same time refreshing it, by typing
+‘C-x g’. (When the status buffer, or any Magit buffer for that matter,
+is the current buffer, then you can also use just ‘g’ to refresh it).
+
+ Move between sections using ‘p’ and ‘n’. Note that the bodies of
+some sections are hidden. Type ‘TAB’ to expand or collapse the section
+at point. You can also use ‘C-tab’ to cycle the visibility of the
+current section and its children. Move to a file section inside the
+section named "Unstaged changes" and type ‘s’ to stage the changes you
+have made to that file. That file now appears under "Staged changes".
+
+ Magit can stage and unstage individual hunks, not just complete
+files. Move to the file you have just staged, expand it using ‘TAB’,
+move to one of the hunks using ‘n’, and unstage just that by typing ‘u’.
+Note how the staging (‘s’) and unstaging (‘u’) commands operate on the
+change at point. Many other commands behave the same way.
+
+ You can also un-/stage just part of a hunk. Inside the body of a
+hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and
+move down until some added and removed lines fall inside the region but
+not all of them. Again type ‘s’ to stage.
+
+ It’s also possible to un-/stage multiple files at once. Move to a
+file section, type ‘C-SPC’, move to the next file using ‘n’, and then
+‘s’ to stage both files. Note that both the mark and point have to be
+on the headings of sibling sections for this to work. If the region
+looks like it does in other buffers, then it doesn’t select Magit
+sections that can be acted on as a unit.
+
+ And then of course you want to commit your changes. Type ‘c’. This
+shows the committing popup buffer featuring various commit variants and
+arguments that can be passed to ‘git commit’. Do not worry about those
+for now. We want to create a "normal" commit, which is done by typing
+‘c’ again.
+
+ Now two new buffers appear. One is for writing the commit message,
+the other shows a diff with the changes that are about to committed.
+Write a message and then type ‘C-c C-c’ to actually create the commit.
+
+ You probably don’t want to push the commit you just created because
+you just committed some random changes, but if that is not the case you
+could push it by typing ‘P’ to bring up the push popup and then ‘u’ to
+push to the configured upstream. (If the upstream is not configured,
+then you would be prompted for the push target instead.)
+
+ Instead we are going to undo the changes made so far. Bring up the
+log for the current branch by typing ‘l l’, move to the last commit
+created before starting with this walk through using ‘n’, and do a hard
+reset using ‘C-u x’. *WARNING*: this discards all uncommitted changes.
+If you did not follow the advice about using a separate repository for
+these experiments and did not create a snapshot of uncommitted changes
+before starting to try out Magit, then don’t do this.
+
+ So far we have mentioned the commit, push, and log popups. These are
+probably among the popups you will be using the most, but many others
+exist. To show a popup with all other popups (as well as the various
+apply commands), type ‘h’. Try a few.
+
+ The key bindings in that popup correspond to the bindings in Magit
+buffers, including but not limited to the status buffer. So you could
+type ‘h d’ to bring up the diff popup, but once you remember that "d"
+stands for "diff", you would usually do so by just typing ‘d’. But the
+"popup of popups" is useful even once you have memorized all the
+bindings, as it can provide easy access to Magit commands from non-Magit
+buffers. So you should bind this globally too:
+
+ (global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
+
+ You might also want to enable ‘global-magit-file-mode’ (see *note
+Minor mode for buffers visiting files: Minor mode for buffers visiting
+files.).
+
+\1f
+File: magit.info, Node: Interface concepts, Next: Inspecting, Prev: Getting started, Up: Top
+
+4 Interface concepts
+********************
+
+* Menu:
+
+* Modes and Buffers::
+* Sections::
+* Popup buffers and prefix commands::
+* Completion and confirmation::
+* Running Git::
+
+\1f
+File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface concepts
+
+4.1 Modes and Buffers
+=====================
+
+Magit provides several major-modes. For each of these modes there
+usually exists only one buffer per repository. Separate modes and thus
+buffers exist for commits, diffs, logs, and some other things.
+
+ Besides these special purpose buffers, there also exists an overview
+buffer, called the *status buffer*. Its usually from this buffer that
+the user invokes Git commands, or creates or visits other buffers.
+
+ In this manual we often speak about "Magit buffers". By that we mean
+buffers whose major-modes derive from ‘magit-mode’.
+
+‘M-x magit-toggle-buffer-lock’ (‘magit-toggle-buffer-lock’)
+
+ This command locks the current buffer to its value or if the buffer
+ is already locked, then it unlocks it.
+
+ Locking a buffer to its value prevents it from being reused to
+ display another value. The name of a locked buffer contains its
+ value, which allows telling it apart from other locked buffers and
+ the unlocked buffer.
+
+ Not all Magit buffers can be locked to their values, for example it
+ wouldn’t make sense to lock a status buffer.
+
+ There can only be a single unlocked buffer using a certain
+ major-mode per repository. So when a buffer is being unlocked and
+ another unlocked buffer already exists for that mode and
+ repository, then the former buffer is instead deleted and the
+ latter is displayed in its place.
+
+* Menu:
+
+* Switching Buffers::
+* Naming Buffers::
+* Quitting Windows::
+* Automatic Refreshing of Magit Buffers::
+* Automatic Saving of File-Visiting Buffers::
+* Automatic Reverting of File-Visiting Buffers::
+
+\1f
+File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers
+
+4.1.1 Switching Buffers
+-----------------------
+
+ -- Function: magit-display-buffer buffer
+
+ This function is a wrapper around ‘display-buffer’ and is used to
+ display any Magit buffer. It displays BUFFER in some window and,
+ unlike ‘display-buffer’, also selects that window, provided
+ ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks
+ mentioned below.
+
+ -- Variable: magit-display-buffer-noselect
+
+ When this is non-nil, then ‘magit-display-buffer’ only displays the
+ buffer but forgoes also selecting the window. This variable should
+ not be set globally, it is only intended to be let-bound, by code
+ that automatically updates "the other window". This is used for
+ example when the revision buffer is updated when you move inside
+ the log buffer.
+
+ -- User Option: magit-display-buffer-function
+
+ The function specified here is called by ‘magit-display-buffer’
+ with one argument, a buffer, to actually display that buffer. This
+ function should call ‘display-buffer’ with that buffer as first and
+ a list of display actions as second argument.
+
+ Magit provides several functions, listed below, that are suitable
+ values for this option. If you want to use different rules, then a
+ good way of doing that is to start with a copy of one of these
+ functions and then adjust it to your needs.
+
+ Instead of using a wrapper around ‘display-buffer’, that function
+ itself can be used here, in which case the display actions have to
+ be specified by adding them to ‘display-buffer-alist’ instead.
+
+ To learn about display actions, see *note (elisp)Choosing a Window
+ for Display::.
+
+ -- Function: magit-display-buffer-traditional buffer
+
+ This function is the current default value of the option
+ ‘magit-display-buffer-function’. Before that option and this
+ function were added, the behavior was hard-coded in many places all
+ over the code base but now all the rules are contained in this one
+ function (except for the "noselect" special case mentioned above).
+
+ -- Function: magit-display-buffer-same-window-except-diff-v1
+
+ This function displays most buffers in the currently selected
+ window. If a buffer’s mode derives from ‘magit-diff-mode’ or
+ ‘magit-process-mode’, it is displayed in another window.
+
+ -- Function: magit-display-buffer-fullframe-status-v1
+
+ This function fills the entire frame when displaying a status
+ buffer. Otherwise, it behaves like
+ ‘magit-display-buffer-traditional’.
+
+ -- Function: magit-display-buffer-fullframe-status-topleft-v1
+
+ This function fills the entire frame when displaying a status
+ buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’
+ except that it displays buffers that derive from ‘magit-diff-mode’
+ or ‘magit-process-mode’ to the top or left of the current buffer
+ rather than to the bottom or right. As a result, Magit buffers
+ tend to pop up on the same side as they would if
+ ‘magit-display-buffer-traditional’ were in use.
+
+ -- Function: magit-display-buffer-fullcolumn-most-v1
+
+ This function displays most buffers so that they fill the entire
+ height of the frame. However, the buffer is displayed in another
+ window if 1) the buffer’s mode derives from ‘magit-process-mode’,
+ or 2) the buffer’s mode derives from ‘magit-diff-mode’, provided
+ that the mode of the current buffer derives from ‘magit-log-mode’
+ or ‘magit-cherry-mode’.
+
+ -- User Option: magit-pre-display-buffer-hook
+
+ This hook is run by ‘magit-display-buffer’ before displaying the
+ buffer.
+
+ -- Function: magit-save-window-configuration
+
+ This function saves the current window configuration. Later when
+ the buffer is buried, it may be restored by
+ ‘magit-restore-window-configuration’.
+
+ -- User Option: magit-post-display-buffer-hook
+
+ This hook is run by ‘magit-display-buffer’ after displaying the
+ buffer.
+
+ -- Function: magit-maybe-set-dedicated
+
+ This function remembers if a new window had to be created to
+ display the buffer, or whether an existing window was reused. This
+ information is later used by ‘magit-mode-quit-window’, to determine
+ whether the window should be deleted when its last Magit buffer is
+ buried.
+
+\1f
+File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers
+
+4.1.2 Naming Buffers
+--------------------
+
+ -- User Option: magit-generate-buffer-name-function
+
+ The function used to generate the names of Magit buffers.
+
+ Such a function should take the options
+ ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’
+ into account. If it doesn’t, then should be clearly stated in the
+ doc-string. And if it supports %-sequences beyond those mentioned
+ in the doc-string of the option ‘magit-buffer-name-format’, then
+ its own doc-string should describe the additions.
+
+ -- Function: magit-generate-buffer-name-default-function mode
+
+ This function returns a buffer name suitable for a buffer whose
+ major-mode is MODE and which shows information about the repository
+ in which ‘default-directory’ is located.
+
+ This function uses ‘magit-buffer-name-format’ and supporting all of
+ the %-sequences mentioned the documentation of that option. It
+ also respects the option ‘magit-uniquify-buffer-names’.
+
+ -- User Option: magit-buffer-name-format
+
+ The format string used to name Magit buffers.
+
+ At least the following %-sequences are supported:
+
+ • ‘%m’
+
+ The name of the major-mode, but with the ‘-mode’ suffix
+ removed.
+
+ • ‘%M’
+
+ Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’.
+
+ • ‘%v’
+
+ The value the buffer is locked to, in parentheses, or an empty
+ string if the buffer is not locked to a value.
+
+ • ‘%V’
+
+ Like ‘%v’, but the string is prefixed with a space, unless it
+ is an empty string.
+
+ • ‘%t’
+
+ The top-level directory of the working tree of the repository,
+ or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation
+ of that.
+ The value should always contain either ‘%m’ or ‘%M’, ‘%v’ or ‘%V’,
+ and ‘%t’. If ‘magit-uniquify-buffer-names’ is non-nil, then the
+ value must end with ‘%t’.
+
+ -- User Option: magit-uniquify-buffer-names
+
+ This option controls whether the names of Magit buffers are
+ uniquified. If the names are not being uniquified, then they
+ contain the full path of the top-level of the working tree of the
+ corresponding repository. If they are being uniquified, then they
+ end with the basename of the top-level, or if that would conflict
+ with the name used for other buffers, then the names of all these
+ buffers are adjusted until they no longer conflict.
+
+ This is done using the ‘uniquify’ package; customize its options to
+ control how buffer names are uniquified.
+
+\1f
+File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers
+
+4.1.3 Quitting Windows
+----------------------
+
+‘q’ (‘magit-mode-bury-buffer’)
+
+ This command buries the current Magit buffer. With a prefix
+ argument, it instead kills the buffer.
+
+ -- User Option: magit-bury-buffer-function
+
+ The function used to actually bury or kill the current buffer.
+
+ ‘magit-mode-bury-buffer’ calls this function with one argument. If
+ the argument is non-nil, then the function has to kill the current
+ buffer. Otherwise it has to bury it alive. The default value
+ currently is ‘magit-restore-window-configuration’.
+
+ -- Function: magit-restore-window-configuration kill-buffer
+
+ Bury or kill the current buffer using ‘quit-window’, which is
+ called with KILL-BUFFER as first and the selected window as second
+ argument.
+
+ Then restore the window configuration that existed right before the
+ current buffer was displayed in the selected frame. Unfortunately
+ that also means that point gets adjusted in all the buffers, which
+ are being displayed in the selected frame.
+
+ -- Function: magit-mode-quit-window kill-buffer
+
+ Bury or kill the current buffer using ‘quit-window’, which is
+ called with KILL-BUFFER as first and the selected window as second
+ argument.
+
+ Then, if the window was originally created to display a Magit
+ buffer and the buried buffer was the last remaining Magit buffer
+ that was ever displayed in the window, then that is deleted.
+
+\1f
+File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers
+
+4.1.4 Automatic Refreshing of Magit Buffers
+-------------------------------------------
+
+After running a command which may change the state of the current
+repository, the current Magit buffer and the corresponding status buffer
+are refreshed. The status buffer may optionally be automatically
+refreshed whenever a buffer is saved to a file inside the respective
+repository.
+
+ Automatically refreshing Magit buffers ensures that the displayed
+information is up-to-date most of the time but can lead to a noticeable
+delay in big repositories. Other Magit buffers are not refreshed to
+keep the delay to a minimum and also because doing so can sometimes be
+undesirable.
+
+ Buffers can also be refreshed explicitly, which is useful in buffers
+that weren’t current during the last refresh and after changes were made
+to the repository outside of Magit.
+
+‘g’ (‘magit-refresh’)
+
+ This command refreshes the current buffer if its major mode derives
+ from ‘magit-mode’ as well as the corresponding status buffer.
+
+ If the option ‘magit-revert-buffers’ calls for it, then it also
+ reverts all unmodified buffers that visit files being tracked in
+ the current repository.
+
+‘G’ (‘magit-refresh-all’)
+
+ This command refreshes all Magit buffers belonging to the current
+ repository and also reverts all unmodified buffers that visit files
+ being tracked in the current repository.
+
+ The file-visiting buffers are always reverted, even if
+ ‘magit-revert-buffers’ is nil.
+
+ -- User Option: magit-refresh-buffer-hook
+
+ This hook is run in each Magit buffer that was refreshed during the
+ current refresh - normally the current buffer and the status
+ buffer.
+
+ -- User Option: magit-refresh-status-buffer
+
+ When this option is non-nil, then the status buffer is
+ automatically refreshed after running git for side-effects, in
+ addition to the current Magit buffer, which is always refreshed
+ automatically.
+
+ Only set this to nil after exhausting all other options to improve
+ performance.
+
+ -- Function: magit-after-save-refresh-status
+
+ This function is intended to be added to ‘after-save-hook’. After
+ doing that the corresponding status buffer is refreshed whenever a
+ buffer is saved to a file inside a repository.
+
+ 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.
+
+\1f
+File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers
+
+4.1.5 Automatic Saving of File-Visiting Buffers
+-----------------------------------------------
+
+File-visiting buffers are by default saved at certain points in time.
+This doesn’t guarantee that Magit buffers are always up-to-date, but,
+provided one only edits files by editing them in Emacs and uses only
+Magit to interact with Git, one can be fairly confident. When in doubt
+or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh
+explicitly.
+
+ -- User Option: magit-save-repository-buffers
+
+ This option controls whether file-visiting buffers are saved before
+ certain events.
+
+ If this is non-nil then all modified file-visiting buffers
+ belonging to the current repository may be saved before running
+ commands, before creating new Magit buffers, and before explicitly
+ refreshing such buffers. If this is ‘dontask’ then this is done
+ without user intervention. If it is ‘t’ then the user has to
+ confirm each save.
+
+\1f
+File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers
+
+4.1.6 Automatic Reverting of File-Visiting Buffers
+--------------------------------------------------
+
+By default Magit automatically reverts buffers that are visiting files
+that are being tracked in a Git repository, after they have changed on
+disk. When using Magit one often changes files on disk by running git,
+i.e. "outside Emacs", making this a rather important feature.
+
+ For example, if you discard a change in the status buffer, then that
+is done by running ‘git apply --reverse ...’, and Emacs considers the
+file to have "changed on disk". If Magit did not automatically revert
+the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in
+the visiting buffer before you could continue making changes.
+
+ -- User Option: magit-auto-revert-mode
+
+ When this mode is enabled, then buffers that visit tracked files,
+ are automatically reverted after the visited files changed on disk.
+
+ -- User Option: global-auto-revert-mode
+
+ When this mode is enabled, then any file-visiting buffer is
+ automatically reverted after the visited file changed on disk.
+
+ If you like buffers that visit tracked files to be automatically
+ reverted, then you might also like any buffer to be reverted, not
+ just those visiting tracked files. If that is the case, then
+ enable this mode _instead of_ ‘magit-auto-revert-mode’.
+
+ -- User Option: magit-auto-revert-immediately
+
+ This option controls whether Magit reverts buffers immediately.
+
+ If this is non-nil and either ‘global-auto-revert-mode’ or
+ ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts
+ buffers by explicitly calling ‘auto-revert-buffers’ after running
+ git for side-effects.
+
+ If ‘auto-revert-use-notify’ is non-nil (and file notifications are
+ actually supported), then ‘magit-auto-revert-immediately’ does not
+ have to be non-nil, because the reverts happen immediately anyway.
+
+ If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are
+ both ‘nil’, then reverts happen after ‘auto-revert-interval’
+ seconds of user inactivity. That is not desirable.
+
+ -- User Option: auto-revert-use-notify
+
+ This option controls whether file notification functions should be
+ used. Note that this variable unfortunately defaults to ‘t’ even
+ on systems on which file notifications cannot be used.
+
+ -- User Option: magit-auto-revert-tracked-only
+
+ This option controls whether ‘magit-auto-revert-mode’ only reverts
+ tracked files or all files that are located inside Git
+ repositories, including untracked files and files located inside
+ Git’s control directory.
+
+ -- Command: auto-revert-mode
+
+ The global mode ‘magit-auto-revert-mode’ works by turning on this
+ local mode in the appropriate buffers (but
+ ‘global-auto-revert-mode’ is implemented differently). You can
+ also turn it on or off manually, which might be necessary if Magit
+ does not notice that a previously untracked file now is being
+ tracked or vice-versa.
+
+ -- User Option: auto-revert-stop-on-user-input
+
+ This option controls whether the arrival of user input suspends the
+ automatic reverts for ‘auto-revert-interval’ seconds.
+
+ -- User Option: auto-revert-interval
+
+ This option controls for how many seconds Emacs waits before
+ resuming suspended reverts.
+
+ -- User Option: auto-revert-buffer-list-filter
+
+ This option specifies an additional filter used by
+ ‘auto-revert-buffers’ to determine whether a buffer should be
+ reverted or not.
+
+ This option is provided by ‘magit’, which also redefines
+ ‘auto-revert-buffers’ to respect it. Magit users who do not turn
+ on the local mode ‘auto-revert-mode’ themselves, are best served by
+ setting the value to ‘magit-auto-revert-repository-buffers-p’.
+
+ However the default is nil, to not disturb users who do use the
+ local mode directly. If you experience delays when running Magit
+ commands, then you should consider using one of the predicates
+ provided by Magit - especially if you also use Tramp.
+
+ Users who do turn on ‘auto-revert-mode’ in buffers in which Magit
+ doesn’t do that for them, should likely not use any filter. Users
+ who turn on ‘global-auto-revert-mode’, do not have to worry about
+ this option, because it is disregarded if the global mode is
+ enabled.
+
+ -- User Option: auto-revert-verbose
+
+ This option controls whether Emacs reports when a buffer has been
+ reverted.
+
+ The options with the ‘auto-revert-’ prefix are located in the Custom
+group named ‘auto-revert’. The other, magit-specific, options are
+located in the ‘magit’ group.
+
+* Menu:
+
+* Risk of Reverting Automatically::
+
+\1f
+File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers
+
+Risk of Reverting Automatically
+...............................
+
+For the vast majority users automatically reverting file-visiting
+buffers after they have changed on disk is harmless.
+
+ If a buffer is modified (i.e. it contains changes that haven’t been
+saved yet), then Emacs would refuse to automatically revert it. If you
+save a previously modified buffer, then that results in what is seen by
+Git as an uncommitted change. Git would then refuse to carry out any
+commands that would cause these changes to be lost. In other words, if
+there is anything that could be lost, then either Git or Emacs would
+refuse to discard the changes.
+
+ However if you do use file-visiting buffers as a sort of ad hoc
+"staging area", then the automatic reverts could potentially cause data
+loss. So far I have only heard from one user who uses such a workflow.
+
+ An example: You visit some file in a buffer, edit it, and save the
+changes. Then, outside of Emacs (or at least not using Magit or by
+saving the buffer) you change the file on disk again. At this point the
+buffer is the only place where the intermediate version still exists.
+You have saved the changes to disk, but that has since been overwritten.
+Meanwhile Emacs considers the buffer to be unmodified (because you have
+not made any changes to it since you last saved it to the visited file)
+and therefore would not object to it being automatically reverted. At
+this point an Auto-Revert mode would kick in. It would check whether
+the buffer is modified and since that is not the case it would revert
+it. The intermediate version would be lost. (Actually you could still
+get it back using the ‘undo’ command.)
+
+ If your workflow depends on Emacs preserving the intermediate version
+in the buffer, then you have to disable all Auto-Revert modes. But
+please consider that such a workflow would be dangerous even without
+using an Auto-Revert mode, and should therefore be avoided. If Emacs
+crashed or if you quit Emacs by mistake, then you would also lose the
+buffer content. There would be no autosave file still containing the
+intermediate version (because that was deleted when you saved the
+buffer) and you would not be asked whether you want to save the buffer
+(because it isn’t modified).
+
+\1f
+File: magit.info, Node: Sections, Next: Popup buffers and prefix commands, Prev: Modes and Buffers, Up: Interface concepts
+
+4.2 Sections
+============
+
+Magit buffers are organized into nested sections, which can be collapsed
+and expanded, similar to how sections are handled in Org mode. Each
+section also has a type, and some sections also have a value. For each
+section type there can also be a local keymap, shared by all sections of
+that type.
+
+ Taking advantage of the section value and type, many commands operate
+on the current section, or when the region is active and selects
+sections of the same type, all of the selected sections. Commands that
+only make sense for a particular section type (as opposed to just
+behaving differently depending on the type) are usually bound in section
+type keymaps.
+
+* Menu:
+
+* Section movement::
+* Section visibility::
+* Section hooks::
+* Section types and values::
+* Section options::
+
+\1f
+File: magit.info, Node: Section movement, Next: Section visibility, Up: Sections
+
+4.2.1 Section movement
+----------------------
+
+To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’
+etc), whose global bindings are not shadowed. To move to another
+section use the following commands.
+
+‘p’ (‘magit-section-backward’)
+
+ When not at the beginning of a section, then move to the beginning
+ of the current section. At the beginning of a section, instead
+ move to the beginning of the previous visible section.
+
+‘n’ (‘magit-section-forward’)
+
+ Move to the beginning of the next visible section.
+
+‘M-p’ (‘magit-section-backward-siblings’)
+
+ Move to the beginning of the previous sibling section. If there is
+ no previous sibling section, then move to the parent section
+ instead.
+
+‘M-n’ (‘magit-section-forward-siblings’)
+
+ Move to the beginning of the next sibling section. If there is no
+ next sibling section, then move to the parent section instead.
+
+‘^’ (‘magit-section-up’)
+
+ Move to the beginning of the parent of the current section.
+
+ The above commands all call the hook ‘magit-section-movement-hook’.
+And, except for the second, the below functions are all members of that
+hook’s default value.
+
+ -- Variable: magit-section-movement-hook
+
+ This hook is run by all of the above movement commands, after
+ arriving at the destination.
+
+ -- Function: magit-hunk-set-window-start
+
+ This hook function ensures that the beginning of the current
+ section is visible, provided it is a ‘hunk’ section. Otherwise, it
+ does nothing.
+
+ -- Function: magit-section-set-window-start
+
+ This hook function ensures that the beginning of the current
+ section is visible, regardless of the section’s type. If you add
+ this to ‘magit-section-movement-hook’, then you must remove the
+ hunk-only variant in turn.
+
+ -- Function: magit-log-maybe-show-more-commits
+
+ This hook function only has an effect in log buffers, and ‘point’
+ is on the "show more" section. If that is the case, then it
+ doubles the number of commits that are being shown.
+
+ -- Function: magit-log-maybe-update-revision-buffer
+
+ When moving inside a log buffer, then this function updates the
+ revision buffer, provided it is already being displayed in another
+ window of the same frame.
+
+ -- Function: magit-log-maybe-update-blob-buffer
+
+ When moving inside a log buffer and another window of the same
+ frame displays a blob buffer, then this function instead displays
+ the blob buffer for the commit at point in that window.
+
+ -- Function: magit-status-maybe-update-revision-buffer
+
+ When moving inside a status buffer, then this function updates the
+ revision buffer, provided it is already being displayed in another
+ window of the same frame.
+
+ -- Function: magit-status-maybe-update-blob-buffer
+
+ When moving inside a status buffer and another window of the same
+ frame displays a blob buffer, then this function instead displays
+ the blob buffer for the commit at point in that window.
+
+ -- User Option: magit-update-other-window-delay
+
+ Delay before automatically updating the other window.
+
+ When moving around in certain buffers certain other buffers, which
+ are being displayed in another window, may optionally be updated to
+ display information about the section at point.
+
+ When holding down a key to move by more than just one section, then
+ that would update that buffer for each section on the way. To
+ prevent that, updating the revision buffer is delayed, and this
+ option controls for how long. For optimal experience you might
+ have to adjust this delay and/or the keyboard repeat rate and delay
+ of your graphical environment or operating system.
+
+\1f
+File: magit.info, Node: Section visibility, Next: Section hooks, Prev: Section movement, Up: Sections
+
+4.2.2 Section visibility
+------------------------
+
+Magit provides many commands for changing the visibility of sections,
+but all you need to get started are the next two.
+
+‘TAB’ (‘magit-section-toggle’)
+
+ Toggle the visibility of the body of the current section.
+
+‘C-<tab>’ (‘magit-section-cycle’)
+
+ Cycle the visibility of current section and its children.
+
+‘M-<tab>’ (‘magit-section-cycle-diffs’)
+
+ Cycle the visibility of diff-related sections in the current
+ buffer.
+
+‘S-<tab>’ (‘magit-section-cycle-global’)
+
+ Cycle the visibility of all sections in the current buffer.
+
+ -- Command: magit-section-show-level-1
+ -- Command: magit-section-show-level-2
+ -- Command: magit-section-show-level-3
+ -- Command: magit-section-show-level-4
+
+ To show sections surrounding the current section, up to level N,
+ press the respective number key (‘1’, ‘2’, ‘3’, or ‘4’).
+
+ -- Command: magit-section-show-level-1-all
+ -- Command: magit-section-show-level-2-all
+ -- Command: magit-section-show-level-3-all
+ -- Command: magit-section-show-level-4-all
+
+ To show all sections up to level N, press the respective number key
+ and meta (‘M-1’, ‘M-2’, ‘M-3’, or ‘M-4’).
+
+ Some functions, which are used to implement the above commands, are
+also exposed as commands themselves. By default no keys are bound to
+these commands, as they are generally perceived to be much less useful.
+But your mileage may vary.
+
+ -- Command: magit-section-show
+
+ Show the body of the current section.
+
+ -- Command: magit-section-hide
+
+ Hide the body of the current section.
+
+ -- Command: magit-section-show-headings
+
+ Recursively show headings of children of the current section. Only
+ show the headings. Previously shown text-only bodies are hidden.
+
+ -- Command: magit-section-show-children
+
+ Recursively show the bodies of children of the current section.
+ With a prefix argument show children down to the level of the
+ current section, and hide deeper children.
+
+ -- Command: magit-section-hide-children
+
+ Recursively hide the bodies of children of the current section.
+
+ -- Command: magit-section-toggle-children
+
+ Toggle visibility of bodies of children of the current section.
+
+ When a buffer is first created then some sections are shown expanded
+while others are not. This is hard coded. When a buffer is refreshed
+then the previous visibility is preserved. The initial visibility of
+certain sections can also be overwritten using the hook
+‘magit-section-set-visibility-hook’.
+
+ -- Variable: magit-section-set-visibility-hook
+
+ This hook is run when first creating a buffer and also when
+ refreshing an existing buffer, and is used to determine the
+ visibility of the section currently being inserted.
+
+ Each function is called with one argument, the section being
+ inserted. It should return ‘hide’ or ‘show’, or to leave the
+ visibility undefined ‘nil’. If no function decides on the
+ visibility and the buffer is being refreshed, then the visibility
+ is preserved; or if the buffer is being created, then the hard
+ coded default is used.
+
+ Usually this should only be used to set the initial visibility but
+ not during refreshes. If ‘magit-insert-section--oldroot’ is
+ non-nil, then the buffer is being refreshed and these functions
+ should immediately return ‘nil’.
+
+\1f
+File: magit.info, Node: Section hooks, Next: Section types and values, Prev: Section visibility, Up: Sections
+
+4.2.3 Section hooks
+-------------------
+
+Which sections are inserted into certain buffers is controlled with
+hooks. This includes the status and the refs buffers. For other
+buffers, e.g. log, diff, and revision buffers, this is not possible.
+
+ For buffers whose sections can be customized by the user, a hook
+variable called ‘magit-TYPE-sections-hook’ exists. This hook should be
+changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the
+Custom interface.
+
+ The various available section hook variables are described later in
+this manual along with the appropriate "section inserter functions".
+
+ -- Function: magit-add-section-hook hook function &optional at append
+ local
+
+ Add the function FUNCTION to the value of section hook HOOK.
+
+ Add FUNCTION at the beginning of the hook list unless optional
+ APPEND is non-nil, in which case FUNCTION is added at the end. If
+ FUNCTION already is a member then move it to the new location.
+
+ If optional AT is non-nil and a member of the hook list, then add
+ FUNCTION next to that instead. Add before or after AT, or replace
+ AT with FUNCTION depending on APPEND. If APPEND is the symbol
+ ‘replace’, then replace AT with FUNCTION. For any other non-nil
+ value place FUNCTION right after AT. If nil, then place FUNCTION
+ right before AT. If FUNCTION already is a member of the list but AT
+ is not, then leave FUNCTION where ever it already is.
+
+ If optional LOCAL is non-nil, then modify the hook’s buffer-local
+ value rather than its global value. This makes the hook local by
+ copying the default value. That copy is then modified.
+
+ HOOK should be a symbol. If HOOK is void, it is first set to nil.
+ HOOK’s value must not be a single hook function. FUNCTION should
+ be a function that takes no arguments and inserts one or multiple
+ sections at point, moving point forward. FUNCTION may choose not
+ to insert its section(s), when doing so would not make sense. It
+ should not be abused for other side-effects.
+
+ To remove a function from a section hook, use ‘remove-hook’.
+
+\1f
+File: magit.info, Node: Section types and values, Next: Section options, Prev: Section hooks, Up: Sections
+
+4.2.4 Section types and values
+------------------------------
+
+Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’.
+Instances of certain section types also have a value. The value of a
+section of type ‘file’, for example, is a file name.
+
+ Users usually do not have to worry about a section’s type and value,
+but knowing them can be handy at times.
+
+‘M-x magit-describe-section’ (‘magit-describe-section’)
+
+ Show information about the section at point in the echo area, as
+ "VALUE [TYPE PARENT-TYPE…] BEGINNING-END".
+
+ Many commands behave differently depending on the type of the section
+at point and/or somehow consume the value of that section. But that is
+only one of the reasons why the same key may do something different,
+depending on what section is current.
+
+ Additionally for each section type a keymap *might* be defined, named
+‘magit-TYPE-section-map’. That keymap is used as text property keymap
+of all text belonging to any section of the respective type. If such a
+map does not exist for a certain type, then you can define it yourself,
+and it will automatically be used.
+
+\1f
+File: magit.info, Node: Section options, Prev: Section types and values, Up: Sections
+
+4.2.5 Section options
+---------------------
+
+This section describes options that have an effect on more than just a
+certain type of sections. As you can see there are not many of those.
+
+ -- User Option: magit-section-show-child-count
+
+ Whether to append the number of children to section headings. This
+ only affects sections that could benefit from this information.
+
+\1f
+File: magit.info, Node: Popup buffers and prefix commands, Next: Completion and confirmation, Prev: Sections, Up: Interface concepts
+
+4.3 Popup buffers and prefix commands
+=====================================
+
+Many Magit commands are implemented using *popup buffers*. First the
+user invokes a *popup* or *prefix* command, which causes a popup buffer
+with the available *infix* arguments and *suffix* commands to be
+displayed. The user then optionally toggles/sets some arguments and
+finally invokes one of the suffix commands.
+
+ This is implemented in the library ‘magit-popup’. Earlier releases
+used the library ‘magit-key-mode’. A future release will switch to a
+yet-to-be-written successor, which will likely be named ‘transient’.
+
+ Because ‘magit-popup’ can also be used by other packages without
+having to depend on all of Magit, it is documented in its own manual.
+See *note (magit-popup)Top::.
+
+‘C-c C-c’ (‘magit-dispatch-popup’)
+
+ This popup command shows a buffer featuring all other Magit popup
+ commands as well as some other commands that are not popup commands
+ themselves.
+
+ This command is also, or especially, useful outside Magit buffers, so
+you should setup a global binding:
+
+ (global-set-key (kbd "C-x M-g") 'magit-dispatch-popup)
+
+\1f
+File: magit.info, Node: Completion and confirmation, Next: Running Git, Prev: Popup buffers and prefix commands, Up: Interface concepts
+
+4.4 Completion and confirmation
+===============================
+
+Many commands read a value from the user. By default this is done using
+the built-in function ‘completing-read’, but Magit can instead use
+another completion framework.
+
+ -- User Option: magit-completing-read-function
+
+ The value of this variable is the function used to perform
+ completion. Because functions _intended_ to replace
+ ‘completing-read’ often are not fully compatible drop-in
+ replacements, and also because Magit expects them to add the
+ default choice to the prompt themselves, such functions should not
+ be used directly. Instead a wrapper function has to be used.
+
+ Currently only the real ‘completing-read’ and Ido
+(http://www.emacswiki.org/emacs/InteractivelyDoThings) are fully
+supported. More frameworks will be supported in the future.
+
+ -- Function: magit-builtin-completing-read prompt choices &optional
+ predicate require-match initial-input hist def
+
+ Perform completion using ‘completion-read’.
+
+ -- Function: magit-ido-completing-read prompt choices &optional
+ predicate require-match initial-input hist def
+
+ Perform completion using ‘ido-completing-read+’ from the package by
+ the same name (which you have to explicitly install). Ido itself
+ comes with a supposed drop-in replacement ‘ido-completing-read’,
+ but that has too many deficits to serve our needs.
+
+ By default many commands that could potentially lead to data loss
+have to be confirmed. This includes many very common commands, so this
+can become annoying quickly. Many of these actions can be undone,
+provided ‘magit-wip-before-change-mode’ is turned on (which it is not by
+default, due to performance concerns).
+
+ -- User Option: magit-no-confirm
+
+ The value of this option is a list of symbols, representing
+ commands which do not have to be confirmed by the user before being
+ carried out.
+
+ When the global mode ‘magit-wip-before-change-mode’ is enabled then
+ many commands can be undone. If that mode is enabled then adding
+ ‘safe-with-wip’ to this list has the same effect as adding
+ ‘discard’, ‘reverse’, ‘stage-all-changes’, and
+ ‘unstage-all-changes’.
+
+ (add-to-list 'magit-no-confirm 'safe-with-wip)
+
+ For a list of all symbols that can be added to the value of this
+ variable, see the doc-string.
+
+ Note that there are commands that ignore this option and always
+require confirmation, or which can be told not to do so using another
+dedicated option. Also most commands, when acting on multiple sections
+at once always, require confirmation, even when they do respect this
+option when acting on a single section.
+
+\1f
+File: magit.info, Node: Running Git, Prev: Completion and confirmation, Up: Interface concepts
+
+4.5 Running Git
+===============
+
+* Menu:
+
+* Viewing Git output::
+* Running Git manually::
+* Git executable::
+* Global Git arguments::
+
+\1f
+File: magit.info, Node: Viewing Git output, Next: Running Git manually, Up: Running Git
+
+4.5.1 Viewing Git output
+------------------------
+
+Magit runs Git either for side-effects (e.g. when pushing) or to get
+some value (e.g. the name of the current branch). When Git is run for
+side-effects then the output goes into a per-repository log buffer,
+which can be consulted when things don’t go as expected.
+
+‘$’ (‘magit-process’)
+
+ This commands displays the process buffer for the current
+ repository.
+
+ Inside that buffer, the usual key bindings for navigating and showing
+sections are available. There is one additional command.
+
+‘k’ (‘magit-process-kill’)
+
+ This command kills the process represented by the section at point.
+
+ -- User Option: magit-git-debug
+
+ When this is non-nil then the output of all calls to git are logged
+ in the process buffer. This is useful when debugging, otherwise it
+ just negatively affects performance.
+
+\1f
+File: magit.info, Node: Running Git manually, Next: Git executable, Prev: Viewing Git output, Up: Running Git
+
+4.5.2 Running Git manually
+--------------------------
+
+While Magit provides many Emacs commands to interact with Git, it does
+not cover everything. In those cases your existing Git knowledge will
+come in handy. Magit provides some commands for running arbitrary Git
+commands by typing them into the minibuffer, instead of having to switch
+to a shell.
+
+‘!’ (‘magit-run-popup’)
+
+ Shows the popup buffer featuring the below suffix commands.
+
+ These suffix commands run a Git subcommand. The user input has to
+begin with the subcommand, "git" is assumed.
+
+‘! !’ (‘magit-git-command-topdir’)
+
+ This command reads a Git subcommand from the user and executes it
+ in the top-level directory of the current repository.
+
+‘! p’ (‘magit-git-command’)
+
+ This command reads a Git subcommand from the user and executes it
+ in ‘default-directory’. With a prefix argument the command is
+ executed in the top-level directory of the current repository
+ instead.
+
+ These suffix commands run arbitrary shell commands.
+
+‘! s’ (‘magit-shell-command-topdir’)
+
+ This command reads a shell command from the user and executes it in
+ the top-level directory of the current repository.
+
+‘! S’ (‘magit-shell-command’)
+
+ This command reads a shell command from the user and executes it in
+ ‘default-directory’. With a prefix argument the command is
+ executed in the top-level directory of the current repository
+ instead.
+
+ These suffix commands start external gui tools.
+
+‘! k’ (‘magit-run-gitk’)
+
+ This command runs ‘gitk’ in the current repository.
+
+‘! a’ (‘magit-run-gitk-all’)
+
+ This command runs ‘gitk --all’ in the current repository.
+
+‘! b’ (‘magit-run-gitk-branches’)
+
+ This command runs ‘gitk --branches’ in the current repository.
+
+‘! g’ (‘magit-run-git-gui’)
+
+ This command runs ‘git gui’ in the current repository.
+
+\1f
+File: magit.info, Node: Git executable, Next: Global Git arguments, Prev: Running Git manually, Up: Running Git
+
+4.5.3 Git executable
+--------------------
+
+Except on MS Windows, Magit defaults to running Git without specifying
+the path to the git executable. Instead the first executable found by
+Emacs on ‘exec-path’ is used (whose value in turn is set based on the
+value of the environment variable ‘$PATH’ when Emacs was started).
+
+ This has the advantage that it continues to work even when using
+Tramp to connect to a remote machine on which the executable is found in
+a different place. The downside is that if you have multiple versions
+of Git installed, then you might end up using another version than the
+one you think you are using.
+
+‘M-x magit-version’ (‘magit-version’)
+
+ Shows the currently used versions of Magit, Git, and Emacs in the
+ echo area. Non-interactively this just returns the Magit version.
+
+ When the ‘system-type’ is ‘windows-nt’, then ‘magit-git-executable’
+is set to an absolute path when Magit is first loaded. This is
+necessary because Git on that platform comes with several wrapper
+scripts for the actual git binary, which are also placed on ‘$PATH’, and
+using one of these wrappers instead of the binary would degrade
+performance horribly.
+
+ If Magit doesn’t find the correct executable then you *can* work
+around that by setting ‘magit-git-executable’ to an absolute path. But
+note that doing so is a kludge. It is better to make sure the order in
+the environment variable ‘$PATH’ is correct, and that Emacs is started
+with that environment in effect. If you have to connect from Windows to
+a non-Windows machine, then you must change the value to "git".
+
+ -- User Option: magit-git-executable
+
+ The git executable used by Magit, either the full path to the
+ executable or the string "git" to let Emacs find the executable
+ itself, using the standard mechanism for doing such things.
+
+\1f
+File: magit.info, Node: Global Git arguments, Prev: Git executable, Up: Running Git
+
+4.5.4 Global Git arguments
+--------------------------
+
+ -- User Option: magit-git-global-arguments
+
+ The arguments set here are used every time the git executable is
+ run as a subprocess. They are placed right after the executable
+ itself and before the git command - as in ‘git HERE... COMMAND
+ REST’. For valid arguments see *note (gitman)git:: .
+
+ Be careful what you add here, especially if you are using Tramp to
+ connect to servers with ancient Git versions. Never remove
+ anything that is part of the default value, unless you really know
+ what you are doing. And think very hard before adding something;
+ it will be used every time Magit runs Git for any purpose.
+
+\1f
+File: magit.info, Node: Inspecting, Next: Manipulating, Prev: Interface concepts, Up: Top
+
+5 Inspecting
+************
+
+The functionality provided by Magit can be roughly divided into three
+groups: inspecting existing data, manipulating existing data or adding
+new data, and transferring data. Of course that is a rather crude
+distinction that often falls short, but it’s more useful than no
+distinction at all. This section is concerned with inspecting data, the
+next two with manipulating and transferring it. Then follows a section
+about miscellaneous functionality, which cannot easily be fit into this
+distinction.
+
+ Of course other distinctions make sense too, e.g. Git’s distinction
+between porcelain and plumbing commands, which for the most part is
+equivalent to Emacs’ distinction between interactive commands and
+non-interactive functions. All of the sections mentioned before are
+mainly concerned with the porcelain – Magit’s plumbing layer is
+described later.
+
+* Menu:
+
+* Status buffer::
+* Repository list::
+* Logging::
+* Diffing::
+* Ediffing::
+* References buffer::
+* Bisecting::
+* Visiting blobs::
+* Blaming::
+
+\1f
+File: magit.info, Node: Status buffer, Next: Repository list, Up: Inspecting
+
+5.1 Status buffer
+=================
+
+While other Magit buffers contain e.g. one particular diff or one
+particular log, the status buffer contains the diffs for staged and
+unstaged changes, logs for unpushed and unpulled commits, lists of
+stashes and untracked files, and information related to the current
+branch.
+
+ During certain incomplete operations – for example when a merge
+resulted in a conflict – additional information is displayed that helps
+proceeding with or aborting the operation.
+
+ The command ‘magit-status’ displays the status buffer belonging to
+the current repository in another window. This command is used so often
+that it should be bound globally. We recommend using ‘C-x g’:
+
+ (global-set-key (kbd "C-x g") 'magit-status)
+
+‘C-x g’ (‘magit-status’)
+
+ Show the status of the current Git repository in a buffer. With a
+ prefix argument prompt for a repository to be shown. With two
+ prefix arguments prompt for an arbitrary directory. If that
+ directory isn’t the root of an existing repository, then offer to
+ initialize it as a new repository.
+
+ -- User Option: magit-repository-directories
+
+ List of directories that are or contain Git repositories. Each
+ element has the form ‘(DIRECTORY . DEPTH)’ or, for backward
+ compatibility, just DIRECTORY. DIRECTORY has to be a directory or a
+ directory file-name, a string. DEPTH, an integer, specifies the
+ maximum depth to look for Git repositories. If it is 0, then only
+ add DIRECTORY itself. For elements that are strings, the value of
+ option ‘magit-repository-directories-depth’ specifies the depth.
+
+ -- User Option: magit-repository-directories-depth
+
+ The maximum depth to look for Git repositories. This option is
+ obsolete and only used for elements of the option
+ ‘magit-repository-directories’ (which see) that don’t specify the
+ depth directly.
+
+ -- Command: ido-enter-magit-status
+
+ From an Ido prompt used to open a file, instead drop into
+ ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which,
+ despite its name, usually causes a Dired buffer to be created.
+
+ To make this command available, use something like:
+
+ (add-hook 'ido-setup-hook
+ (lambda ()
+ (define-key ido-completion-map
+ (kbd \"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:
+
+ (define-key ido-common-completion-map
+ (kbd \"C-x g\") 'ido-enter-magit-status)
+
+* Menu:
+
+* Status sections::
+* Status header sections::
+* Status options::
+
+\1f
+File: magit.info, Node: Status sections, Next: Status header sections, Up: Status buffer
+
+5.1.1 Status sections
+---------------------
+
+The contents of status buffers is controlled using the hook
+‘magit-status-sections-hook’. See *note Section hooks: Section hooks.
+to learn about such hooks and how to customize them.
+
+ -- User Option: magit-status-sections-hook
+
+ Hook run to insert sections into a status buffer.
+
+ The first function on that hook by default is
+‘magit-insert-status-headers’; it is described in the next section. By
+default the following functions are also members of that hook:
+
+ -- Function: magit-insert-merge-log
+
+ Insert section for the on-going merge. Display the heads that are
+ being merged. If no merge is in progress, do nothing.
+
+ -- Function: magit-insert-rebase-sequence
+
+ Insert section for the on-going rebase sequence. If no such
+ sequence is in progress, do nothing.
+
+ -- Function: magit-insert-am-sequence
+
+ Insert section for the on-going patch applying sequence. If no
+ such sequence is in progress, do nothing.
+
+ -- Function: magit-insert-sequencer-sequence
+
+ Insert section for the on-going cherry-pick or revert sequence. If
+ no such sequence is in progress, do nothing.
+
+ -- Function: magit-insert-bisect-output
+
+ While bisecting, insert section with output from ‘git bisect’.
+
+ -- Function: magit-insert-bisect-rest
+
+ While bisecting, insert section visualizing the bisect state.
+
+ -- Function: magit-insert-bisect-log
+
+ While bisecting, insert section logging bisect progress.
+
+ -- Function: magit-insert-untracked-files
+
+ Maybe insert a list or tree 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’.
+
+ -- Function: magit-insert-unstaged-changes
+
+ Insert section showing unstaged changes.
+
+ -- Function: magit-insert-staged-changes
+
+ Insert section showing staged changes.
+
+ -- Function: magit-insert-stashes &optional ref heading
+
+ Insert the ‘stashes’ section showing reflog for "refs/stash". If
+ optional REF is non-nil show reflog for that instead. If optional
+ HEADING is non-nil use that as section heading instead of
+ "Stashes:".
+
+ -- Function: magit-insert-unpulled-from-upstream
+
+ Insert section showing commits that haven’t been pulled from the
+ upstream branch yet.
+
+ -- Function: magit-insert-unpulled-from-pushremote
+
+ Insert section showing commits that haven’t been pulled from the
+ push-remote branch yet.
+
+ -- Function: magit-insert-unpushed-to-upstream
+
+ Insert section showing commits that haven’t been pushed to the
+ upstream yet.
+
+ -- Function: magit-insert-unpushed-to-pushremote
+
+ Insert section showing commits that haven’t been pushed to the
+ push-remote yet.
+
+ The following functions can also be added to the above hook:
+
+ -- Function: magit-insert-tracked-files
+
+ Insert a tree of tracked files.
+
+ -- Function: magit-insert-unpulled-or-recent-commits
+
+ Insert section showing unpulled or recent commits. If an upstream
+ is configured for the current branch and it is ahead of the current
+ branch, then show the missing commits. Otherwise, show the last
+ ‘magit-log-section-commit-count’ commits.
+
+ -- Function: magit-insert-recent-commits
+
+ Insert section showing the last ‘magit-log-section-commit-count’
+ commits.
+
+ -- User Option: magit-log-section-commit-count
+
+ How many recent commits ‘magit-insert-recent-commits’ and
+ ‘magit-insert-unpulled-or-recent-commits’ (provided there are no
+ unpulled commits) show.
+
+ -- Function: magit-insert-modules-unpulled-from-upstream
+
+ Insert sections for modules that haven’t been pulled from the
+ upstream yet. These sections can be expanded to show the
+ respective commits.
+
+ -- Function: magit-insert-modules-unpulled-from-pushremote
+
+ Insert sections for modules that haven’t been pulled from the
+ push-remote yet. These sections can be expanded to show the
+ respective commits.
+
+ -- Function: magit-insert-modules-unpushed-to-upstream
+
+ Insert sections for modules that haven’t been pushed to the
+ upstream yet. These sections can be expanded to show the
+ respective commits.
+
+ -- Function: magit-insert-modules-unpushed-to-pushremote
+
+ Insert sections for modules that haven’t been pushed to the
+ push-remote yet. These sections can be expanded to show the
+ respective commits.
+
+ -- Function: magit-insert-submodules
+
+ Insert sections for all submodules. For each section insert the
+ path, the branch, and the output of ‘git describe --tags’.
+
+ Press ‘RET’ on such a submodule section to show its own status
+ buffer. Press ‘RET’ on the "Modules" section to display a list of
+ submodules in a separate buffer. This shows additional information
+ not displayed in the super-repository’s status buffer.
+
+ -- Function: magit-insert-unpulled-cherries
+
+ Insert section showing unpulled commits. Like
+ ‘magit-insert-unpulled-commits’ but prefix each commit that has not
+ been applied yet (i.e. a commit with a patch-id not shared with
+ any local commit) with "+", and all others with "-".
+
+ -- Function: magit-insert-unpushed-cherries
+
+ Insert section showing unpushed commits. Like
+ ‘magit-insert-unpushed-commits’ but prefix each commit which has
+ not been applied to upstream yet (i.e. a commit with a patch-id
+ not shared with any upstream commit) with "+" and all others with
+ "-".
+
+ See *note References buffer: References buffer. for some more section
+inserters, which could be used here.
+
+\1f
+File: magit.info, Node: Status header sections, Next: Status options, Prev: Status sections, Up: Status buffer
+
+5.1.2 Status header sections
+----------------------------
+
+The contents of status buffers is controlled using the hook
+‘magit-status-sections-hook’, as described in the previous section. By
+default ‘magit-insert-status-headers’ is the first member of that hook
+variable.
+
+ -- Function: magit-insert-status-headers
+
+ Insert headers sections appropriate for ‘magit-status-mode’
+ buffers. The sections are inserted by running the functions on the
+ hook ‘magit-status-headers-hook’.
+
+ -- User Option: magit-status-headers-hook
+
+ Hook run to insert headers sections into the status buffer.
+
+ This hook is run by ‘magit-insert-status-headers’, which in turn
+ has to be a member of ‘magit-status-sections-hook’ to be used at
+ all.
+
+ By default the following functions are members of the above hook:
+
+ -- Function: magit-insert-error-header
+
+ Insert a header line showing the message about the Git error that
+ just occurred.
+
+ This function is only aware of the last error that occur when Git
+ was run for side-effects. If, for example, an error occurs while
+ generating a diff, then that error won’t be inserted. Refreshing
+ the status buffer causes this section to disappear again.
+
+ -- Function: magit-insert-diff-filter-header
+
+ Insert a header line showing the effective diff filters.
+
+ -- Function: magit-insert-head-branch-header
+
+ Insert a header line about the current branch or detached ‘HEAD’.
+
+ -- Function: magit-insert-upstream-branch-header
+
+ Insert a header line about the branch that is usually pulled into
+ the current branch.
+
+ -- Function: magit-insert-push-branch-header
+
+ Insert a header line about the branch that the current branch is
+ usually pushed to.
+
+ -- Function: magit-insert-tags-header
+
+ Insert a header line about the current and/or next tag.
+
+ The following functions can also be added to the above hook:
+
+ -- Function: magit-insert-repo-header
+
+ Insert a header line showing the path to the repository top-level.
+
+ -- Function: magit-insert-remote-header
+
+ Insert a header line about the remote of the current branch.
+
+ If no remote is configured for the current branch, then fall back
+ showing the "origin" remote, or if that does not exist the first
+ remote in alphabetic order.
+
+ -- Function: magit-insert-user-header
+
+ Insert a header line about the current user.
+
+\1f
+File: magit.info, Node: Status options, Prev: Status header sections, Up: Status buffer
+
+5.1.3 Status options
+--------------------
+
+ -- User Option: magit-status-refresh-hook
+
+ Hook run after a status buffer has been refreshed.
+
+ -- User Option: magit-log-section-args
+
+ Additional Git arguments used when creating log sections. Only
+ ‘--graph’, ‘--decorate’, and ‘--show-signature’ are supported.
+ This option is only a temporary kludge and will be removed.
+
+ Note that due to an issue in Git the use of ‘--graph’ is very slow
+ with long histories, so you probably don’t want to add this here.
+
+ Also see the proceeding section for more options concerning status
+buffers.
+
+\1f
+File: magit.info, Node: Repository list, Next: Logging, Prev: Status buffer, Up: Inspecting
+
+5.2 Repository list
+===================
+
+ -- Command: magit-list-repositories
+
+ This command displays a list of repositories in a separate buffer.
+
+ The options ‘magit-repository-directories’ and
+ ‘magit-repository-directories-depth’ control which repositories are
+ displayed.
+
+ -- User Option: magit-repolist-columns
+
+ This option controls what columns are displayed by the command
+ ‘magit-list-repositories’ and how they are displayed.
+
+ Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’.
+
+ HEADER is the string displayed in the header. WIDTH is the width
+ of the column. FORMAT is a function that is called with one
+ argument, the repository identification (usually its basename), and
+ with ‘default-directory’ bound to the toplevel of its working tree.
+ It has to return a string to be inserted or nil. PROPS is an alist
+ that supports the keys ‘:right-align’ and ‘:pad-right’.
+
+ The following functions can be added to the above option:
+
+ -- Function: magit-repolist-column-ident
+
+ This function inserts the identification of the repository.
+ Usually this is just its basename.
+
+ -- Function: magit-repolist-column-path
+
+ This function inserts the absolute path of the repository.
+
+ -- Function: magit-repolist-column-version
+
+ This function inserts a description of the repository’s ‘HEAD’
+ revision.
+
+ -- Function: magit-repolist-column-unpulled-from-upstream
+
+ This function inserts the number of upstream commits not in the
+ current branch.
+
+ -- Function: magit-repolist-column-unpulled-from-pushremote
+
+ This function inserts the number of commits in the push branch but
+ not the current branch.
+
+ -- Function: magit-repolist-column-unpushed-to-upstream
+
+ This function inserts the number of commits in the current branch
+ but not its upstream.
+
+ -- Function: magit-repolist-column-unpushed-to-pushremote
+
+ This function inserts the number of commits in the current branch
+ but not its push branch.
+
+\1f
+File: magit.info, Node: Logging, Next: Diffing, Prev: Repository list, Up: Inspecting
+
+5.3 Logging
+===========
+
+The status buffer contains logs for the unpushed and unpulled commits,
+but that obviously isn’t enough. The prefix command ‘magit-log-popup’,
+on ‘l’, features several suffix commands, which show a specific log in a
+separate log buffer.
+
+ Like other popups, the log popup also features several arguments that
+can be changed before invoking one of the suffix commands. However in
+case of the log popup these arguments correspond to those currently in
+use in the current repository’s log buffer. When the log popup is
+invoked while no log buffer exists for the current repository yet, then
+the default value of ‘magit-log-arguments’ is used instead.
+
+ For information about the various arguments, see *note
+(gitman)git-log:: . The switch ‘++order=VALUE’ is converted to one of
+‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being
+passed to ‘git log’.
+
+ The log popup also features several reflog commands. See *note
+Reflog: Reflog.
+
+‘l’ (‘magit-log-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘l l’ (‘magit-log-current’)
+
+ Show log for the current branch. When ‘HEAD’ is detached or with a
+ prefix argument, show log for one or more revs read from the
+ minibuffer.
+
+‘l o’ (‘magit-log’)
+
+ Show log for one or more revs read from the minibuffer. The user
+ can input any revision or revisions separated by a space, or even
+ ranges, but only branches, tags, and a representation of the commit
+ at point are available as completion candidates.
+
+‘l h’ (‘magit-log-head’)
+
+ Show log for ‘HEAD’.
+
+‘l L’ (‘magit-log-branches’)
+
+ Show log for all local branches and ‘HEAD’.
+
+‘l b’ (‘magit-log-all-branches’)
+
+ Show log for all local and remote branches and ‘HEAD’.
+
+‘l a’ (‘magit-log-all’)
+
+ Show log for all references and ‘HEAD’.
+
+ The following related commands are not available from the popup.
+
+‘Y’ (‘magit-cherry’)
+
+ Show commits in a branch that are not merged in the upstream
+ branch.
+
+‘M-x magit-log-buffer-file’ (‘magit-log-buffer-file’)
+
+ Show log for the file visited in the current buffer.
+
+ Two additional commands that show the log for the file or blob that
+is being visited in the current buffer exists, see *note Minor mode for
+buffers visiting files: Minor mode for buffers visiting files.
+
+* Menu:
+
+* Refreshing logs::
+* Log Buffer::
+* Select from log::
+* Reflog::
+
+\1f
+File: magit.info, Node: Refreshing logs, Next: Log Buffer, Up: Logging
+
+5.3.1 Refreshing logs
+---------------------
+
+The prefix command ‘magit-log-refresh-popup’, on ‘L’, can be used to
+change the log arguments used in the current buffer, without changing
+which log is shown. This works in dedicated log buffers, but also in
+the status buffer.
+
+‘L’ (‘magit-log-refresh-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘L g’ (‘magit-log-refresh’)
+
+ This suffix command sets the local log arguments for the current
+ buffer.
+
+‘L s’ (‘magit-log-set-default-arguments’)
+
+ This suffix command sets the default log arguments for buffers of
+ the same type as that of the current buffer. Other existing
+ buffers of the same type are not affected because their local
+ values have already been initialized.
+
+‘L w’ (‘magit-log-save-default-arguments’)
+
+ This suffix command sets the default log arguments for buffers of
+ the same type as that of the current buffer, and saves the value
+ for future sessions. Other existing buffers of the same type are
+ not affected because their local values have already been
+ initialized.
+
+‘L t’ (‘magit-toggle-margin’)
+
+ Show or hide the margin.
+
+\1f
+File: magit.info, Node: Log Buffer, Next: Select from log, Prev: Refreshing logs, Up: Logging
+
+5.3.2 Log Buffer
+----------------
+
+‘L’ (‘magit-log-refresh-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer. See *note
+ Refreshing logs: Refreshing logs.
+
+‘q’ (‘magit-log-bury-buffer’)
+
+ Bury the current buffer or the revision buffer in the same frame.
+ Like ‘magit-mode-bury-buffer’ (which see) but with a negative
+ prefix argument instead bury the revision buffer, provided it is
+ displayed in the current frame.
+
+‘C-c C-b’ (‘magit-go-backward’)
+
+ Move backward in current buffer’s history.
+
+‘C-c C-f’ (‘magit-go-forward’)
+
+ Move forward in current buffer’s history.
+
+‘C-c C-n’ (‘magit-log-move-to-parent’)
+
+ Move to a parent of the current commit. By default, this is the
+ first parent, but a numeric prefix can be used to specify another
+ parent.
+
+‘SPC’ (‘magit-diff-show-or-scroll-up’)
+
+ Update the commit or diff buffer for the thing at point.
+
+ Either show the commit or stash at point in the appropriate buffer,
+ or if that buffer is already being displayed in the current frame
+ and contains information about that commit or stash, then instead
+ scroll the buffer up. If there is no commit or stash at point,
+ then prompt for a commit.
+
+‘DEL’ (‘magit-diff-show-or-scroll-down’)
+
+ Update the commit or diff buffer for the thing at point.
+
+ Either show the commit or stash at point in the appropriate buffer,
+ or if that buffer is already being displayed in the current frame
+ and contains information about that commit or stash, then instead
+ scroll the buffer down. If there is no commit or stash at point,
+ then prompt for a commit.
+
+‘=’ (‘magit-log-toggle-commit-limit’)
+
+ Toggle the number of commits the current log buffer is limited to.
+ If the number of commits is currently limited, then remove that
+ limit. Otherwise set it to 256.
+
+‘+’ (‘magit-log-double-commit-limit’)
+
+ Double the number of commits the current log buffer is limited to.
+
+‘=’ (‘magit-log-half-commit-limit’)
+
+ Half the number of commits the current log buffer is limited to.
+
+ -- User Option: magit-log-auto-more
+
+ Insert more log entries automatically when moving past the last
+ entry. Only considered when moving past the last entry with
+ ‘magit-goto-*-section’ commands.
+
+ -- User Option: magit-log-show-margin
+
+ Whether to initially show the margin in log buffers.
+
+ When non-nil the author name and date are initially displayed in
+ the margin of log buffers. The margin can be shown or hidden in
+ the current buffer using the command ‘magit-toggle-margin’.
+
+ When a log buffer contains a verbose log, then the margin is never
+ displayed. In status buffers this option is ignored, but it is
+ possible to show the margin using the mentioned command.
+
+ -- User Option: magit-log-show-refname-after-summary
+
+ Whether to show the refnames after the commit summaries. This is
+ useful if you use really long branch names.
+
+\1f
+File: magit.info, Node: Select from log, Next: Reflog, Prev: Log Buffer, Up: Logging
+
+5.3.3 Select from log
+---------------------
+
+When the user has to select a recent commit that is reachable from
+‘HEAD’, using regular completion would be inconvenient (because most
+humans cannot remember hashes or "HEAD~5", at least not without double
+checking). Instead a log buffer is used to select the commit, which has
+the advantage that commits are presented in order and with the commit
+message. The following additional key bindings are available when a log
+is used for selection:
+
+‘C-c C-c’ (‘magit-log-select-pick’)
+
+ Select the commit at point and act on it. Call
+ ‘magit-log-select-pick-function’ with the selected commit as
+ argument.
+
+‘C-c C-k’ (‘magit-log-select-quit’)
+
+ Abort selecting a commit, don’t act on any commit.
+
+ This feature is used by rebase and squash commands.
+
+\1f
+File: magit.info, Node: Reflog, Prev: Select from log, Up: Logging
+
+5.3.4 Reflog
+------------
+
+Also see *note (gitman)git-reflog:: .
+
+ These reflog commands are available from the log popup. See *note
+Logging: Logging.
+
+‘l r’ (‘magit-reflog-current’)
+
+ Display the reflog of the current branch.
+
+‘l O’ (‘magit-reflog-other’)
+
+ Display the reflog of a branch.
+
+‘l H’ (‘magit-reflog-head’)
+
+ Display the ‘HEAD’ reflog.
+
+\1f
+File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting
+
+5.4 Diffing
+===========
+
+The status buffer contains diffs for the staged and unstaged commits,
+but that obviously isn’t enough. The prefix command ‘magit-diff-popup’,
+on ‘d’, features several suffix commands, which show a specific diff in
+a separate diff buffer.
+
+ Like other popups, the diff popup also features several arguments
+that can be changed before invoking one of the suffix commands. However
+in case of the diff popup these arguments correspond to those currently
+in use in the current repository’s diff buffer. When the diff popup is
+invoked while no diff buffer exists for the current repository yet, then
+the default value of ‘magit-diff-arguments’ is used instead.
+
+ Also see *note (gitman)git-diff:: .
+
+‘d’ (‘magit-diff-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘d d’ (‘magit-diff-dwim’)
+
+ Show changes for the thing at point.
+
+‘d r’ (‘magit-diff’)
+
+ Show differences between two commits.
+
+ RANGE should be a range (A..B or A…B) but can also be a single
+ commit. If one side of the range is omitted, then it defaults to
+ HEAD. If just a commit is given, then changes in the working tree
+ relative to that commit are shown.
+
+ If the region is active, use the revisions on the first and last
+ line of the region. With a prefix argument, instead of diffing the
+ revisions, choose a revision to view changes along, starting at the
+ common ancestor of both revisions (i.e., use a "…" range).
+
+‘d w’ (‘magit-diff-worktree’)
+
+ Show changes between the current working tree and the ‘HEAD’
+ commit. With a prefix argument show changes between the working
+ tree and a commit read from the minibuffer.
+
+‘d s’ (‘magit-diff-staged’)
+
+ Show changes between the index and the ‘HEAD’ commit. With a
+ prefix argument show changes between the index and a commit read
+ from the minibuffer.
+
+‘d u’ (‘magit-diff-unstaged’)
+
+ Show changes between the working tree and the index.
+
+‘d p’ (‘magit-diff-paths’)
+
+ Show changes between any two files on disk.
+
+ All of the above suffix commands update the repository’s diff buffer.
+The diff popup also features two commands which show differences in
+another buffer:
+
+‘d c’ (‘magit-show-commit’)
+
+ Show the commit at point. If there is no commit at point or with a
+ prefix argument, prompt for a commit.
+
+‘d t’ (‘magit-stash-show’)
+
+ Show all diffs of a stash in a buffer.
+
+ Two additional commands that show the diff for the file or blob that
+is being visited in the current buffer exists, see *note Minor mode for
+buffers visiting files: Minor mode for buffers visiting files.
+
+* Menu:
+
+* Refreshing diffs::
+* Diff buffer::
+* Diff options::
+* Revision buffer::
+
+\1f
+File: magit.info, Node: Refreshing diffs, Next: Diff buffer, Up: Diffing
+
+5.4.1 Refreshing diffs
+----------------------
+
+The prefix command ‘magit-diff-refresh-popup’, on ‘D’, can be used to
+change the diff arguments used in the current buffer, without changing
+which diff is shown. This works in dedicated diff buffers, but also in
+the status buffer.
+
+‘D’ (‘magit-diff-refresh-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘D g’ (‘magit-diff-refresh’)
+
+ This suffix command sets the local diff arguments for the current
+ buffer.
+
+‘D s’ (‘magit-diff-set-default-arguments’)
+
+ This suffix command sets the default diff arguments for buffers of
+ the same type as that of the current buffer. Other existing
+ buffers of the same type are not affected because their local
+ values have already been initialized.
+
+‘D w’ (‘magit-diff-save-default-arguments’)
+
+ This suffix command sets the default diff arguments for buffers of
+ the same type as that of the current buffer, and saves the value
+ for future sessions. Other existing buffers of the same type are
+ not affected because their local values have already been
+ initialized.
+
+‘D t’ (‘magit-diff-toggle-refine-hunk’)
+
+ This command toggles hunk refinement on or off.
+
+‘D r’ (‘magit-diff-switch-range-type’)
+
+ This command converts the diff range type from "revA..revB" to
+ "revB…revA", or vice versa.
+
+‘D f’ (‘magit-diff-flip-revs’)
+
+ This command swaps revisions in the diff range from "revA..revB" to
+ "revB..revA", or vice versa.
+
+ In addition to the above popup, which allows changing any of the
+supported arguments, there also exist some commands which change a
+particular argument.
+
+‘-’ (‘magit-diff-less-context’)
+
+ This command decreases the context for diff hunks by COUNT lines.
+
+‘+’ (‘magit-diff-more-context’)
+
+ This command increases the context for diff hunks by COUNT lines.
+
+‘0’ (‘magit-diff-default-context’)
+
+ This command resets the context for diff hunks to the default
+ height.
+
+ The following commands quickly change what diff is being displayed
+without having to using one of the diff popups.
+
+‘C-c C-d’ (‘magit-diff-while-committing’)
+
+ While committing, this command shows the changes that are about to
+ be committed. While amending, invoking the command again toggles
+ between showing just the new changes or all the changes that will
+ be committed.
+
+ This binding is available in the diff buffer as well as the commit
+ message buffer.
+
+‘C-c C-b’ (‘magit-go-backward’)
+
+ This command moves backward in current buffer’s history.
+
+‘C-c C-f’ (‘magit-go-forward’)
+
+ This command moves forward in current buffer’s history.
+
+\1f
+File: magit.info, Node: Diff buffer, Next: Diff options, Prev: Refreshing diffs, Up: Diffing
+
+5.4.2 Diff buffer
+-----------------
+
+‘RET’ (‘magit-diff-visit-file’)
+
+ From a diff, visit the corresponding file at the appropriate
+ position.
+
+ If the diff shows changes in the worktree, the index, or ‘HEAD’,
+ then visit the actual file. Otherwise, when the diff is about an
+ older commit or a range, then visit the appropriate blob.
+
+ If point is on a removed line, then visit the blob for the first
+ parent of the commit which removed that line, i.e. the last commit
+ where that line still existed. Otherwise visit the blob for the
+ commit whose changes are being shown.
+
+ When the file or blob to be displayed is already being displayed in
+ another window of the same frame, then just select that window and
+ adjust point. Otherwise, or with a prefix argument, display the
+ buffer in another window.
+
+ -- User Option: magit-diff-visit-previous-blob
+
+ This option controls whether ‘magit-diff-visit-file’ may visit the
+ previous blob. When this is ‘t’ and point is on a removed line in
+ a diff for a committed change, then ‘magit-diff-visit-file’ visits
+ the blob from the last revision which still had that line.
+
+ Currently this is only supported for committed changes, for staged
+ and unstaged changes ‘magit-diff-visit-file’ always visits the file
+ in the working tree.
+
+‘C-<return>’ (‘magit-diff-visit-file-worktree’)
+
+ From a diff, visit the corresponding file at the appropriate
+ position.
+
+ When the file is already being displayed in another window of the
+ same frame, then just select that window and adjust point. With a
+ prefix argument also display in another window.
+
+ The actual file in the worktree is visited. The positions in the
+ hunk headers get less useful the "older" the changes are, and as a
+ result, jumping to the appropriate position gets less reliable.
+
+ Also see ‘magit-diff-visit-file-worktree’, which visits the
+ respective blob, unless the diff shows changes in the worktree, the
+ index, or ‘HEAD’.
+
+‘j’ (‘magit-jump-to-diffstat-or-diff’)
+
+ Jump to the diffstat or diff. When point is on a file inside the
+ diffstat section, then jump to the respective diff section.
+ Otherwise, jump to the diffstat section or a child thereof.
+
+‘SPC’ (‘scroll-up’)
+
+ Scroll text upward.
+
+‘DEL’ (‘scroll-down’)
+
+ Scroll text downward.
+
+\1f
+File: magit.info, Node: Diff options, Next: Revision buffer, Prev: Diff buffer, Up: Diffing
+
+5.4.3 Diff options
+------------------
+
+ -- User Option: magit-diff-refine-hunk
+
+ Whether to show word-granularity differences within diff hunks.
+
+ • ‘nil’ never show fine differences.
+
+ • ‘t’ show fine differences for the current diff hunk only.
+
+ • ‘all’ show fine differences for all displayed diff hunks.
+
+ -- User Option: magit-diff-paint-whitespace
+
+ Specify where to highlight whitespace errors.
+
+ See ‘magit-highlight-trailing-whitespace’,
+ ‘magit-highlight-indentation’. The symbol ‘t’ means in all diffs,
+ ‘status’ means only in the status buffer, and nil means nowhere.
+
+ -- User Option: magit-diff-highlight-trailing
+
+ Whether to highlight whitespace at the end of a line in diffs.
+ Used only when ‘magit-diff-paint-whitespace’ is non-nil.
+
+ -- User Option: magit-diff-highlight-indentation
+
+ Highlight the "wrong" indentation style. Used only when
+ ‘magit-diff-paint-whitespace’ is non-nil.
+
+ The value is a list of cons cells. The car is a regular
+ expression, and the cdr is the value that applies to repositories
+ whose directory matches the regular expression. If more than one
+ element matches, then the *last* element in the list applies. The
+ default value should therefore come first in the list.
+
+ If the value is ‘tabs’, highlight indentation with tabs. If the
+ value is an integer, highlight indentation with at least that many
+ spaces. Otherwise, highlight neither.
+
+ -- User Option: magit-diff-hide-trailing-cr-characters
+
+ Whether to hide ^M characters at the end of a line in diffs.
+
+ -- User Option: magit-diff-highlight-hunk-region-functions
+
+ This option specifies the functions used to highlight the
+ hunk-internal region.
+
+ ‘magit-diff-highlight-hunk-region-dim-outside’ overlays the outside
+ of the hunk internal selection with a face that causes the added
+ and removed lines to have the same background color as context
+ lines. This function should not be removed from the value of this
+ option.
+
+ ‘magit-diff-highlight-hunk-region-using-overlays’ and
+ ‘magit-diff-highlight-hunk-region-using-underline’ emphasize the
+ region by placing delimiting horizonal lines before and after it.
+ Both of these functions have glitches which cannot be fixed due to
+ limitations of Emacs’ display engine. For more information see
+ <https://github.com/magit/magit/issues/2758> ff.
+
+ Instead of, or in addition to, using delimiting horizontal lines,
+ to emphasize the boundaries, you may which to emphasize the text
+ itself, using ‘magit-diff-highlight-hunk-region-using-face’.
+
+ In terminal frames it’s not possible to draw lines as the overlay
+ and underline variants normally do, so there they fall back to
+ calling the face function instead.
+
+ -- User Option: magit-diff-unmarked-lines-keep-foreground
+
+ This option controls whether added and removed lines outside the
+ hunk-internal region only lose their distinct background color or
+ also the foreground color. Whether the outside of the region is
+ dimmed at all depends on
+ ‘magit-diff-highlight-hunk-region-functions’.
+
+\1f
+File: magit.info, Node: Revision buffer, Prev: Diff options, Up: Diffing
+
+5.4.4 Revision buffer
+---------------------
+
+ -- User Option: magit-revision-insert-related-refs
+
+ Whether to show related refs in revision buffers.
+
+ -- User Option: magit-revision-show-gravatar
+
+ Whether to show gravatar images in revision buffers.
+
+ If non-nil, then the value has to be a cons-cell which specifies
+ where the gravatar images for the author and/or the committer are
+ inserted inside the text that was previously inserted according to
+ ‘magit-revision-header-format’.
+
+ Both cells are regular expressions. The car specifies where to
+ insert the author gravatar image. The top halve of the image is
+ inserted right after the matched text, the bottom halve on the next
+ line at the same offset. The cdr specifies where to insert the
+ committer image, accordingly. Either the car or the cdr may be
+ nil.
+
+\1f
+File: magit.info, Node: Ediffing, Next: References buffer, Prev: Diffing, Up: Inspecting
+
+5.5 Ediffing
+============
+
+This section describes how to enter Ediff from Magit buffers. For
+information on how to use Ediff itself, see *note (ediff)Top::.
+
+‘e’ (‘magit-ediff-dwim’)
+
+ Compare, stage, or resolve using Ediff.
+
+ This command tries to guess what file, and what commit or range the
+ user wants to compare, stage, or resolve using Ediff. It might
+ only be able to guess either the file, or range/commit, in which
+ case the user is asked about the other. It might not always guess
+ right, in which case the appropriate ‘magit-ediff-*’ command has to
+ be used explicitly. If it cannot read the user’s mind at all, then
+ it asks the user for a command to run.
+
+‘E’ (‘magit-ediff-popup’)
+
+ This prefix command shows the following suffix commands in a popup
+ buffer.
+
+‘E r’ (‘magit-ediff-compare’)
+
+ Compare two revisions of a file using Ediff.
+
+ If the region is active, use the revisions on the first and last
+ line of the region. With a prefix argument, instead of diffing the
+ revisions, choose a revision to view changes along, starting at the
+ common ancestor of both revisions (i.e., use a "…" range).
+
+‘E m’ (‘magit-ediff-resolve’)
+
+ Resolve outstanding conflicts in a file using Ediff, defaulting to
+ the file at point.
+
+ Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you
+ can view the file’s merge-base revision using ‘/’ in the Ediff
+ control buffer.
+
+ In the rare event that you want to manually resolve all conflicts,
+ including those already resolved by Git, use
+ ‘ediff-merge-revisions-with-ancestor’.
+
+‘E s’ (‘magit-ediff-stage’)
+
+ Stage and unstage changes to a file using Ediff, defaulting to the
+ file at point.
+
+‘E u’ (‘magit-ediff-show-unstaged’)
+
+ Show unstaged changes to a file using Ediff.
+
+‘E i’ (‘magit-ediff-show-staged’)
+
+ Show staged changes to a file using Ediff.
+
+‘E w’ (‘magit-ediff-show-working-tree’)
+
+ Show changes in a file between HEAD and working tree using Ediff.
+
+‘E c’ (‘magit-ediff-show-commit’)
+
+ Show changes to a file introduced by a commit using Ediff.
+
+‘E z’ (‘magit-ediff-show-stash’)
+
+ Show changes to a file introduced by a stash using Ediff.
+
+ -- User Option: magit-ediff-dwim-show-on-hunks
+
+ This option controls what command ‘magit-ediff-dwim’ calls when
+ point is on uncommitted hunks. When nil, always run
+ ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and
+ ‘magit-ediff-show-unstaged’ to show staged and unstaged changes,
+ respectively.
+
+ -- User Option: magit-ediff-show-stash-with-index
+
+ This option controls whether ‘magit-ediff-show-stash’ includes a
+ buffer containing the file’s state in the index at the time the
+ stash was created. This makes it possible to tell which changes in
+ the stash were staged.
+
+ -- User Option: magit-ediff-quit-hook
+
+ This hook is run after quitting an Ediff session that was created
+ using a Magit command. The hook functions are run inside the Ediff
+ control buffer, and should not change the current buffer.
+
+ This is similar to ‘ediff-quit-hook’ but takes the needs of Magit
+ into account. The regular ‘ediff-quit-hook’ is ignored by Ediff
+ sessions that were created using a Magit command.
+
+\1f
+File: magit.info, Node: References buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting
+
+5.6 References buffer
+=====================
+
+‘y’ (‘magit-show-refs-popup’)
+
+ List and compare references in a dedicated buffer. By default all
+ refs are compared with ‘HEAD’, but with a prefix argument this
+ command instead acts as a prefix command and shows the following
+ suffix commands along with the appropriate infix arguments in a
+ popup buffer.
+
+‘y y’ (‘magit-show-refs-head’)
+
+ List and compare references in a dedicated buffer. Refs are
+ compared with ‘HEAD’.
+
+‘y c’ (‘magit-show-refs-current’)
+
+ List and compare references in a dedicated buffer. Refs are
+ compared with the current branch or ‘HEAD’ if it is detached.
+
+‘y o’ (‘magit-show-refs’)
+
+ List and compare references in a dedicated buffer. Refs are
+ compared with a branch read from the user.
+
+ -- User Option: magit-refs-show-commit-count
+
+ Whether to show commit counts in Magit-Refs mode buffers.
+
+ • ‘all’ Show counts for branches and tags.
+
+ • ‘branch’ Show counts for branches only.
+
+ • ‘nil’ Never show counts.
+ The default is ‘nil’ because anything else can be very expensive.
+
+ -- User Option: magit-refs-show-margin
+
+ Whether to initially show the margin in refs buffers.
+
+ When non-nil the committer name and date are initially displayed in
+ the margin of refs buffers. The margin can be shown or hidden in
+ the current buffer using the command ‘magit-toggle-margin’.
+
+ The following variables control how individual refs are displayed.
+If you change one of these variables (especially the "%c" part), then
+you should also change the others to keep things aligned. The following
+%-sequences are supported:
+
+ • ‘%a’ Number of commits this ref has over the one we compare to.
+
+ • ‘%b’ Number of commits the ref we compare to has over this one.
+
+ • ‘%c’ Number of commits this ref has over the one we compare to.
+ For the ref which all other refs are compared this is instead "@",
+ if it is the current branch, or "#" otherwise.
+
+ • ‘%C’ For the ref which all other refs are compared this is "@", if
+ it is the current branch, or "#" otherwise. For all other refs "
+ ".
+
+ • ‘%h’ Hash of this ref’s tip.
+
+ • ‘%m’ Commit summary of the tip of this ref.
+
+ • ‘%n’ Name of this ref.
+
+ • ‘%u’ Upstream of this local branch.
+
+ • ‘%U’ Upstream of this local branch and additional local vs.
+ upstream information.
+
+ -- Variable: magit-refs-local-branch-format
+
+ Format used for local branches in refs buffers.
+
+ -- Variable: magit-refs-remote-branch-format
+
+ Format used for remote branches in refs buffers.
+
+ -- Variable: magit-refs-tags-format
+
+ Format used for tags in refs buffers.
+
+ -- Variable: magit-refs-indent-cherry-lines
+
+ Indentation of cherries in refs buffers. This should be N-1 where
+ N is taken from "%Nc" in the above format strings.
+
+ Everywhere in Magit ‘RET’ visits the thing represented by the section
+at point. In almost all cases visiting is done by showing some
+information in another buffer and *not* doing anything else. In refs
+buffers ‘RET’ behaves differently, and because many users have grown
+accustomed to that inconsistency we are keeping it that way.
+
+‘RET’ (‘magit-visit-ref’)
+
+ Everywhere except in refs buffers this command behaves exactly like
+ ‘magit-show-commit’; it shows the commit at point in another
+ buffer.
+
+ In refs buffers, when there is a local branch at point, then this
+ command instead checks out that branch. When there is a remote
+ branch or a tag at point then the respective commit is checked out
+ causing ‘HEAD’ to be detached.
+
+ When a prefix argument it used, then this command only *focuses* on
+ the reference at point, i.e. the commit counts and cherries are
+ updated to be relative to that reference, but nothing is checked
+ out.
+
+ -- User Option: magit-visit-ref-create
+
+ When this is non-nil and ‘magit-visit-ref’ is called inside a refs
+ buffer, then it "visits" the remote branch at point by creating a
+ new local branch which tracks that remote branch and then checking
+ out the newly created branch.
+
+ This is not enabled by default because one has to use an extremely
+ loose definition of the verb "to visit" to be able to argue that
+ creating and then checking out a new local branch is a form of
+ visiting a remote branch.
+
+* Menu:
+
+* References sections::
+
+\1f
+File: magit.info, Node: References sections, Up: References buffer
+
+5.6.1 References sections
+-------------------------
+
+The contents of references buffers is controlled using the hook
+‘magit-refs-sections-hook’. See *note Section hooks: Section hooks. to
+learn about such hooks and how to customize them. All of the below
+functions are members of the default value. Note that it makes much
+less sense to customize this hook than it does for the respective hook
+used for the status buffer.
+
+ -- User Option: magit-refs-sections-hook
+
+ Hook run to insert sections into a references buffer.
+
+ -- Function: magit-insert-local-branches
+
+ Insert sections showing all local branches.
+
+ -- Function: magit-insert-remote-branches
+
+ Insert sections showing all remote-tracking branches.
+
+ -- Function: magit-insert-tags
+
+ Insert sections showing all tags.
+
+\1f
+File: magit.info, Node: Bisecting, Next: Visiting blobs, Prev: References buffer, Up: Inspecting
+
+5.7 Bisecting
+=============
+
+Also see *note (gitman)git-bisect:: .
+
+‘B’ (‘magit-bisect-popup’)
+
+ This prefix command shows the following suffix commands in a popup
+ buffer.
+
+ When bisecting is not in progress, then the popup buffer features the
+following commands.
+
+‘B B’ (‘magit-bisect-start’)
+
+ Start a bisect session.
+
+ Bisecting a bug means to find the commit that introduced it. This
+ command starts such a bisect session by asking for a known good and
+ a bad commit.
+
+‘B s’ (‘magit-bisect-run’)
+
+ Bisect automatically by running commands after each step.
+
+ When bisecting is in progress, then the popup buffer features these
+commands instead.
+
+‘B b’ (‘magit-bisect-bad’)
+
+ Mark the current commit as bad. Use this after you have asserted
+ that the commit does contain the bug in question.
+
+‘B g’ (‘magit-bisect-good’)
+
+ Mark the current commit as good. Use this after you have asserted
+ that the commit does not contain the bug in question.
+
+‘B k’ (‘magit-bisect-skip’)
+
+ Skip the current commit. Use this if for some reason the current
+ commit is not a good one to test. This command lets Git choose a
+ different one.
+
+‘B r’ (‘magit-bisect-reset’)
+
+ After bisecting, cleanup bisection state and return to original
+ ‘HEAD’.
+
+ By default the status buffer shows information about the ongoing
+bisect session.
+
+ -- User Option: magit-bisect-show-graph
+
+ This option controls whether a graph is displayed for the log of
+ commits that still have to be bisected.
+
+\1f
+File: magit.info, Node: Visiting blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting
+
+5.8 Visiting blobs
+==================
+
+‘M-x magit-find-file’ (‘magit-find-file’)
+
+ View FILE from REV. Switch to a buffer visiting blob REV:FILE,
+ creating one if none already exists.
+
+‘M-x magit-find-file-other-window’ (‘magit-find-file-other-window’)
+
+ View FILE from REV, in another window. Like ‘magit-find-file’, but
+ create a new window or reuse an existing one.
+
+\1f
+File: magit.info, Node: Blaming, Prev: Visiting blobs, Up: Inspecting
+
+5.9 Blaming
+===========
+
+Also see *note (gitman)git-blame:: .
+
+‘M-x magit-blame’ (‘magit-blame’)
+
+ Display edit history of FILE up to REVISION.
+
+ Interactively blame the file being visited in the current buffer.
+ If the buffer visits a revision of that file, then blame up to that
+ revision. Otherwise, blame the file’s full history, including
+ uncommitted changes.
+
+ If Magit-Blame mode is already turned on then blame recursively, by
+ visiting REVISION:FILE (using ‘magit-find-file’), where revision is
+ the revision before the revision that added the lines at point.
+
+ ARGS is a list of additional arguments to pass to ‘git blame’; only
+ arguments available from ‘magit-blame-popup’ should be used.
+
+‘M-x magit-blame-popup’ (‘magit-blame-popup’)
+
+ This prefix command shows the above suffix command along with the
+ appropriate infix arguments in a popup buffer.
+
+‘RET’ (‘magit-show-commit’)
+
+ Show the commit at point. If there is no commit at point or with a
+ prefix argument, prompt for a commit.
+
+‘SPC’ (‘magit-diff-show-or-scroll-up’)
+
+ Update the commit or diff buffer for the thing at point.
+
+ Either show the commit or stash at point in the appropriate buffer,
+ or if that buffer is already being displayed in the current frame
+ and contains information about that commit or stash, then instead
+ scroll the buffer up. If there is no commit or stash at point,
+ then prompt for a commit.
+
+‘DEL’ (‘magit-diff-show-or-scroll-down’)
+
+ Update the commit or diff buffer for the thing at point.
+
+ Either show the commit or stash at point in the appropriate buffer,
+ or if that buffer is already being displayed in the current frame
+ and contains information about that commit or stash, then instead
+ scroll the buffer down. If there is no commit or stash at point,
+ then prompt for a commit.
+
+‘n’ (‘magit-blame-next-chunk’)
+
+ Move to the next chunk.
+
+‘N’ (‘magit-blame-next-chunk-same-commit’)
+
+ Move to the next chunk from the same commit.
+
+‘p’ (‘magit-blame-previous-chunk’)
+
+ Move to the previous chunk.
+
+‘P’ (‘magit-blame-previous-chunk-same-commit’)
+
+ Move to the previous chunk from the same commit.
+
+‘q’ (‘magit-blame-quit’)
+
+ Turn off Magit-Blame mode. If the buffer was created during a
+ recursive blame, then also kill the buffer.
+
+‘M-w’ (‘magit-blame-copy-hash’)
+
+ Save the hash of the current chunk’s commit to the kill ring.
+
+ When the region is active, then save that to the ‘kill-ring’, like
+ ‘kill-ring-save’ would.
+
+‘t’ (‘magit-blame-toggle-headings’)
+
+ Show or hide blame chunk headings.
+
+ -- User Option: magit-blame-heading-format
+
+ Format string used for blame headings.
+
+ -- User Option: magit-blame-time-format
+
+ Format string used for time strings in blame headings.
+
+ -- User Option: magit-blame-show-headings
+
+ Whether to initially show blame block headings. The headings can
+ also be toggled locally using command
+ ‘magit-blame-toggle-headings’.
+
+ -- User Option: magit-blame-goto-chunk-hook
+
+ Hook run by ‘magit-blame-next-chunk’ and
+ ‘magit-blame-previous-chunk’.
+
+\1f
+File: magit.info, Node: Manipulating, Next: Transferring, Prev: Inspecting, Up: Top
+
+6 Manipulating
+**************
+
+* Menu:
+
+* Repository setup::
+* Staging and unstaging::
+* Applying::
+* Committing::
+* Branching::
+* Merging::
+* Resolving conflicts::
+* Rebasing::
+* Cherry picking::
+* Resetting::
+* Stashing::
+
+\1f
+File: magit.info, Node: Repository setup, Next: Staging and unstaging, Up: Manipulating
+
+6.1 Repository setup
+====================
+
+‘M-x magit-init’ (‘magit-init’)
+
+ This command initializes a repository and then shows the status
+ buffer for the new repository.
+
+ If the directory is below an existing repository, then the user has
+ to confirm that a new one should be created inside. If the
+ directory is the root of the existing repository, then the user has
+ to confirm that it should be reinitialized.
+
+‘M-x magit-clone’ (‘magit-clone’)
+
+ This command clones a repository and then shows the status buffer
+ for the new repository.
+
+ The user is queried for a remote url and a local directory.
+
+ -- User Option: magit-clone-set-remote.pushDefault
+
+ Whether to set the value of ‘remote.pushDefault’ after cloning.
+
+ If ‘t’, then set without asking. If ‘nil’, then don’t set. If
+ ‘ask’, then ask the user every time she clones a repository.
+
+\1f
+File: magit.info, Node: Staging and unstaging, Next: Applying, Prev: Repository setup, Up: Manipulating
+
+6.2 Staging and unstaging
+=========================
+
+Like Git, Magit can of course stage and unstage complete files. Unlike
+Git, it also allows users to gracefully un-/stage individual hunks and
+even just part of a hunk. To stage individual hunks and parts of hunks
+using Git directly, one has to use the very modal and rather clumsy
+interface of a ‘git add --interactive’ session.
+
+ With Magit, on the other hand, one can un-/stage individual hunks by
+just moving point into the respective section inside a diff displayed in
+the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To
+operate on just parts of a hunk, mark the changes that should be
+un-/staged using the region and then press the same key that would be
+used to un-/stage. To stage multiple files or hunks at once use a
+region that starts inside the heading of such a section and ends inside
+the heading of a sibling section of the same type.
+
+ Besides staging and unstaging, Magit also provides several other
+"apply variants" that can also operate on a file, multiple files at
+once, a hunk, multiple hunks at once, and on parts of a hunk. These
+apply variants are described in the next section.
+
+ You can also use Ediff to stage and unstage. See *note Ediffing:
+Ediffing.
+
+‘s’ (‘magit-stage’)
+
+ Add the change at point to the staging area.
+
+ With a prefix argument and an untracked file (or files) at point,
+ stage the file but not its content. This makes it possible to
+ stage only a subset of the new file’s changes.
+
+‘S’ (‘magit-stage-modified’)
+
+ Stage all changes to files modified in the worktree. Stage all new
+ content of tracked files and remove tracked files that no longer
+ exist in the working tree from the index also. With a prefix
+ argument also stage previously untracked (but not ignored) files.
+
+‘u’ (‘magit-unstage’)
+
+ Remove the change at point from the staging area.
+
+ Only staged changes can be unstaged. But by default this command
+ performs an action that is somewhat similar to unstaging, when it
+ is called on a committed change: it reverses the change in the
+ index but not in the working tree.
+
+‘U’ (‘magit-unstage-all’)
+
+ Remove all changes from the staging area.
+
+ -- User Option: magit-unstage-committed
+
+ This option controls whether ‘magit-unstage’ "unstages" committed
+ changes by reversing them in the index but not the working tree.
+ The alternative is to raise an error.
+
+‘M-x magit-reverse-in-index’ (‘magit-reverse-in-index’)
+
+ This command reverses the committed change at point in the index
+ but not the working tree. By default no key is bound directly to
+ this command, but it is indirectly called when ‘u’
+ (‘magit-unstage’) is pressed on a committed change.
+
+ This allows extracting a change from ‘HEAD’, while leaving it in
+ the working tree, so that it can later be committed using a
+ separate commit. A typical workflow would be:
+
+ • Optionally make sure that there are no uncommitted changes.
+
+ • Visit the ‘HEAD’ commit and navigate to the change that should
+ not have been included in that commit.
+
+ • Type ‘u’ (‘magit-unstage’) to reverse it in the index. This
+ assumes that ‘magit-unstage-committed-changes’ is non-nil.
+
+ • Type ‘c e’ to extend ‘HEAD’ with the staged changes, including
+ those that were already staged before.
+
+ • Optionally stage the remaining changes using ‘s’ or ‘S’ and
+ then type ‘c c’ to create a new commit.
+
+‘M-x magit-reset-index’ (‘magit-reset-index’)
+
+ Reset the index to some commit. The commit is read from the user
+ and defaults to the commit at point. If there is no commit at
+ point, then it defaults to ‘HEAD’.
+
+* Menu:
+
+* Staging from file-visiting buffers::
+
+\1f
+File: magit.info, Node: Staging from file-visiting buffers, Up: Staging and unstaging
+
+6.2.1 Staging from file-visiting buffers
+----------------------------------------
+
+Fine-grained un-/staging has to be done from the status or a diff
+buffer, but it’s also possible to un-/stage all changes made to the file
+visited in the current buffer right from inside that buffer.
+
+‘M-x magit-stage-file’ (‘magit-stage-file’)
+
+ When invoked inside a file-visiting buffer, then stage all changes
+ to that file. In a Magit buffer, stage the file at point if any.
+ Otherwise prompt for a file to be staged. With a prefix argument
+ always prompt the user for a file, even in a file-visiting buffer
+ or when there is a file section at point.
+
+‘M-x magit-unstage-file’ (‘magit-unstage-file’)
+
+ When invoked inside a file-visiting buffer, then unstage all
+ changes to that file. In a Magit buffer, unstage the file at point
+ if any. Otherwise prompt for a file to be unstaged. With a prefix
+ argument always prompt the user for a file, even in a file-visiting
+ buffer or when there is a file section at point.
+
+\1f
+File: magit.info, Node: Applying, Next: Committing, Prev: Staging and unstaging, Up: Manipulating
+
+6.3 Applying
+============
+
+Magit provides several "apply variants": stage, unstage, discard,
+reverse, and "regular apply". At least when operating on a hunk they
+are all implemented using ‘git apply’, which is why they are called
+"apply variants".
+
+ • Stage. Apply a change from the working tree to the index. The
+ change also remains in the working tree.
+
+ • Unstage. Remove a change from the index. The change remains in
+ the working tree.
+
+ • Discard. On a staged change, remove it from the working tree and
+ the index. On an unstaged change, remove it from the working tree
+ only.
+
+ • Reverse. Reverse a change in the working tree. Both committed and
+ staged changes can be reversed. Unstaged changes cannot be
+ reversed. Discard them instead.
+
+ • Apply. Apply a change to the working tree. Both committed and
+ staged changes can be applied. Unstaged changes cannot be applied
+ - as they already have been applied.
+
+ The previous section described the staging and unstaging commands.
+What follows are the commands which implement the remaining apply
+variants.
+
+‘a’ (‘magit-apply’)
+
+ Apply the change at point to the working tree.
+
+ With a prefix argument fallback to a 3-way merge. Doing so causes
+ the change to be applied to the index as well.
+
+‘k’ (‘magit-discard’)
+
+ Remove the change at point from the working tree.
+
+‘v’ (‘magit-reverse’)
+
+ Reverse the change at point in the working tree.
+
+ With a prefix argument fallback to a 3-way merge. Doing so causes
+ the change to be applied to the index as well.
+
+ With a prefix argument all apply variants attempt a 3-way merge when
+appropriate (i.e. when ‘git apply’ is used internally).
+
+\1f
+File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating
+
+6.4 Committing
+==============
+
+When the user initiates a commit, Magit calls ‘git commit’ without any
+arguments, so Git has to get it from the user. It creates the file
+‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit
+arranges for that editor to be the Emacsclient. Once the user finishes
+the editing session, the Emacsclient exits and Git creates the commit
+using the file’s content as message.
+
+* Menu:
+
+* Initiating a commit::
+* Editing commit messages::
+
+\1f
+File: magit.info, Node: Initiating a commit, Next: Editing commit messages, Up: Committing
+
+6.4.1 Initiating a commit
+-------------------------
+
+Also see *note (gitman)git-commit:: .
+
+‘c’ (‘magit-commit-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘c c’ (‘magit-commit’)
+
+ Create a new commit on ‘HEAD’. With a prefix argument amend to the
+ commit at ‘HEAD’ instead.
+
+‘c a’ (‘magit-commit-amend’)
+
+ Amend the last commit.
+
+‘c e’ (‘magit-commit-extend’)
+
+ Amend the last commit, without editing the 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.
+
+ Non-interactively respect the optional OVERRIDE-DATE argument and
+ ignore the option.
+
+‘c w’ (‘magit-commit-reword’)
+
+ Reword the last commit, ignoring staged changes. 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.
+
+‘c f’ (‘magit-commit-fixup’)
+
+ Create a fixup commit.
+
+ 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’.
+
+‘c F’ (‘magit-commit-instant-fixup’)
+
+ Create a fixup commit and instantly rebase.
+
+‘c s’ (‘magit-commit-squash’)
+
+ Create a squash commit, without editing the squash 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’.
+
+‘c S’ (‘magit-commit-instant-squash’)
+
+ Create a squash commit and instantly rebase.
+
+‘c A’ (‘magit-commit-augment’)
+
+ Create a squash commit, editing the squash 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’.
+
+ -- User Option: magit-commit-ask-to-stage
+
+ Whether to ask to stage everything when committing and nothing is
+ staged.
+
+ -- User Option: magit-commit-extend-override-date
+
+ Whether using ‘magit-commit-extend’ changes the committer date.
+
+ -- User Option: magit-commit-reword-override-date
+
+ Whether using ‘magit-commit-reword’ changes the committer date.
+
+ -- User Option: magit-commit-squash-confirm
+
+ Whether the commit targeted by squash and fixup has to be
+ confirmed. When non-nil then the commit at point (if any) is used
+ as default choice. Otherwise it has to be confirmed. This option
+ only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The
+ "instant" variants always require confirmation because making an
+ error while using those is harder to recover from.
+
+\1f
+File: magit.info, Node: Editing commit messages, Prev: Initiating a commit, Up: Committing
+
+6.4.2 Editing commit messages
+-----------------------------
+
+After initiating a commit as described in the previous section, two new
+buffers appear. One shows the changes that are about to committed,
+while the other is used to write the message. All regular editing
+commands are available in the commit message buffer. This section only
+describes the additional commands.
+
+ Commit messages are edited in an edit session - in the background Git
+is waiting for the editor, in our case the Emacsclient, to save the
+commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then
+return. If the Emacsclient returns with a non-zero exit status then Git
+does not create the commit. So the most important commands are those
+for finishing and aborting the commit.
+
+‘C-c C-c’ (‘with-editor-finish’)
+
+ Finish the current editing session by returning with exit code 0.
+ Git then creates the commit using the message it finds in the file.
+
+‘C-c C-k’ (‘with-editor-cancel’)
+
+ Cancel the current editing session by returning with exit code 1.
+ Git then cancels the commit, but leaves the file untouched.
+
+ In addition to being used by Git, these messages may also be stored
+in a ring that persists until Emacs is closed. By default the message
+is stored at the beginning and the end of an edit session (regardless of
+whether the session is finished successfully or was canceled). It is
+sometimes useful to bring back messages from that ring.
+
+‘C-s M-s’ (‘git-commit-save-message’)
+
+ Save the current buffer content to the commit message ring.
+
+‘M-p’ (‘git-commit-prev-message’)
+
+ Cycle backward through the commit message ring, after saving the
+ current message to the ring. With a numeric prefix ARG, go back
+ ARG comments.
+
+‘M-n’ (‘git-commit-next-message’)
+
+ Cycle forward through the commit message ring, after saving the
+ current message to the ring. With a numeric prefix ARG, go back
+ ARG comments.
+
+ By default the diff for the changes that are about to be committed
+are automatically shown when invoking the commit. When amending to an
+existing commit it may be useful to show either the changes that are
+about to be added to that commit or to show those changes together with
+those that are already committed.
+
+‘C-c C-d’ (‘magit-diff-while-committing’)
+
+ While committing, show the changes that are about to be committed.
+ While amending, invoking the command again toggles between showing
+ just the new changes or all the changes that will be committed.
+
+‘C-c C-w’ (‘magit-pop-revision-stack’)
+
+ This command inserts a representation of a revision into the
+ current buffer. It can be used inside buffers used to write commit
+ messages but also in other buffers such as buffers used to edit
+ emails or ChangeLog files.
+
+ By default this command pops the revision which was last added to
+ the ‘magit-revision-stack’ and inserts it into the current buffer
+ according to ‘magit-pop-revision-stack-format’. Revisions can be
+ put on the stack using ‘magit-copy-section-value’ and
+ ‘magit-copy-buffer-revision’.
+
+ If the stack is empty or with a prefix argument it instead reads a
+ revision in the minibuffer. By using the minibuffer history this
+ allows selecting an item which was popped earlier or to insert an
+ arbitrary reference or revision without first pushing it onto the
+ stack.
+
+ When reading the revision from the minibuffer, then it might not be
+ possible to guess the correct repository. When this command is
+ called inside a repository (e.g. while composing a commit
+ message), then that repository is used. Otherwise (e.g. while
+ composing an email) then the repository recorded for the top
+ element of the stack is used (even though we insert another
+ revision). If not called inside a repository and with an empty
+ stack, or with two prefix arguments, then read the repository in
+ the minibuffer too.
+
+ -- User Option: magit-pop-revision-stack-format
+
+ This option controls how the command ‘magit-pop-revision-stack’
+ inserts a revision into the current buffer.
+
+ The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this
+ option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all
+ of which may be nil or a string (though either one of EOB-FORMAT or
+ POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil,
+ then the two formats should be too).
+
+ First INDEX-REGEXP is used to find the previously inserted entry,
+ by searching backward from point. The first submatch must match
+ the index number. That number is incremented by one, and becomes
+ the index number of the entry to be inserted. If you don’t want to
+ number the inserted revisions, then use nil for INDEX-REGEXP.
+
+ If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
+ should contain \"%N\", which is replaced with the number that was
+ determined in the previous step.
+
+ Both formats, if non-nil and after removing %N, are then expanded
+ using ‘git show –format=FORMAT …’ inside TOPLEVEL.
+
+ The expansion of POINT-FORMAT is inserted at point, and the
+ expansion of EOB-FORMAT is inserted at the end of the buffer (if
+ the buffer ends with a comment, then it is inserted right before
+ that).
+
+ Some projects use pseudo headers in commit messages. Magit colorizes
+such headers and provides some commands to insert such headers.
+
+ -- User Option: git-commit-known-pseudo-headers
+
+ A list of Git pseudo headers to be highlighted.
+
+‘C-c C-a’ (‘git-commit-ack’)
+
+ Insert a header acknowledging that you have looked at the commit.
+
+‘C-c C-r’ (‘git-commit-review’)
+
+ Insert a header acknowledging that you have reviewed the commit.
+
+‘C-c C-s’ (‘git-commit-signoff’)
+
+ Insert a header to sign off the commit.
+
+‘C-c C-t’ (‘git-commit-test’)
+
+ Insert a header acknowledging that you have tested the commit.
+
+‘C-c C-o’ (‘git-commit-cc’)
+
+ Insert a header mentioning someone who might be interested.
+
+‘C-c C-p’ (‘git-commit-reported’)
+
+ Insert a header mentioning the person who reported the issue being
+ fixed by the commit.
+
+‘C-c C-i’ (‘git-commit-suggested’)
+
+ Insert a header mentioning the person who suggested the change.
+
+ ‘git-commit-mode’ is a minor mode that is only used to establish the
+above key bindings. This allows using an arbitrary major mode when
+editing the commit message. It’s even possible to use a different major
+mode in different repositories, which is useful when different projects
+impose different commit message conventions.
+
+ -- User Option: git-commit-major-mode
+
+ The value of this option is the major mode used to edit Git commit
+ messages.
+
+ Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook
+to setup the buffer, except for the key bindings. All other setup
+happens in the function ‘git-commit-setup’, which among other things
+runs the hook ‘git-commit-setup-hook’. The following functions are
+suitable for that hook.
+
+ -- User Option: git-commit-setup-hook
+
+ Hook run at the end of ‘git-commit-setup’.
+
+ -- Function: magit-revert-buffers &optional force
+
+ Revert unmodified file-visiting buffers of the current repository.
+
+ If either ‘magit-revert-buffers’ is non-nil and
+ ‘inhibit-magit-revert’ is nil, or if optional FORCE is non-nil,
+ then revert all unmodified buffers that visit files being tracked
+ in the current repository.
+
+ -- Function: git-commit-save-message
+
+ Save the current buffer content to the commit message ring.
+
+ -- Function: git-commit-setup-changelog-support
+
+ After this function is called, ChangeLog entries are treated as
+ paragraphs.
+
+ -- Function: git-commit-turn-on-auto-fill
+
+ Turn on ‘auto-fill-mode’ and set ‘fill-column’ to the value of
+ ‘git-commit-fill-column’.
+
+ -- Function: git-commit-turn-on-flyspell
+
+ Turn on Flyspell mode. Also prevent comments from being checked
+ and finally check current non-comment text.
+
+ -- Function: git-commit-propertize-diff
+
+ Propertize the diff shown inside the commit message buffer. Git
+ inserts such diffs into the commit message template when the
+ ‘--verbose’ argument is used. Magit’s commit popup by default does
+ not offer that argument because the diff that is shown in a
+ separate buffer is more useful. But some users disagree, which is
+ why this function exists.
+
+ -- Function: with-editor-usage-message
+
+ Show usage information in the echo area.
+
+ Magit also helps with writing *good* commit messages by complaining
+when certain rules are violated.
+
+ -- User Option: git-commit-summary-max-length
+
+ The intended maximal length of the summary line of commit messages.
+ Characters beyond this column are colorized to indicate that this
+ preference has been violated.
+
+ -- User Option: git-commit-fill-column
+
+ Column beyond which automatic line-wrapping should happen in commit
+ message buffers.
+
+ -- User Option: git-commit-finish-query-functions
+
+ List of functions called to query before performing commit.
+
+ The commit message buffer is current while the functions are
+ called. If any of them returns nil, then the commit is not
+ performed and the buffer is not killed. The user should then fix
+ the issue and try again.
+
+ The functions are called with one argument. If it is non-nil then
+ that indicates that the user used a prefix argument to force
+ finishing the session despite issues. Functions should usually
+ honor this wish and return non-nil.
+
+ -- Function: git-commit-check-style-conventions
+
+ Check for violations of certain basic style conventions. For each
+ violation ask the user if she wants to proceed anyway. This makes
+ sure the summary line isn’t too long and that the second line is
+ empty.
+
+ To show no diff while committing remove ‘magit-commit-diff’ from
+‘server-switch-hook’.
+
+\1f
+File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating
+
+6.5 Branching
+=============
+
+* Menu:
+
+* The two remotes::
+* The branch popup::
+* The branch config popup::
+
+\1f
+File: magit.info, Node: The two remotes, Next: The branch popup, Up: Branching
+
+6.5.1 The two remotes
+---------------------
+
+The upstream branch of some local branch is the branch into which the
+commits on that local branch should eventually be merged, usually
+something like ‘origin/master’. For the ‘master’ branch itself the
+upstream branch and the branch it is being pushed to, are usually the
+same remote branch. But for a feature branch the upstream branch and
+the branch it is being pushed to should differ.
+
+ Feature branches too should _eventually_ end up in a remote branch
+such as ‘origin/master’ or ‘origin/maint’. Such a branch should
+therefore be used as the upstream. But feature branches shouldn’t be
+pushed directly to such branches. Instead a feature branch ‘my-feature’
+is usually pushed to ‘my-fork/my-feature’ or ‘origin/my-feature’. After
+the new feature has been reviewed, the maintainer merges the feature
+into ‘master’. And finally ‘master’ (not ‘my-feature’ itself) is pushed
+to ‘origin/master’.
+
+ But new features seldom are perfect on the first try, and so feature
+branches usually have to be improved and re-pushed many times. Pushing
+should therefore be easy to do, and for that reason some users have
+concluded that the remote branch to which a feature branch is being
+pushed should be set as the upstream. Luckily Git has long ago gained
+support for a push-remote which can be configured separately from the
+upstream branch, using the variables ‘branch.<name>.pushRemote’ and
+‘remote.pushDefault’, so we no longer have to choose which of the two
+remotes should be used as "the remote".
+
+ Each of the fetching, pulling, and pushing popups features three
+commands which act on the current branch and some other branch. Of
+these, ‘p’ is bound to a command which acts on the push-remote, ‘u’ is
+bound to a command which acts on the upstream, and ‘e’ is bound to a
+command which acts on any other branch. The status buffer shows
+unpushed and unpulled for both the push-remote and the upstream.
+
+ It’s fairly simple to configure these two remotes. The values of all
+the variables that are related to fetching, pulling, and pushing (as
+well as some other branch-related variables) can be inspected and
+changed using the popup ‘magit-branch-config-popup’, which is a
+sub-popup of many popups that deal with branches. It is also possible
+to set the push-remote and/or upstream while pushing (see *note Pushing:
+Pushing.).
+
+\1f
+File: magit.info, Node: The branch popup, Next: The branch config popup, Prev: The two remotes, Up: Branching
+
+6.5.2 The branch popup
+----------------------
+
+The popup ‘magit-branch-popup’ is used to create and checkout branches,
+and to make changes to existing branches. It is not used to fetch,
+pull, merge, rebase, or push branches, i.e. this popup deals with
+branches themselves, not with the commits reachable from them. Those
+features are available from separate popups.
+
+‘b’ (‘magit-branch-popup’)
+
+ This prefix command shows the following suffix commands in a popup
+ buffer.
+
+ By default it also displays the values of some branch-related Git
+ variables and allows changing their values, just like the
+ specialized ‘magit-branch-config-popup’ does.
+
+ -- User Option: magit-branch-popup-show-variables
+
+ Whether the ‘magit-branch-popup’ shows Git variables. This
+ defaults to t to avoid changing key bindings. When set to nil, no
+ variables are displayed directly in this popup, and the sub-popup
+ ‘magit-branch-config-popup’ has to be used indead to view and
+ change branch related variables.
+
+‘b b’ (‘magit-checkout’)
+
+ Checkout a revision read in the minibuffer and defaulting to the
+ branch or arbitrary revision at point. If the revision is a local
+ branch then that becomes the current branch. If it is something
+ else then ‘HEAD’ becomes detached. Checkout fails if the working
+ tree or the staging area contain changes.
+
+‘b n’ (‘magit-branch’)
+
+ Create a new branch. The user is asked for a branch or arbitrary
+ revision to use as the starting point of the new branch. When a
+ branch name is provided, then that becomes the upstream branch of
+ the new branch. The name of the new branch is also read in the
+ minibuffer.
+
+ Also see option ‘magit-branch-prefer-remote-upstream’.
+
+‘b c’ (‘magit-branch-and-checkout’)
+
+ This command creates a new branch like ‘magit-branch’, but then
+ also checks it out.
+
+ Also see option ‘magit-branch-prefer-remote-upstream’.
+
+‘b s’ (‘magit-branch-spinoff’)
+
+ This command creates and checks out a new branch starting at and
+ tracking the current branch. That branch in turn is reset to the
+ last commit it shares with its upstream. If the current branch has
+ no upstream or no unpushed commits, then the new branch is created
+ anyway and the previously current branch is not touched.
+
+ This is useful to create a feature branch after work has already
+ began on the old branch (likely but not necessarily "master").
+
+ If the current branch is a member of the value of option
+ ‘magit-branch-prefer-remote-upstream’ (which see), then the current
+ branch will be used as the starting point as usual, but the
+ upstream of the starting-point may be used as the upstream of the
+ new branch, instead of the starting-point itself.
+
+ If optional FROM is non-nil, then the source branch is reset to
+ that commit, instead of to the last commit it shares with its
+ upstream. Interactively, FROM is non-nil, when the region selects
+ some commits, and among those commits, FROM it is the commit that
+ is the fewest commits ahead of the source branch.
+
+ The commit at the other end of the selection actually does not
+ matter, all commits between FROM and ‘HEAD’ are moved to the new
+ branch. If FROM is not reachable from ‘HEAD’ or is reachable from
+ the source branch’s upstream, then an error is raised.
+
+‘b x’ (‘magit-branch-reset’)
+
+ This command resets a branch, defaulting to the branch at point, to
+ the tip of another branch or any other commit.
+
+ When the branch being reset is the current branch, then a hard
+ reset is performed. If there are any uncommitted changes, then the
+ user has to confirming the reset because those changes would be
+ lost.
+
+ This is useful when you have started work on a feature branch but
+ realize it’s all crap and want to start over.
+
+ When resetting to another branch and a prefix argument is used,
+ then the target branch is set as the upstream of the branch that is
+ being reset.
+
+‘b k’ (‘magit-branch-delete’)
+
+ Delete one or multiple branches. If the region marks multiple
+ branches, then offer to delete those. Otherwise, prompt for a
+ single branch to be deleted, defaulting to the branch at point.
+
+‘b r’ (‘magit-branch-rename’)
+
+ Rename a branch. The branch and the new name are read in the
+ minibuffer. With prefix argument the branch is renamed even if
+ that name conflicts with an existing branch.
+
+ -- User Option: magit-branch-read-upstream-first
+
+ When creating a branch, whether to read the upstream branch before
+ the name of the branch that is to be created. The default is
+ ‘nil’, and I recommend you leave it at that.
+
+ -- User Option: magit-branch-prefer-remote-upstream
+
+ This option specifies whether remote upstreams are favored over
+ local upstreams when creating new branches.
+
+ When a new branch is created, Magit offers the branch, commit, or
+ stash as the default starting point of the new branch. If there is
+ no such thing at point, then it falls back to offer the current
+ branch as starting-point. The user may then accept that default or
+ pick something else.
+
+ If the chosen starting-point is a branch, then it may also be set
+ as the upstream of the new branch, depending on the value of the
+ Git variable ‘branch.autoSetupMerge’. By default this is done for
+ remote branches, but not for local branches.
+
+ You might prefer to always use some remote branch as upstream. If
+ the chosen starting-point is (1) a local branch, (2) whose name
+ matches a member of the value of this option, (3) the upstream of
+ that local branch is a remote branch with the same name, and (4)
+ that remote branch can be fast-forwarded to the local branch, then
+ the chosen branch is used as starting-point, but its own upstream
+ is used as the upstream of the new branch.
+
+ Members of this option’s value are treated as branch names that
+ have to match exactly unless they contain a character that makes
+ them invalid as a branch name. Recommended characters to use to
+ trigger interpretation as a regexp are "*" and "^". Some other
+ characters which you might expect to be invalid, actually are not,
+ e.g. ".+$" are all perfectly valid. More precisely, if ‘git
+ check-ref-format –branch STRING’ exits with a non-zero status, then
+ treat STRING as a regexp.
+
+ Assuming the chosen branch matches these conditions you would end
+ up with with e.g.:
+
+ feature --upstream--> origin/master
+
+ instead of
+
+ feature --upstream--> master --upstream--> origin/master
+
+ Which you prefer is a matter of personal preference. If you do
+ prefer the former, then you should add branches such as ‘master’,
+ ‘next’, and ‘maint’ to the value of this options.
+
+ -- User Option: magit-branch-adjust-remote-upstream-alist
+
+ The value of this option is an alist of branches to be used as the
+ upstream when branching a remote branch.
+
+ When creating a local branch from an ephemeral branch located on a
+ remote, e.g. a feature or hotfix branch, then that remote branch
+ should usually not be used as the upstream branch, since the
+ push-remote already allows accessing it and having both the
+ upstream and the push-remote reference the same related branch
+ would be wasteful. Instead a branch like "maint" or "master"
+ should be used as the upstream.
+
+ This option allows specifing the branch that should be used as the
+ upstream when branching certain remote branches. The value is an
+ alist of the form ‘((UPSTREAM . RULE)...)’. The first matching
+ element is used, the following elements are ignored.
+
+ UPSTREAM is the branch to be used as the upstream for branches
+ specified by RULE. It can be a local or a remote branch.
+
+ RULE can either be a regular expression, matching branches whose
+ upstream should be the one specified by UPSTREAM. Or it can be a
+ list of the only branches that should *not* use UPSTREAM; all other
+ branches will. Matching is done after stripping the remote part of
+ the name of the branch that is being branched from.
+
+ If you use a finite set of non-ephemeral branches across all your
+ repositories, then you might use something like:
+
+ (("origin/master" "master" "next" "maint"))
+
+ Or if the names of all your ephemeral branches contain a slash, at
+ least in some repositories, then a good value could be:
+
+ (("origin/master" . "/"))
+
+ Of course you can also fine-tune:
+
+ (("origin/maint" . "\\`hotfix/")
+ ("origin/master" . "\\`feature/"))
+
+ -- Command: magit-branch-orphan
+
+ This command creates and checks out a new orphan branch with
+ contents from a given revision.
+
+\1f
+File: magit.info, Node: The branch config popup, Prev: The branch popup, Up: Branching
+
+6.5.3 The branch config popup
+-----------------------------
+
+ -- Command: magit-branch-popup
+
+ This prefix command shows the following branch-related Git
+ variables in a popup buffer. The values can be changed from that
+ buffer.
+
+ This popup is a sub-popup of several popups that deal with
+ branches, including ‘magit-branch-popup’, ‘magit-pull-popup’,
+ ‘magit-fetch-popup’, ‘magit-pull-and-fetch-popup’, and
+ ‘magit-push-popup’. In all of these popups "C" is bound to this
+ popup.
+
+ The following variables are used to configure a specific branch. The
+values are being displayed for the current branch (if any). To change
+the value for another branch invoke ‘magit-branch-config-popup’ with a
+prefix argument.
+
+ -- Variable: branch.NAME.merge
+
+ Together with ‘branch.NAME.remote’ this variable defines the
+ upstream branch of the local branch named NAME. The value of this
+ variable is the full reference of the upstream _branch_.
+
+ -- Variable: branch.NAME.remote
+
+ Together with ‘branch.NAME.merge’ this variable defines the
+ upstream branch of the local branch named NAME. The value of this
+ variable is the name of the upstream _remote_.
+
+ -- Variable: branch.NAME.rebase
+
+ This variable controls whether pulling into the branch named NAME
+ is done by rebasing or by merging the fetched branch.
+
+ • When ‘true’ then pulling is done by rebasing.
+
+ • When ‘false’ then pulling is done by merging.
+
+ • When undefined then the value of ‘pull.rebase’ is used. The
+ default of that variable is ‘false’.
+
+ -- Variable: branch.NAME.pushRemote
+
+ This variable specifies the remote that the branch named NAME is
+ usually pushed to. The value has to be the name of an existing
+ remote.
+
+ It is not possible to specify the name of _branch_ to push the
+ local branch to. The name of the remote branch is always the same
+ as the name of the local branch.
+
+ If this variable is undefined but ‘remote.pushDefault’ is defined,
+ then the value of the latter is used. By default
+ ‘remote.pushDefault’ is undefined.
+
+ -- Variable: branch.NAME.description
+
+ This variable can be used to describe the branch named NAME. That
+ description is used e.g. when turning the branch into a series of
+ patches.
+
+ The following variables specify defaults which are used if the above
+branch-specific variables are not set.
+
+ -- Variable: pull.rebase
+
+ This variable specifies whether pulling is done by rebasing or by
+ merging. It can be overwritten using ‘branch.NAME.rebase’.
+
+ • When ‘true’ then pulling is done by rebasing.
+
+ • When ‘false’ (the default) then pulling is done by merging.
+ Since it is never a good idea to merge the upstream branch into a
+ feature or hotfix branch and most branches are such branches, you
+ should consider setting this to ‘true’, and ‘branch.master.rebase’
+ to ‘false’.
+
+ -- Variable: remote.pushDefault
+
+ This variable specifies what remote the local branches are usually
+ pushed to. This can be overwritten per branch using
+ ‘branch.NAME.pushRemote’.
+
+ The following variables are used during the creation of a branch and
+control whether the various branch-specific variables are automatically
+set at this time.
+
+ -- Variable: branch.autoSetupMerge
+
+ This variable specifies under what circumstances creating a branch
+ NAME should result in the variables ‘branch.NAME.merge’ and
+ ‘branch.NAME.remote’ being set according to the starting point used
+ to create the branch. If the starting point isn’t a branch, then
+ these variables are never set.
+
+ • When ‘always’ then the variables are set regardless of whether
+ the starting point is a local or a remote branch.
+
+ • When ‘true’ (the default) then the variables are set when the
+ starting point is a remote branch, but not when it is a local
+ branch.
+
+ • When ‘false’ then the variables are never set.
+
+ -- Variable: branch.autoSetupRebase
+
+ This variable specifies whether creating a branch NAME should
+ result in the variable ‘branch.NAME.rebase’ being set to ‘true’.
+
+ • When ‘always’ then the variable is set regardless of whether
+ the starting point is a local or a remote branch.
+
+ • When ‘local’ then the variable are set when the starting point
+ is a local branch, but not when it is a remote branch.
+
+ • When ‘remote’ then the variable are set when the starting
+ point is a remote branch, but not when it is a local branch.
+
+ • When ‘never’ (the default) then the variable is never set.
+
+ Note that the respective commands always change the repository-local
+values. If you want to change the global value, which is used when the
+local value is undefined, then you have to do so on the command line,
+e.g.:
+
+ git config --global remote.autoSetupMerge always
+
+ For more information about these variables you should also see
+
+ *note (gitman)git-config:: . Also see *note (gitman)git-branch:: ,
+
+ *note (gitman)git-checkout:: , and *note Pushing: Pushing.
+
+ -- User Option: magit-prefer-remote-upstream
+
+ This option controls whether commands that read a branch from the
+ user and then set it as the upstream branch, offer a local or a
+ remote branch as default completion candidate, when they have the
+ choice.
+
+ This affects all commands that use ‘magit-read-upstream-branch’ or
+ ‘magit-read-starting-point’, which includes all commands that
+ change the upstream and many which create new branches.
+
+\1f
+File: magit.info, Node: Merging, Next: Resolving conflicts, Prev: Branching, Up: Manipulating
+
+6.6 Merging
+===========
+
+Also see *note (gitman)git-merge:: . For information on how to resolve
+merge conflicts see the next section.
+
+‘m’ (‘magit-merge-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+ When no merge is in progress, then the popup buffer features the
+following commands.
+
+‘m m’ (‘magit-merge’)
+
+ Merge another branch or an arbitrary revision into the current
+ branch. The branch or revision to be merged is read in the
+ minibuffer and defaults to the one at point.
+
+ Unless there are conflicts or a prefix argument is used, the
+ resulting merge commit uses a generic commit message, and the user
+ does not get a chance to inspect or change it before the commit is
+ created. With a prefix argument this does not actually create the
+ merge commit, which makes it possible to inspect how conflicts were
+ resolved and to adjust the commit message.
+
+‘m e’ (‘magit-merge-editmsg’)
+
+ Merge another branch or an arbitrary revision into the current
+ branch and open a commit message buffer, so that the user can make
+ adjustments. The commit is not actually created until the user
+ finishes with ‘C-c C-c’.
+
+‘m n’ (‘magit-merge-nocommit’)
+
+ Merge another branch or an arbitrary revision into the current
+ branch, but do not actually create the commit. The user can then
+ further adjust the merge, even when automatic conflict resolution
+ succeeded and/or adjust the commit message.
+
+‘m p’ (‘magit-merge-preview’)
+
+ Preview result of merging another branch or an arbitrary revision
+ into the current branch.
+
+ When a merge is in progress, then the popup buffer features these
+commands instead.
+
+‘m m’ (‘magit-merge’)
+
+ After resolving conflicts, proceed with the merge. If there are
+ still conflicts, then this fails.
+
+‘m a’ (‘magit-merge-abort’)
+
+ Abort the current merge operation.
+
+\1f
+File: magit.info, Node: Resolving conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating
+
+6.7 Resolving conflicts
+=======================
+
+When merging branches (or otherwise combining or changing history)
+conflicts can occur. If you edited two completely different parts of
+the same file in two branches and then merge one of these branches into
+the other, then Git can resolve that on its own, but if you edit the
+same area of a file, then a human is required to decide how the two
+versions, or "sides of the conflict", are to be combined into one.
+
+ Here we can only provide a brief introduction to the subject and
+point you toward some tools that can help. If you are new to this, then
+please also consult Git’s own documentation as well as other resources.
+
+ If a file has conflicts and Git cannot resolve them by itself, then
+it puts both versions into the affected file along with special markers
+whose purpose is to denote the boundaries of the unresolved part of the
+file and between the different versions. These boundary lines begin
+with the strings consisting of six times the same character, one of ‘<’,
+‘|’, ‘=’ and ‘>’ and are followed by information about the source of the
+respective versions, e.g.:
+
+ <<<<<<< HEAD
+ Take the blue pill.
+ =======
+ Take the red pill.
+ >>>>>>> feature
+
+ In this case you have chosen to take the red pill on one branch and
+on another you picked the blue pill. Now that you are merging these two
+diverging branches, Git cannot possibly know which pill you want to
+take.
+
+ To resolve that conflict you have to create a version of the affected
+area of the file by keeping only one of the sides, possibly by editing
+it in order to bring in the changes from the other side, remove the
+other versions as well as the markers, and then stage the result. A
+possible resolution might be:
+
+ Take both pills.
+
+ Often it is useful to see not only the two sides of the conflict but
+also the "original" version from before the same area of the file was
+modified twice on different branches. Instruct Git to insert that
+version as well by running this command once:
+
+ git config --global merge.conflictStyle diff3
+
+ The above conflict might then have looked like this:
+
+ <<<<<<< HEAD
+ Take the blue pill.
+ ||||||| merged common ancestors
+ Take either the blue or the red pill, but not both.
+ =======
+ Take the red pill.
+ >>>>>>> feature
+
+ If that were the case, then the above conflict resolution would not
+have been correct, which demonstrates why seeing the original version
+alongside the conflicting versions can be useful.
+
+ You can perform the conflict resolution completely by hand, but Emacs
+also provides some packages that help in the process: Smerge, Ediff
+(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does
+not provide its own tools for conflict resolution, but it does make
+using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so
+you probably don’t want to use the latter anyway.)
+
+ In the Magit status buffer, files with unresolved conflicts are
+listed in the "Unstaged changes" and/or "Staged changes" sections. They
+are prefixed with the word "unmerged", which in this context essentially
+is a synonym for "unresolved".
+
+ Pressing ‘RET’ while point is on such a file section shows a buffer
+visiting that file, turns on ‘smerge-mode’ in that buffer, and places
+point inside the first area with conflicts. You should then resolve
+that conflict using regular edit commands and/or Smerge commands.
+
+ Unfortunately Smerge does not have a manual, but you can get a list
+of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a
+command name to read its documentation.
+
+ Normally you would edit one version and then tell Smerge to keep only
+that version. Use ‘C-c ^ m’ (‘smerge-keep-mine)’ to keep the "HEAD"
+version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that
+follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting
+area in the same file. Once you are done resolving conflicts, return to
+the Magit status buffer. The file should now be shown as "modified", no
+longer as "unmerged", because Smerge automatically stages the file when
+you save the buffer after resolving the last conflict.
+
+ Alternatively you could use Ediff, which uses separate buffers for
+the different versions of the file. To resolve conflicts in a file
+using Ediff press ‘e’ while point is on such a file in the status
+buffer.
+
+ Ediff can be used for other purposes as well. For more information
+on how to enter Ediff from Magit, see *note Ediffing: Ediffing.
+Explaining how to use Ediff is beyond the scope of this manual, instead
+see *note (ediff)Top::.
+
+ If you are unsure whether you should Smerge or Ediff, then use the
+former. It is much easier to understand and use, and except for truely
+complex conflicts, the latter is usually overkill.
+
+\1f
+File: magit.info, Node: Rebasing, Next: Cherry picking, Prev: Resolving conflicts, Up: Manipulating
+
+6.8 Rebasing
+============
+
+Also see *note (gitman)git-rebase:: . For information on how to resolve
+conflicts that occur during rebases see the preceding section.
+
+‘r’ (‘magit-rebase-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+ When no rebase is in progress, then the popup buffer features the
+following commands.
+
+ Using one of these commands _starts_ a rebase sequence. Git might
+then stop somewhere along the way, either because you told it to do so,
+or because applying a commit failed due to a conflict. When that
+happens, then the status buffer shows information about the rebase
+sequence which is in progress in a section similar to a log section.
+See *note Information about in-progress rebase: Information about
+in-progress rebase.
+
+‘r p’ (‘magit-rebase-onto-pushremote’)
+
+ Rebase the current branch onto ‘branch.<name>.pushRemote’. If that
+ variable is unset, then rebase onto ‘remote.pushDefault’.
+
+‘r u’ (‘magit-rebase-onto-upstream’)
+
+ Rebase the current branch onto its upstream branch.
+
+‘r e’ (‘magit-rebase’)
+
+ Rebase the current branch onto a branch read in the minibuffer.
+ All commits that are reachable from head but not from the selected
+ branch TARGET are being rebased."
+
+‘r o’ (‘magit-rebase-subset’)
+
+ Start a non-interactive rebase sequence with commits from START to
+ ‘HEAD’ onto NEWBASE. START has to be selected from a list of recent
+ commits.
+
+ Note that the popup also features the infix argument ‘--interactive’.
+This can be used to turn one of the above non-interactive rebase
+variants into an interactive rebase.
+
+ For example if you want to clean up a feature branch and at the same
+time rebase it onto ‘master’, then you could use ‘r-iu’. But we
+recommend that you instead do that in two steps. First use ‘ri’ to
+cleanup the feature branch, and then in a second step ‘ru’ to rebase it
+onto ‘master’. That way if things turn out to be more complicated than
+you thought and/or you make a mistake and have to start over, then you
+only have to redo half the work.
+
+ Explicitly enabling ‘--interactive’ won’t have an effect on the
+following commands as they always use that argument anyway, even if it
+is not enabled in the popup.
+
+‘r i’ (‘magit-rebase-interactive’)
+
+ Start an interactive rebase sequence.
+
+‘r f’ (‘magit-rebase-autosquash’)
+
+ Combine squash and fixup commits with their intended targets.
+
+‘r m’ (‘magit-rebase-edit-commit’)
+
+ Edit a single older commit using rebase.
+
+‘r w’ (‘magit-rebase-reword-commit’)
+
+ Reword a single older commit using rebase.
+
+ When a rebase is in progress, then the popup buffer features these
+commands instead.
+
+‘r r’ (‘magit-rebase-continue’)
+
+ Restart the current rebasing operation.
+
+ In some cases this pops up a commit message buffer for you do edit.
+ With a prefix argument the old message is reused as-is.
+
+‘r s’ (‘magit-rebase-skip’)
+
+ Skip the current commit and restart the current rebase operation.
+
+‘r e’ (‘magit-rebase-edit’)
+
+ Edit the todo list of the current rebase operation.
+
+‘r a’ (‘magit-rebase-abort’)
+
+ Abort the current rebase operation, restoring the original branch.
+
+* Menu:
+
+* Editing rebase sequences::
+* Information about in-progress rebase::
+
+\1f
+File: magit.info, Node: Editing rebase sequences, Next: Information about in-progress rebase, Up: Rebasing
+
+6.8.1 Editing rebase sequences
+------------------------------
+
+‘C-c C-c’ (‘with-editor-finish’)
+
+ Finish the current editing session by returning with exit code 0.
+ Git then uses the rebase instructions it finds in the file.
+
+‘C-c C-k’ (‘with-editor-cancel’)
+
+ Cancel the current editing session by returning with exit code 1.
+ Git then forgoes starting the rebase sequence.
+
+‘RET’ (‘git-rebase-show-commit’)
+
+ Show the commit on the current line in another buffer and select
+ that buffer.
+
+‘SPC’ (‘magit-diff-show-or-scroll-up’)
+
+ Show the commit on the current line in another buffer without
+ selecting that buffer. If the revision buffer is already visible
+ in another window of the current frame, then instead scroll that
+ window up.
+
+‘DEL’ (‘magit-diff-show-or-scroll-down’)
+
+ Show the commit on the current line in another buffer without
+ selecting that buffer. If the revision buffer is already visible
+ in another window of the current frame, then instead scroll that
+ window down.
+
+‘p’ (‘git-rebase-backward-line’)
+
+ Move to previous line.
+
+‘n’ (‘forward-line’)
+
+ Move to next line.
+
+‘M-p’ (‘git-rebase-move-line-up’)
+
+ Move the current commit (or command) up.
+
+‘M-n’ (‘git-rebase-move-line-down’)
+
+ Move the current commit (or command) down.
+
+‘r’ (‘git-rebase-reword’)
+
+ Edit message of commit on current line.
+
+‘e’ (‘git-rebase-edit’)
+
+ Stop at the commit on the current line.
+
+‘s’ (‘git-rebase-squash’)
+
+ Meld commit on current line into previous commit, and edit message.
+
+‘f’ (‘git-rebase-fixup’)
+
+ Meld commit on current line into previous commit, discarding the
+ current commit’s message.
+
+‘k’ (‘git-rebase-kill-line’)
+
+ Kill the current action line.
+
+‘c’ (‘git-rebase-pick’)
+
+ Use commit on current line.
+
+‘x’ (‘git-rebase-exec’)
+
+ Insert a shell command to be run after the proceeding commit.
+
+ If there already is such a command on the current line, then edit
+ that instead. With a prefix argument insert a new command even
+ when there already is one on the current line. With empty input
+ remove the command on the current line, if any.
+
+‘y’ (‘git-rebase-insert’)
+
+ Read an arbitrary commit and insert it below current line.
+
+‘C-x u’ (‘git-rebase-undo’)
+
+ Undo some previous changes. Like ‘undo’ but works in read-only
+ buffers.
+
+ -- User Option: git-rebase-auto-advance
+
+ Whether to move to next line after changing a line.
+
+ -- User Option: git-rebase-show-instructions
+
+ Whether to show usage instructions inside the rebase buffer.
+
+ -- User Option: git-rebase-confirm-cancel
+
+ Whether confirmation is required to cancel.
+
+\1f
+File: magit.info, Node: Information about in-progress rebase, Prev: Editing rebase sequences, Up: Rebasing
+
+6.8.2 Information about in-progress rebase
+------------------------------------------
+
+While a rebase sequence is in progress, the status buffer features a
+section which lists the commits that have already been applied as well
+as the commits that still have to be applied.
+
+ The commits are split in two halves. When rebase stops at a commit,
+either because the user has to deal with a conflict or explicitly
+requested that rebase stops at that commit, then point is placed on the
+commit that separates the two groups, i.e. on ‘HEAD’. The commits
+above it have not been applied yet, while it and the commits below it
+have already been applied. In between these two groups of applied and
+yet-to-be applied commits, there sometimes is a commit which has been
+dropped.
+
+ Each commit is prefixed with a word and these words are additionally
+shown in different colors to indicate the status of the commits.
+
+ The following colors are used:
+
+ • Yellow commits have not been applied yet.
+
+ • Gray commits have already been applied.
+
+ • The blue commit is the ‘HEAD’ commit.
+
+ • The green commit is the commit the rebase sequence stopped at. If
+ this is the same commit as ‘HEAD’ (e.g. because you haven’t done
+ anything yet after rebase stopped at the commit, then this commit
+ is shown in blue, not green. There can only be a green and a blue
+ commit at the same time, if you create one or more new commits
+ after rebase stops at a commit.
+
+ • Red commits have been dropped. They are shown for reference only,
+ e.g. to make it easier to diff.
+
+ Of course these colors are subject to the color-theme in use.
+
+ The following words are used:
+
+ • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and
+ ‘fixup’ have not been applied yet. These words have the same
+ meaning here as they do in the buffer used to edit the rebase
+ sequence. See *note Editing rebase sequences: Editing rebase
+ sequences.
+
+ • The commit prefixed with ‘onto’ is the commit on top of which all
+ the other commits are being re-applied. Like the commits that have
+ already been re-applied, it is reachable from ‘HEAD’, but unlike
+ those it has not actually been re-applied during the current
+ session - it wasn’t touched at all.
+
+ • Commits prefixed with ‘done’ have already been re-applied. Not all
+ commits that have already been applied are prefixed with this word,
+ though.
+
+ • When a commit is prefixed with ‘void’, then that indicates that
+ Magit knows for sure that all the changes in that commit have been
+ applied using several new commits. This commit is no longer
+ reachable from ‘HEAD’, and it also isn’t one of the commits that
+ will be applied when resuming the session.
+
+ • When a commit is prefixed with ‘join’, then that indicates that the
+ rebase sequence stopped at that commit due to a conflict - you now
+ have to join (merge) the changes with what has already been
+ applied. In a sense this is the commit rebase stopped at, but
+ while its effect is already in the index and in the worktree (with
+ conflict markers), the commit itself has not actually been applied
+ yet (it isn’t the ‘HEAD’). So it is shown in yellow, like the
+ other commits that still have to be applied.
+
+ • When a commit is prefixed with ‘goal’, ‘same’, or ‘work’, then that
+ indicates that you reset to an earlier commit (and that this commit
+ therefore is no longer reachable from ‘HEAD’), but that it might
+ still be possible to create a new commit with the exact same tree
+ or at least the same patch-id (1), without manually editing any
+ file. Or at the very least that there are some uncommitted
+ remaining, which may or may not originate from that commit.
+
+ • When a commit is prefixed with ‘goal’, then that indicates
+ that it is still possible to create a commit with the exact
+ same tree (the "goal") without manually editing a file, by
+ simply committing the index (or, provided nothing is already
+ staged, by staging all unstaged changes and then committing
+ that). This is the case when the original tree exists in the
+ index or worktree in untainted form.
+
+ • When a commit is prefixed with ‘same’, then that indicates
+ that it is no longer possible to create a commit with the
+ exact same tree, but that it is still possible to create a
+ commit with the same patch-id. This would be the case if you
+ created a new commit with other changes, but the changes from
+ the original commit still exist in the index and/or working
+ tree in untainted form.
+
+ • When a commit is prefixed with ‘work’, then that indicates
+ that you are working with the changes from that commit after
+ resetting to an earlier commit. There are changes in the
+ index and/or working tree and some of them likely originate
+ from that commit.
+
+ • When a commit is prefixed with ‘poof’ or ‘gone’, then that
+ indicates that you reset to an earlier commit (and that this commit
+ therefore is no longer reachable from ‘HEAD’), and that there are
+ no uncommitted changes remaining which might allow you to create a
+ new commit with the same tree or at least the same patch-id.
+
+ • When a commit is prefixed with ‘poof’, then that indicates
+ that it is no longer reachable from ‘HEAD’, but that it has
+ been replaced with one or more commits, which together have
+ the exact same effect.
+
+ • When a commit is prefixed with ‘gone’, then that indicates
+ that it is no longer reachable from ‘HEAD’ and that we also
+ cannot determine whether its changes are still in effect in
+ one or more new commits. They might be, but if so, then there
+ must also be other changes which makes it impossible to know
+ for sure.
+
+ Do not worry if you do not fully understand the above. That’s okay,
+you will acquire a good enough understanding through practice.
+
+ For other sequence operations such as cherry-picking, a similar
+section is displayed, but they lack some of the features described
+above, due to limitations in the git commands used to implement them.
+Most importantly these sequences only support "picking" a commit but not
+other actions such as "rewording", and they do not keep track of the
+commits which have already been applied.
+
+ ---------- Footnotes ----------
+
+ (1) The patch-id is a hash of the _changes_ introduced by commit. It
+differs from hash of the commit itself, which is a hash of the result of
+applying that change (i.e. the resulting trees and blobs) as well as
+author and committer information, the commit message, and the hashes of
+the parents of the commit. The patch-id hash on the other hand is
+created only from the added and removed lines, even line numbers and
+whitespace are created when calculating the hash. The patch-ids of two
+commits can be used to answer the question "Do these two commits make
+the same change?".
+
+\1f
+File: magit.info, Node: Cherry picking, Next: Resetting, Prev: Rebasing, Up: Manipulating
+
+6.9 Cherry picking
+==================
+
+Also see *note (gitman)git-cherry-pick:: .
+
+‘A’ (‘magit-cherry-pick-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+ When no cherry-pick or revert is in progress, then the popup buffer
+features the following commands.
+
+‘A A’ (‘magit-cherry-pick’)
+
+ Cherry-pick a commit. Prompt for a commit, defaulting to the
+ commit at point. If the region selects multiple commits, then pick
+ all of them, without prompting.
+
+‘A a’ (‘magit-cherry-apply’)
+
+ Apply the changes in a commit to the working tree, but do not
+ commit them. Prompt for a commit, defaulting to the commit at
+ point. If the region selects multiple commits, then apply all of
+ them, without prompting.
+
+ This command also has a top-level binding, which can be invoked
+ without using the popup by typing ‘a’ at the top-level.
+
+ When a cherry-pick or revert is in progress, then the popup buffer
+features these commands instead.
+
+‘A A’ (‘magit-sequence-continue’)
+
+ Resume the current cherry-pick or revert sequence.
+
+‘A s’ (‘magit-sequence-skip’)
+
+ Skip the stopped at commit during a cherry-pick or revert sequence.
+
+‘A a’ (‘magit-sequence-abort’)
+
+ Abort the current cherry-pick or revert sequence. This discards
+ all changes made since the sequence started.
+
+* Menu:
+
+* Reverting::
+
+\1f
+File: magit.info, Node: Reverting, Up: Cherry picking
+
+6.9.1 Reverting
+---------------
+
+‘V’ (‘magit-revert-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+ When no cherry-pick or revert is in progress, then the popup buffer
+features the following commands.
+
+‘V V’ (‘magit-revert’)
+
+ Revert a commit by creating a new commit. Prompt for a commit,
+ defaulting to the commit at point. If the region selects multiple
+ commits, then revert all of them, without prompting.
+
+‘V v’ (‘magit-revert-no-commit’)
+
+ Revert a commit by applying it in reverse to the working tree.
+ Prompt for a commit, defaulting to the commit at point. If the
+ region selects multiple commits, then revert all of them, without
+ prompting.
+
+ When a cherry-pick or revert is in progress, then the popup buffer
+features these commands instead.
+
+‘V A’ (‘magit-sequence-continue’)
+
+ Resume the current cherry-pick or revert sequence.
+
+‘V s’ (‘magit-sequence-skip’)
+
+ Skip the stopped at commit during a cherry-pick or revert sequence.
+
+‘V a’ (‘magit-sequence-abort’)
+
+ Abort the current cherry-pick or revert sequence. This discards
+ all changes made since the sequence started.
+
+\1f
+File: magit.info, Node: Resetting, Next: Stashing, Prev: Cherry picking, Up: Manipulating
+
+6.10 Resetting
+==============
+
+Also see *note (gitman)git-reset:: .
+
+‘x’ (‘magit-reset’)
+
+ Reset the head and index to some commit read from the user and
+ defaulting to the commit at point. The working tree is kept as-is.
+ With a prefix argument also reset the working tree.
+
+‘M-x magit-reset-index’ (‘magit-reset-index’)
+
+ Reset the index to some commit read from the user and defaulting to
+ the commit at point. Keep the ‘HEAD’ and working tree as-is, so if
+ the commit refers to the ‘HEAD’, then this effectively unstages all
+ changes.
+
+‘M-x magit-reset-head’ (‘magit-reset-head’)
+
+ Reset the ‘HEAD’ and index to some commit read from the user and
+ defaulting to the commit at point. The working tree is kept as-is.
+
+‘M-x magit-reset-soft’ (‘magit-reset-soft’)
+
+ Reset the ‘HEAD’ to some commit read from the user and defaulting
+ to the commit at point. The index and the working tree are kept
+ as-is.
+
+‘M-x magit-reset-hard’ (‘magit-reset-hard’)
+
+ Reset the ‘HEAD’, index, and working tree to some commit read from
+ the user and defaulting to the commit at point.
+
+‘M-x magit-checkout-file’ (‘magit-checkout-file’)
+
+ Update file in the working tree and index to the contents from a
+ revision.
+
+ Both the revision and file are read from the user.
+
+\1f
+File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating
+
+6.11 Stashing
+=============
+
+Also see *note (gitman)git-stash:: .
+
+‘z’ (‘magit-stash-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘z z’ (‘magit-stash’)
+
+ Create a stash of the index and working tree. Untracked files are
+ included according to popup arguments. One prefix argument is
+ equivalent to ‘--include-untracked’ while two prefix arguments are
+ equivalent to ‘--all’.
+
+‘z i’ (‘magit-stash-index’)
+
+ Create a stash of the index only. Unstaged and untracked changes
+ are not stashed.
+
+‘z w’ (‘magit-stash-worktree’)
+
+ Create a stash of unstaged changes in the working tree. Untracked
+ files are included according to popup arguments. One prefix
+ argument is equivalent to ‘--include-untracked’ while two prefix
+ arguments are equivalent to ‘--all’.
+
+‘z x’ (‘magit-stash-keep-index’)
+
+ Create a stash of the index and working tree, keeping index intact.
+ Untracked files are included according to popup arguments. One
+ prefix argument is equivalent to ‘--include-untracked’ while two
+ prefix arguments are equivalent to ‘--all’.
+
+‘z Z’ (‘magit-snapshot’)
+
+ Create a snapshot of the index and working tree. Untracked files
+ are included according to popup arguments. One prefix argument is
+ equivalent to ‘--include-untracked’ while two prefix arguments are
+ equivalent to ‘--all’.
+
+‘z I’ (‘magit-snapshot-index’)
+
+ Create a snapshot of the index only. Unstaged and untracked
+ changes are not stashed.
+
+‘z W’ (‘magit-snapshot-worktree’)
+
+ Create a snapshot of unstaged changes in the working tree.
+ Untracked files are included according to popup arguments. One
+ prefix argument is equivalent to ‘--include-untracked’ while two
+ prefix arguments are equivalent to ‘--all’-.
+
+‘z a’ (‘magit-stash-apply’)
+
+ Apply a stash to the working tree. Try to preserve the stash
+ index. If that fails because there are staged changes, apply
+ without preserving the stash index.
+
+‘z p’ (‘magit-stash-pop’)
+
+ Apply a stash to the working tree and remove it from stash list.
+ Try to preserve the stash index. If that fails because there are
+ staged changes, apply without preserving the stash index and forgo
+ removing the stash.
+
+‘z k’ (‘magit-stash-drop’)
+
+ Remove a stash from the stash list. When the region is active,
+ offer to drop all contained stashes.
+
+‘z l’ (‘magit-stash-list’)
+
+ List all stashes in a buffer.
+
+‘z v’ (‘magit-stash-show’)
+
+ Show all diffs of a stash in a buffer.
+
+‘z b’ (‘magit-stash-branch’)
+
+ Create and checkout a new BRANCH from STASH.
+
+‘z f’ (‘magit-stash-format-patch’)
+
+ Create a patch from STASH.
+
+‘k’ (‘magit-stash-clear’)
+
+ Remove all stashes saved in REF’s reflog by deleting REF.
+
+\1f
+File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top
+
+7 Transferring
+**************
+
+* Menu:
+
+* Remotes::
+* Fetching::
+* Pulling::
+* Pushing::
+* Creating and sending patches::
+* Applying patches::
+
+\1f
+File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring
+
+7.1 Remotes
+===========
+
+Also see *note (gitman)git-remote:: .
+
+‘M’ (‘magit-remote-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘M a’ (‘magit-remote-add’)
+
+ Add a remote and fetch it. The remote name and url are read in the
+ minibuffer.
+
+‘M r’ (‘magit-remote-rename’)
+
+ Rename a remote. Both the old and the new names are read in the
+ minibuffer.
+
+‘M u’ (‘magit-remote-set-url’)
+
+ Change the url of a remote. Both the remote and the new url are
+ read in the minibuffer.
+
+‘M k’ (‘magit-remote-remove’)
+
+ Delete a remote, read from the minibuffer.
+
+ -- User Option: magit-remote-add-set-remote.pushDefault
+
+ Whether to set the value of ‘remote.pushDefault’ after adding a
+ remote.
+
+ If ‘ask’, then always ask. If ‘ask-if-unset’, then ask, but only
+ if the variable isn’t set already. If ‘nil’, then don’t ever set.
+ If the value is a string, then set without asking, provided the
+ name of the name of the added remote is equal to that string and
+ the variable isn’t already set.
+
+\1f
+File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring
+
+7.2 Fetching
+============
+
+For information about the differences between the _upstream_ and the
+_push-remote_, see *note Branching: Branching.
+
+ Also see *note (gitman)git-fetch:: .
+
+‘f’ (‘magit-fetch-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘f p’ (‘magit-fetch-from-pushremote’)
+
+ Fetch from the push-remote of the current branch.
+
+‘f u’ (‘magit-fetch-from-upstream’)
+
+ Fetch from the upstream of the current branch.
+
+‘f e’ (‘magit-fetch’)
+
+ Fetch from another repository.
+
+‘f o’ (‘magit-fetch-branch’)
+
+ Fetch a branch from a remote, both of which are read from the
+ minibuffer.
+
+‘f r’ (‘magit-fetch-refspec’)
+
+ Fetch from a remote using an explicit refspec, both of which are
+ read from the minibuffer.
+
+‘f a’ (‘magit-fetch-all’)
+
+ Fetch from all remotes.
+
+‘f m’ (‘magit-submodule-fetch’)
+
+ Fetch all submodules. With a prefix argument fetch all remotes of
+ all submodules.
+
+ Instead of using one popup for fetching and another for pulling, you
+could also use ‘magit-pull-and-fetch-popup’. See its doc-string for
+more information.
+
+\1f
+File: magit.info, Node: Pulling, Next: Pushing, Prev: Fetching, Up: Transferring
+
+7.3 Pulling
+===========
+
+For information about the differences between the _upstream_ and the
+_push-remote_, see *note Branching: Branching.
+
+ Also see *note (gitman)git-pull:: .
+
+‘F’ (‘magit-pull-popup’)
+
+ This prefix command shows the following suffix commands in a popup
+ buffer.
+
+‘F p’ (‘magit-pull-from-pushremote’)
+
+ Pull from the push-remote of the current branch.
+
+‘F u’ (‘magit-pull-from-upstream’)
+
+ Pull from the upstream of the current branch.
+
+‘F e’ (‘magit-pull’)
+
+ Pull from a branch read in the minibuffer.
+
+ Instead of using one popup for fetching and another for pulling, you
+could also use ‘magit-pull-and-fetch-popup’. See its doc-string for
+more information.
+
+\1f
+File: magit.info, Node: Pushing, Next: Creating and sending patches, Prev: Pulling, Up: Transferring
+
+7.4 Pushing
+===========
+
+For information about the differences between the _upstream_ and the
+_push-remote_, see *note Branching: Branching.
+
+ Also see *note (gitman)git-push:: .
+
+‘P’ (‘magit-push-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘P p’ (‘magit-push-current-to-pushremote’)
+
+ Push the current branch to ‘branch.<name>.pushRemote’ or if that is
+ unset to ‘remote.pushDefault’.
+
+ When ‘magit-push-current-set-remote-if-missing’ is non-nil and the
+ push-remote is not configured, then read the push-remote from the
+ user, set it, and then push to it. With a prefix argument the
+ push-remote can be changed before pushed to it.
+
+‘P u’ (‘magit-push-current-to-upstream’)
+
+ Push the current branch to its upstream branch.
+
+ When ‘magit-push-current-set-remote-if-missing’ is non-nil and the
+ push-remote is not configured, then read the upstram from the user,
+ set it, and then push to it. With a prefix argument the
+ push-remote can be changed before pushed to it.
+
+‘P e’ (‘magit-push-current’)
+
+ Push the current branch to a branch read in the minibuffer.
+
+‘P o’ (‘magit-push’)
+
+ Push an arbitrary branch or commit somewhere. Both the source and
+ the target are read in the minibuffer.
+
+‘P r’ (‘magit-push-refspecs’)
+
+ Push one or multiple refspecs to a remote, both of which are read
+ in the minibuffer.
+
+ To use multiple refspecs, separate them with commas. Completion is
+ only available for the part before the colon, or when no colon is
+ used.
+
+‘P m’ (‘magit-push-matching’)
+
+ Push all matching branches to another repository. If multiple
+ remotes exit, then read one from the user. If just one exists, use
+ that without requiring confirmation.
+
+‘P t’ (‘magit-push-tags’)
+
+ Push all tags to another repository. If only one remote exists,
+ then push to that. Otherwise prompt for a remote, offering the
+ remote configured for the current branch as default.
+
+‘P T’ (‘magit-push-tag’)
+
+ Push a tag to another repository.
+
+ Two more push commands exist, which by default are not available from
+the push popup. See their doc-strings for instructions on how to add
+them to the popup.
+
+ -- Command: magit-push-implicitly args
+
+ Push somewhere without using an explicit refspec.
+
+ This command simply runs ‘git push -v [ARGS]’. ARGS are the
+ arguments specified in the popup buffer. No explicit refspec
+ arguments are used. Instead the behavior depends on at least these
+ Git variables: ‘push.default’, ‘remote.pushDefault’,
+ ‘branch.<branch>.pushRemote’, ‘branch.<branch>.remote’,
+ ‘branch.<branch>.merge’, and ‘remote.<remote>.push’.
+
+ -- Command: magit-push-to-remote remote args
+
+ Push to the remote REMOTE without using an explicit refspec. The
+ remote is read in the minibuffer.
+
+ This command simply runs ‘git push -v [ARGS] REMOTE’. ARGS are the
+ arguments specified in the popup buffer. No refspec arguments are
+ used. Instead the behavior depends on at least these Git
+ variables: ‘push.default’, ‘remote.pushDefault’,
+ ‘branch.<branch>.pushRemote’, ‘branch.<branch>.remote’,
+ ‘branch.<branch>.merge’, and ‘remote.<remote>.push’.
+
+ -- User Option: magit-push-current-set-remote-if-missing
+
+ This option controls whether missing remotes are configured before
+ pushing.
+
+ When ‘nil’, then the command ‘magit-push-current-to-pushremote’ and
+ ‘magit-push-current-to-upstream’ do not appear in the push popup if
+ the push-remote resp. upstream is not configured. If the user
+ invokes one of these commands anyway, then it raises an error.
+
+ When ‘non-nil’, then these commands always appear in the push
+ popup. But if the required configuration is missing, then they do
+ appear in a way that indicates that this is the case. If the user
+ invokes one of them, then it asks for the necessary configuration,
+ stores the configuration, and then uses it to push a first time.
+
+ This option also affects whether the argument ‘--set-upstream’ is
+ available in the popup. If the value is ‘non-nil’, then that
+ argument is redundant. But note that changing the value of this
+ option does not take affect immediately, the argument will only be
+ added or removed after restarting Emacs.
+
+\1f
+File: magit.info, Node: Creating and sending patches, Next: Applying patches, Prev: Pushing, Up: Transferring
+
+7.5 Creating and sending patches
+================================
+
+‘W’ (‘magit-patch-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘W p’ (‘magit-format-patch’)
+
+ Create patches for a set commits. If the region marks commits,
+ then create patches for those. Otherwise prompt for a range or a
+ single commit, defaulting to the commit at point.
+
+‘W r’ (‘magit-request-pull’)
+
+ Request that upstream pulls from your public repository.
+
+\1f
+File: magit.info, Node: Applying patches, Prev: Creating and sending patches, Up: Transferring
+
+7.6 Applying patches
+====================
+
+Also see *note (gitman)git-am:: .
+
+‘w’ (‘magit-am-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘w w’ (‘magit-am-apply-patches’)
+
+ Apply one or more patches. If the region marks files, then apply
+ those patches. Otherwise read a file name in the minibuffer
+ defaulting to the file at point.
+
+‘w m’ (‘magit-am-apply-maildir’)
+
+ Apply the patches from a maildir.
+
+‘w w’ (‘magit-am-continue’)
+
+ Resume the current patch applying sequence.
+
+‘w s’ (‘magit-am-skip’)
+
+ Skip the stopped at patch during a patch applying sequence.
+
+‘w a’ (‘magit-am-abort’)
+
+ Abort the current patch applying sequence. This discards all
+ changes made since the sequence started.
+
+\1f
+File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top
+
+8 Miscellaneous
+***************
+
+* Menu:
+
+* Tagging::
+* Notes::
+* Submodules::
+* Subtree::
+* Common commands::
+* Wip modes::
+* Minor mode for buffers visiting files::
+* Minor mode for buffers visiting blobs::
+
+\1f
+File: magit.info, Node: Tagging, Next: Notes, Up: Miscellaneous
+
+8.1 Tagging
+===========
+
+Also see *note (gitman)git-tag:: .
+
+‘t’ (‘magit-tag-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘t t’ (‘magit-tag’)
+
+ Create a new tag with the given NAME at REV. With a prefix argument
+ annotate the tag.
+
+‘t k’ (‘magit-tag-delete’)
+
+ Delete one or more tags. If the region marks multiple tags (and
+ nothing else), then offer to delete those. Otherwise, prompt for a
+ single tag to be deleted, defaulting to the tag at point.
+
+‘t p’ (‘magit-tag-prune’)
+
+ Offer to delete tags missing locally from REMOTE, and vice versa.
+
+\1f
+File: magit.info, Node: Notes, Next: Submodules, Prev: Tagging, Up: Miscellaneous
+
+8.2 Notes
+=========
+
+Also see *note (gitman)git-notes:: .
+
+‘T’ (‘magit-notes-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘T T’ (‘magit-notes-edit’)
+
+ Edit the note attached to a commit, defaulting to the commit at
+ point.
+
+ By default use the value of Git variable ‘core.notesRef’ or
+ "refs/notes/commits" if that is undefined.
+
+‘T r’ (‘magit-notes-remove’)
+
+ Remove the note attached to a commit, defaulting to the commit at
+ point.
+
+ By default use the value of Git variable ‘core.notesRef’ or
+ "refs/notes/commits" if that is undefined.
+
+‘T p’ (‘magit-notes-prune’)
+
+ Remove notes about unreachable commits.
+
+‘T s’ (‘magit-notes-set-ref’)
+
+ Set the current notes ref to a the value read from the user. The
+ ref is made current by setting the value of the Git variable
+ ‘core.notesRef’. With a prefix argument change the global value
+ instead of the value in the current repository. When this is
+ undefined, then "refs/notes/commit" is used.
+
+ Other ‘magit-notes-*’ commands, as well as the sub-commands of
+ Git’s ‘note’ command, default to operate on that ref.
+
+‘T S’ (‘magit-notes-set-display-refs’)
+
+ Set notes refs to be display in addition to "core.notesRef". This
+ reads a colon separated list of notes refs from the user. The
+ values are stored in the Git variable ‘notes.displayRef’. With a
+ prefix argument GLOBAL change the global values instead of the
+ values in the current repository.
+
+ It is possible to merge one note ref into another. That may result
+in conflicts which have to resolved in the temporary worktree
+".git/NOTES_MERGE_WORKTREE".
+
+‘T m’ (‘magit-notes-merge’)
+
+ Merge the notes of a ref read from the user into the current notes
+ ref. The current notes ref is the value of Git variable
+ ‘core.notesRef’ or "refs/notes/commits" if that is undefined.
+
+ When a notes merge is in progress then the popup features the
+following suffix commands, instead of those listed above.
+
+‘T c’ (‘magit-notes-merge-commit’)
+
+ Commit the current notes ref merge, after manually resolving
+ conflicts.
+
+‘T a’ (‘magit-notes-merge-abort’)
+
+ Abort the current notes ref merge.
+
+\1f
+File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous
+
+8.3 Submodules
+==============
+
+Also see *note (gitman)git-submodule:: .
+
+* Menu:
+
+* Listing submodules::
+* Submodule popup::
+
+\1f
+File: magit.info, Node: Listing submodules, Next: Submodule popup, Up: Submodules
+
+8.3.1 Listing submodules
+------------------------
+
+The command ‘magit-list-submodule’ displays a list of the current
+repository’s submodules in a separate buffer. It’s also possible to
+display information about submodules directly in the status buffer of
+the super-repository by adding ‘magit-insert-submodules’ to the hook
+‘magit-status-sections-hook’.
+
+ -- Command: magit-list-submodules
+
+ This command displays a list of the current repository’s submodules
+ in a separate buffer.
+
+ It can be invoked by pressing ‘RET’ on the section titled
+ "Modules".
+
+ -- User Option: magit-submodule-list-columns
+
+ This option controls what columns are displayed by the command
+ ‘magit-list-submodules’ and how they are displayed.
+
+ Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’.
+
+ HEADER is the string displayed in the header. WIDTH is the width
+ of the column. FORMAT is a function that is called with one
+ argument, the repository identification (usually its basename), and
+ with ‘default-directory’ bound to the toplevel of its working tree.
+ It has to return a string to be inserted or nil. PROPS is an alist
+ that supports the keys ‘:right-align’ and ‘:pad-right’.
+
+ -- Function: magit-insert-submodules
+
+ Insert sections for all submodules. For each section insert the
+ path, the branch, and the output of ‘git describe --tags’.
+
+ Press ‘RET’ on such a submodule section to show its own status
+ buffer. Press ‘RET’ on the "Modules" section to display a list of
+ submodules in a separate buffer. This shows additional information
+ not displayed in the super-repository’s status buffer.
+
+\1f
+File: magit.info, Node: Submodule popup, Prev: Listing submodules, Up: Submodules
+
+8.3.2 Submodule popup
+---------------------
+
+‘o’ (‘magit-submodule-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+‘o a’ (‘magit-submodule-add’)
+
+ Add the repository at URL as a submodule. Optional PATH is the
+ path to the submodule relative to the root of the super-project.
+ If it is nil then the path is determined based on URL.
+
+‘o b’ (‘magit-submodule-setup’)
+
+ Clone and register missing submodules and checkout appropriate
+ commits.
+
+‘o i’ (‘magit-submodule-init’)
+
+ Register submodules listed in ".gitmodules" into ".git/config".
+
+‘o u’ (‘magit-submodule-update’)
+
+ Clone missing submodules and checkout appropriate commits. With a
+ prefix argument also register submodules in ".git/config".
+
+‘o s’ (‘magit-submodule-sync’)
+
+ Update each submodule’s remote URL according to ".gitmodules".
+
+‘o f’ (‘magit-submodule-fetch’)
+
+ Fetch submodule. With a prefix argument fetch all remotes.
+
+‘o i’ (‘magit-submodule-init’)
+
+ Unregister the submodule at PATH.
+
+\1f
+File: magit.info, Node: Subtree, Next: Common commands, Prev: Submodules, Up: Miscellaneous
+
+8.4 Subtree
+===========
+
+Also see *note (gitman)git-subtree:: .
+
+‘O’ (‘magit-tree-popup’)
+
+ This prefix command shows the following suffix commands along with
+ the appropriate infix arguments in a popup buffer.
+
+ Most infix arguments only apply to some of the ‘git subtree’
+subcommands. When an argument that does not apply to the invoked
+command is set, then it is silently ignored.
+
+ When the ‘--prefix’ argument is set in the popup buffer, then that is
+used. Otherwise the prefix is read in the minibuffer.
+
+‘O a’ (‘magit-subtree-add’)
+
+ Add COMMIT from REPOSITORY as a new subtree at PREFIX.
+
+‘O c’ (‘magit-subtree-add-commit’)
+
+ Add COMMIT as a new subtree at PREFIX.
+
+‘O m’ (‘magit-subtree-merge’)
+
+ Merge COMMIT into the PREFIX subtree.
+
+‘O f’ (‘magit-subtree-pull’)
+
+ Pull COMMIT from REPOSITORY into the PREFIX subtree.
+
+‘O p’ (‘magit-subtree-push’)
+
+ Extract the history of the subtree PREFIX and push it to REF on
+ REPOSITORY.
+
+‘O s’ (‘magit-subtree-split’)
+
+ Extract the history of the subtree PREFIX.
+
+\1f
+File: magit.info, Node: Common commands, Next: Wip modes, Prev: Subtree, Up: Miscellaneous
+
+8.5 Common commands
+===================
+
+These are some of the commands that can be used in all buffers whose
+major-modes derive from ‘magit-mode’. There are other common commands
+beside the ones below, but these didn’t fit well anywhere else.
+
+‘M-w’ (‘magit-copy-section-value’)
+
+ This command saves the value of the current section to the
+ ‘kill-ring’, and, provided that the current section is a commit,
+ branch, or tag section, it also pushes the (referenced) revision to
+ the ‘magit-revision-stack’.
+
+ When the current section is a branch or a tag, and a prefix
+ argument is used, then it saves the revision at its tip to the
+ ‘kill-ring’ instead of the reference name.
+
+‘C-w’ (‘magit-copy-buffer-revision’)
+
+ This command save the revision being displayed in the current
+ buffer to the ‘kill-ring’ and also pushes it to the
+ ‘magit-revision-stack’. It is mainly intended for use in
+ ‘magit-revision-mode’ buffers, the only buffers where it is always
+ unambiguous exactly which revision should be saved.
+
+ Most other Magit buffers usually show more than one revision, in
+ some way or another, so this command has to select one of them, and
+ that choice might not always be the one you think would have been
+ the best pick.
+
+ Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to
+‘kill-ring-save’ and ‘kill-region’, and these commands would also be
+useful in Magit buffers. Therefore when the region is active, then both
+of these commands behave like ‘kill-ring-save’ instead of as described
+above.
+
+\1f
+File: magit.info, Node: Wip modes, Next: Minor mode for buffers visiting files, Prev: Common commands, Up: Miscellaneous
+
+8.6 Wip modes
+=============
+
+Git keeps *committed* changes around long enough for users to recover
+changes they have accidentally deleted. It does so by not garbage
+collecting any committed but no longer referenced objects for a certain
+period of time, by default 30 days.
+
+ But Git does *not* keep track of *uncommitted* changes in the working
+tree and not even the index (the staging area). Because Magit makes it
+so convenient to modify uncommitted changes, it also makes it easy to
+shoot yourself in the foot in the process.
+
+ For that reason Magit provides three global modes that save *tracked*
+files to work-in-progress references after or before certain actions.
+(Untracked files are never saved and these modes also only work after
+the first commit has been created).
+
+ Two separate work-in-progress references are used to track the state
+of the index and of the working tree: "refs/wip/index/<branchref>" and
+"refs/wip/wtree/<branchref>", where ‘<branchref>’ is the full ref of the
+current branch, e.g. "refs/heads/master". When the ‘HEAD’ is detached
+then "HEAD" is in place of ‘<branchref>’.
+
+ Checking out another branch (or detaching ‘HEAD’) causes the use of
+different wip refs for subsequent changes, but the old refs are not
+deleted.
+
+ Creating a commit and then making a change causes the wip refs to be
+recreated to fork from the new commit. But the old commits on the wip
+refs are not lost. They are still available from the reflog. To make
+it easier to see when the fork point of a wip ref was changed, an
+additional commit with the message "restart autosaving" is created on it
+(‘xxO’ commits below are such boundary commits).
+
+ Starting with
+
+ BI0---BI1 refs/wip/index/refs/heads/master
+ /
+A---B refs/heads/master
+ \
+ BW0---BW1 refs/wip/wtree/refs/heads/master
+
+ and committing the staged changes and editing and saving a file would
+result in
+
+ BI0---BI1 refs/wip/index/refs/heads/master
+ /
+A---B---C refs/heads/master
+ \ \
+ \ CW0---CW1 refs/wip/wtree/refs/heads/master
+ \
+ BW0---BW1 refs/wip/wtree/refs/heads/master@{2}
+
+ The fork-point of the index wip ref is not changed until some change
+is being staged. Likewise just checking out a branch or creating a
+commit does not change the fork-point of the working tree wip ref. The
+fork-points are not adjusted until there actually is a change that
+should be committed to the respective wip ref.
+
+ To view the log for the a branch and its wip refs use the commands
+‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’
+when using these commands. Alternatively you can use the reflog to show
+all commits that ever existed on a wip ref. You can then recover lost
+changes from the commits shown in the log or reflog.
+
+ -- Command: magit-wip-log
+
+ This command shows the log for a branch and its wip refs.
+
+ With a negative prefix argument only the worktree wip ref is shown.
+ The absolute numeric value of the prefix argument controls how many
+ "branches" of each wip ref are shown.
+
+ -- Command: magit-wip-log-current
+
+ This command shows the log for the current branch and its wip refs.
+
+ With a negative prefix argument only the worktree wip ref is shown.
+ The absolute numeric value of the prefix argument controls how many
+ "branches" of each wip ref are shown.
+
+ There exists a total of three global modes that save to the wip refs,
+which might seem excessive, but allows fine tuning of when exactly
+changes are being committed to the wip refs. Enabling all modes makes
+it less likely that a change slips through the cracks.
+
+ Setting the below variable directly does not take effect; either
+customize them or call the respective mode function.
+
+ -- User Option: magit-wip-after-save-mode
+
+ When this mode is enabled, then saving a buffer that visits a file
+ tracked in a Git repository causes its current state to be
+ committed to the working tree wip ref for the current branch.
+
+ -- User Option: magit-wip-after-apply-mode
+
+ When this mode is enabled, then applying (i.e. staging, unstaging,
+ discarding, reversing, and regularly applying) a change to a file
+ tracked in a Git repository causes its current state to be
+ committed to the index and/or working tree wip refs for the current
+ branch.
+
+ If you only ever edit files using Emacs and only ever interact with
+Git using Magit, then the above two modes should be enough to protect
+each and every change from accidental loss. In practice nobody does
+that. So an additional mode exists that does commit to the wip refs
+before making changes that could cause the loss of earlier changes.
+
+ -- User Option: magit-wip-before-change-mode
+
+ When this mode is enabled, then certain commands commit the
+ existing changes to the files they are about to make changes to.
+
+ Note that even if you enable all three modes this won’t give you
+perfect protection. The most likely scenario for losing changes despite
+the use of these modes is making a change outside Emacs and then
+destroying it also outside Emacs. In such a scenario, Magit, being an
+Emacs package, didn’t get the opportunity to keep you from shooting
+yourself in the foot.
+
+ When you are unsure whether Magit did commit a change to the wip
+refs, then you can explicitly request that all changes to all tracked
+files are being committed.
+
+‘M-x magit-wip-commit’ (‘magit-wip-commit’)
+
+ This command commits all changes to all tracked files to the index
+ and working tree work-in-progress refs. Like the modes described
+ above, it does not commit untracked files, but it does check all
+ tracked files for changes. Use this command when you suspect that
+ the modes might have overlooked a change made outside Emacs/Magit.
+
+ -- User Option: magit-wip-after-save-local-mode-lighter
+
+ Mode-line lighter for ‘magit-wip-after-save-local-mode’.
+
+ -- User Option: magit-wip-after-apply-mode-lighter
+
+ Mode-line lighter for ‘magit-wip-after-apply-mode’.
+
+ -- User Option: magit-wip-before-change-mode-lighter
+
+ Mode-line lighter for ‘magit-wip-before-change-mode’.
+
+ -- User Option: magit-wip-namespace
+
+ The namespace used for work-in-progress refs. It has to end with a
+ slash. The wip refs are named "<namespace>index/<branchref>" and
+ "<namespace>wtree/<branchref>". When snapshots are created while
+ the ‘HEAD’ is detached then "HEAD" is used in place of
+ ‘<branchref>’.
+
+\1f
+File: magit.info, Node: Minor mode for buffers visiting files, Next: Minor mode for buffers visiting blobs, Prev: Wip modes, Up: Miscellaneous
+
+8.7 Minor mode for buffers visiting files
+=========================================
+
+The ‘magit-file-mode’ enables certain Magit features in file-visiting
+buffers belonging to a Git repository. It should be enabled globally
+using ‘global-magit-file-mode’. Currently this mode only establishes a
+few key bindings, but this might be extended in the future.
+
+ -- User Option: magit-file-mode
+
+ Whether to establish certain Magit key bindings in all
+ file-visiting buffers belonging to a Git repository. This
+ establishes the bindings suggested in *note Getting started:
+ Getting started. (but only for file-visiting buffers), and
+ additionally binds ‘C-c M-g’ to ‘magit-file-popup’.
+
+‘C-c M-g’ (‘magit-file-popup’)
+
+ This prefix command shows a popup buffer featuring suffix commands
+ that operate on the file being visited in the current buffer.
+
+‘C-c M-g s’ (‘magit-stage-file’)
+
+ Stage all changes to the file being visited in the current buffer.
+
+‘C-c M-g u’ (‘magit-unstage-file’)
+
+ Unstage all changes to the file being visited in the current
+ buffer.
+
+‘C-c M-g c’ (‘magit-commit-popup’)
+
+ This prefix command shows suffix commands along with the
+ appropriate infix arguments in a popup buffer. See *note
+ Initiating a commit: Initiating a commit.
+
+‘C-c M-g D’ (‘magit-diff-buffer-file-popup’)
+
+ This prefix command shows the same suffix commands and infix
+ arguments in a popup buffer as ‘magit-diff-popup’. But this
+ variant has to be called from a file-visiting buffer and the
+ visited file is automatically used in the popup to limit the diff
+ to that file.
+
+‘C-c M-g d’ (‘magit-diff-buffer-file’)
+
+ This command shows the diff for the file of blob that the current
+ buffer visits. Renames are followed when a prefix argument is used
+ or when ‘--follow’ is part of ‘magit-diff-arguments’.
+
+ -- User Option: magit-diff-buffer-file-locked
+
+ This option controls whether ‘magit-diff-buffer-file’ uses a
+ decicated buffer. See *note Modes and Buffers: Modes and Buffers.
+
+‘C-c M-g L’ (‘magit-log-buffer-file-popup’)
+
+ This prefix command shows the same suffix commands and infix
+ arguments in a popup buffer as ‘magit-log-popup’. But this variant
+ has to be called from a file-visiting buffer and the visited file
+ is automatically used in the popup to limit the log to that file.
+
+‘C-c M-g l’ (‘magit-log-buffer-file’)
+
+ This command shows the log for the file of blob that the current
+ buffer visits. Renames are followed when a prefix argument is used
+ or when ‘--follow’ is part of ‘magit-log-arguments’.
+
+ -- User Option: magit-log-buffer-file-locked
+
+ This option controls whether ‘magit-log-buffer-file’ uses a
+ decicated buffer. See *note Modes and Buffers: Modes and Buffers.
+
+‘C-c M-g b’ (‘magit-blame-popup’)
+
+ This prefix command shows the ‘magit-blame’ suffix command along
+ with the appropriate infix arguments in a popup buffer. See *note
+ Initiating a commit: Initiating a commit.
+
+‘C-c M-g p’ (‘magit-blob-previous’)
+
+ Visit the previous blob which modified the current file.
+
+\1f
+File: magit.info, Node: Minor mode for buffers visiting blobs, Prev: Minor mode for buffers visiting files, Up: Miscellaneous
+
+8.8 Minor mode for buffers visiting blobs
+=========================================
+
+The ‘magit-blob-mode’ enables certain Magit features in blob-visiting
+buffers. Such buffers can be created using ‘magit-find-file’ and some
+of the commands mentioned below, which also take care of turning on this
+minor mode. Currently this mode only establishes a few key bindings,
+but this might be e
+
+‘p’ (‘magit-blob-previous’)
+
+ Visit the previous blob which modified the current file.
+
+‘n’ (‘magit-blob-next’)
+
+ Visit the next blob which modified the current file.
+
+‘q’ (‘magit-kill-this-buffer’)
+
+ Kill the current buffer.
+
+\1f
+File: magit.info, Node: Customizing, Next: Plumbing, Prev: Miscellaneous, Up: Top
+
+9 Customizing
+*************
+
+Both Git and Emacs are highly customizable. Magit is both a Git
+porcelain as well as an Emacs package, so it makes sense to customize it
+using both Git variables as well as Emacs options. However this
+flexibility doesn’t come without problems, including but not limited to
+the following.
+
+ • Some Git variables automatically have an effect in Magit without
+ requiring any explicit support. Sometimes that is desirable - in
+ other cases, it breaks Magit.
+
+ When a certain Git setting breaks Magit but you want to keep using
+ that setting on the command line, then that can be accomplished by
+ overriding the value for Magit only by appending something like
+ ‘("-c" "some.variable=compatible-value")’ to
+ ‘magit-git-global-arguments’.
+
+ • Certain settings like ‘fetch.prune=true’ are respected by Magit
+ commands (because they simply call the respective Git command) but
+ their value is not reflected in the respective popup buffers. In
+ this case the ‘--prune’ argument in ‘magit-fetch-popup’ might be
+ active or inactive depending on the value of
+ ‘magit-fetch-arguments’ only, but that doesn’t keep the Git
+ variable from being honored by the suffix commands anyway. So
+ pruning might happen despite the the ‘--prune’ arguments being
+ displayed in a way that seems to indicate that no pruning will
+ happen.
+
+ I intend to address these and similar issues in a future release.
+
+* Menu:
+
+* Per-repository configuration::
+* Essential settings::
+
+\1f
+File: magit.info, Node: Per-repository configuration, Next: Essential settings, Up: Customizing
+
+9.1 Per-repository configuration
+================================
+
+Magit can be configured on a per-repository level using both Git
+variables as well as Emacs options.
+
+ To set a Git variable for one repository only, simply set it in
+‘/path/to/repo/.git/config’ instead of ‘$HOME/.gitconfig’ or
+‘/etc/gitconfig’. See *note (gitman)git-config:: .
+
+ Similarly, Emacs options can be set for one repository only by
+editing ‘/path/to/repo/.dir-locals.el’. See *note (emacs)Directory
+Variables::. For example to disable automatic refreshes of
+file-visiting buffers in just one huge repository use this:
+
+ • ‘/path/to/huge/repo/.dir-locals.el’
+
+ ((nil . ((magit-refresh-buffers . nil))
+
+ If you want to apply the same settings to several, but not all,
+repositories then keeping the repository-local config files in sync
+would quickly become annoying. To avoid that you can create config
+files for certain classes of repositories (e.g. "huge repositories")
+and then include those files in the per-repository config files. For
+example:
+
+ • ‘/path/to/huge/repo/.git/config’
+
+ [include]
+ path = /path/to/huge-gitconfig
+
+ • ‘/path/to/huge-gitconfig’
+
+ [status]
+ showUntrackedFiles = no
+
+ • ‘$HOME/.emacs.d/init.el’
+
+ (dir-locals-set-class-variables 'huge-git-repository
+ '((nil . ((magit-refresh-buffers . nil)))))
+
+ (dir-locals-set-directory-class
+ "/path/to/huge/repo/" 'huge-git-repository)
+
+\1f
+File: magit.info, Node: Essential settings, Prev: Per-repository configuration, Up: Customizing
+
+9.2 Essential settings
+======================
+
+The next two sections list and discuss several variables that many users
+might want to customize, for safety and/or performance reasons.
+
+* Menu:
+
+* Safety::
+* Performance::
+
+\1f
+File: magit.info, Node: Safety, Next: Performance, Up: Essential settings
+
+9.2.1 Safety
+------------
+
+This section discusses various variables that you might want to change
+(or *not* change) for safety reasons.
+
+ Git keeps *committed* changes around long enough for users to recover
+changes they have accidentally been deleted. It does not do the same
+for *uncommitted* changes in the working tree and not even the index
+(the staging area). Because Magit makes it so easy to modify
+uncommitted changes, it also makes it easy to shoot yourself in the foot
+in the process. For that reason Magit provides three global modes that
+save *tracked* files to work-in-progress references after or before
+certain actions. See *note Wip modes: Wip modes.
+
+ These modes are not enabled by default because of performance
+concerns. Instead a lot of potentially destructive commands require
+confirmation every time they are used. In many cases this can be
+disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion
+and confirmation: Completion and confirmation.). If you enable the
+various wip modes then you should add ‘safe-with-wip’ to this list.
+
+ Similarly it isn’t necessary to require confirmation before moving a
+file to the system trash - if you trashed a file by mistake then you can
+recover it from the there. Option ‘magit-delete-by-moving-to-trash’
+controls whether the system trash is used, which is the case by default.
+Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might
+want to change that.
+
+ By default buffers visiting files are automatically reverted when the
+visited file changes on disk. This isn’t as risky as it might seem, but
+to make an informed decision you should see *note Risk of Reverting
+Automatically: Risk of Reverting Automatically.
+
+\1f
+File: magit.info, Node: Performance, Prev: Safety, Up: Essential settings
+
+9.2.2 Performance
+-----------------
+
+After Magit has run ‘git’ for side-effects, it also refreshes the
+current Magit buffer and the respective status buffer. This is
+necessary because otherwise outdated information might be displayed
+without the user noticing. Magit buffers are updated by recreating
+their content from scratch, which makes updating simpler and less
+error-prone, but also more costly. Keeping it simple and just
+re-creating everything from scratch is an old design decision and
+departing from that will require major refactoring.
+
+ I plan to do that in time for the next major release. I also intend
+to create logs and diffs asynchronously, which should also help a lot
+but also requires major refactoring.
+
+ Meanwhile you can tell Magit to only automatically refresh the
+current Magit buffer, but not the status buffer. If you do that, then
+the status buffer is only refreshed automatically if it itself is the
+current buffer.
+
+ (setq magit-refresh-status-buffer nil)
+
+ You should also check whether any third-party packages have added
+anything to ‘magit-refresh-buffer-hook’, ‘magit-status-refresh-hook’,
+‘magit-pre-refresh-hook’, and ‘magit-post-refresh-hook’. If so, then
+check whether those additions impacts performance significantly.
+Setting ‘magit-refresh-verbose’ and then inspecting the output in the
+‘*Messages*’ buffer, should help doing so.
+
+ Magit also reverts buffers which visit files located inside the
+current repository, when the visited file changes on disk. That is
+implemented on top of ‘auto-revert-mode’ from the built-in library
+‘autorevert’. To figure out whether that impacts performance, check
+whether performance is significantly worse, when many buffers exist
+and/or when some buffers visit files using Tramp. If so, then this
+should help.
+
+ (setq auto-revert-buffer-list-filter
+ 'magit-auto-revert-repository-buffers-p)
+
+ For alternative approaches see *note Automatic Reverting of
+File-Visiting Buffers: Automatic Reverting of File-Visiting Buffers.
+
+ If you have enabled any features that are disabled by default, then
+you should check whether they impact performance significantly. It’s
+likely that they were not enabled by default because it is known that
+they reduce performance at least in large repositories.
+
+ If performance is only slow inside certain unusually large
+repositories, then you might want to disable certain features on a
+per-repository or per-repository-class basis only. See *note
+Per-repository configuration: Per-repository configuration.
+
+Microsoft Windows Performance
+.............................
+
+In order to update the status buffer, ‘git’ has to be run a few dozen
+times. That is only problematic on Microsoft Windows, because that
+operating system is exceptionally slow at starting processes. Sadly
+this is an issue that can only be fixed by Microsoft itself, and they
+don’t appear to be particularly interested in doing so.
+
+ Beside the subprocess issue, there also exist other Window-specific
+performance issues, some of which can be worked around. The maintainers
+of "Git for Windows" try to reduce their effect, and in order to benefit
+from the latest performance tweaks, should always use the latest
+release. Magit too tries to work around some Windows-specific issues.
+
+ According to some sources setting the following Git variables can
+also help.
+
+ git config --global core.preloadindex true # default since v2.1
+ git config --global core.fscache true # default since v2.8
+ git config --global gc.auto 256
+
+ You should also check whether an anti-virus program is slowing things
+down.
+
+Log Performance
+...............
+
+When showing logs, Magit limits the number of commits initially shown in
+the hope that this avoids unnecessary work. When using ‘--graph’ is
+used, then this unfortunately does not have the desired effect for large
+histories. Junio, Git’s maintainer, said on the git mailing list
+(<http://www.spinics.net/lists/git/msg232230.html>): "‘--graph’ wants to
+compute the whole history and the max-count only affects the output
+phase after ‘--graph’ does its computation".
+
+ In other words, it’s not that Git is slow at outputting the
+differences, or that Magit is slow at parsing the output - the problem
+is that Git first goes outside and has a smoke.
+
+ We actually work around this issue by limiting the number of commits
+not only by using ‘-<N>’ but by also using a range. But unfortunately
+that’s not always possible.
+
+ In repositories with more than a few thousand commits ‘--graph’
+should never be a member of ‘magit-log-section-arguments’. That
+variable is used in the status buffer which is refreshed every time you
+run any Magit command.
+
+ Using ‘--color --graph’ is even slower. Magit uses code that is part
+of Emacs to turn control characters into faces. That code is pretty
+slow and this is quite noticeable when showing a log with many branches
+and merges. For that reason ‘--color’ is not enabled by default
+anymore. Consider leaving it at that.
+
+Diff Performance
+................
+
+If diffs are slow, then consider turning off some optional diff features
+by setting all or some of the following variables to ‘nil’:
+‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’,
+‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and
+‘magit-diff-refine-hunk’.
+
+ When showing a commit instead of some arbitrary diff, then some
+additional information is displayed. Calculating this information can
+be quite expensive given certain circumstances. If looking at a commit
+using ‘magit-revision-mode’ takes considerably more time than looking at
+the same commit in ‘magit-diff-mode’, then consider setting
+‘magit-revision-insert-related-refs’ to ‘nil’.
+
+Refs Buffer Performance
+.......................
+
+When refreshing the "references buffer" is slow, then that’s usually
+because several hundred refs are being displayed. The best way to
+address that is to display fewer refs, obviously.
+
+ If you are not, or only mildly, interested in seeing the list of
+tags, then start by not displaying them:
+
+ (remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
+
+ Then you should also make sure that the listed remote branches
+actually all exist. You can do so by pruning branches which no longer
+exist using ‘f-pa’.
+
+Committing Performance
+......................
+
+When you initiate a commit, then Magit by default automatically shows a
+diff of the changes you are about to commit. For large commits this can
+take a long time, which is especially distracting when you are
+committing large amounts of generated data which you don’t actually
+intend to inspect before committing. This behavior can be turned off
+using:
+
+ (remove-hook 'server-switch-hook 'magit-commit-diff)
+
+ Then you can type ‘C-c C-d’ to show the diff when you actually want
+to see it, but only then. Alternatively you can leave the hook alone
+and just type ‘C-g’ in those cases when it takes to long to generate the
+diff. If you do that, then you will end up with a broken diff buffer,
+but doing it this way has the advantage that you usually get to see the
+diff, which is useful because it increases the odds that you spot
+potential issues.
+
+The built-in VC Package
+.......................
+
+Emacs comes with a version control interface called "VC", see *note
+(emacs)Version Control::. It is enabled be default and if you don’t use
+it in addition to Magit, then you should disable it to keep it from
+performing unnecessary work:
+
+ (setq vc-handled-backends nil)
+
+ You can also disable its use only for Git but keep using it when
+using another version control system:
+
+ (setq vc-handled-backends (delq 'Git vc-handled-backends))
+
+\1f
+File: magit.info, Node: Plumbing, Next: FAQ, Prev: Customizing, Up: Top
+
+10 Plumbing
+***********
+
+The following sections describe how to use several of Magit’s core
+abstractions to extend Magit itself or implement a separate extension.
+
+ A few of the low-level features used by Magit have been factored out
+into separate libraries/packages, so that they can be used by other
+packages, without having to depend on Magit. These libraries are
+described in separate manuals, see *note (with-editor)Top:: and *note
+(magit-popup)Top::.
+
+ If you are trying to find an unused key that you can bound to a
+command provided by your own Magit extension, then checkout
+<https://github.com/magit/magit/wiki/Plugin-Dispatch-Key-Registry>.
+
+* Menu:
+
+* Calling Git::
+* Section plumbing::
+* Refreshing buffers::
+* Conventions::
+
+\1f
+File: magit.info, Node: Calling Git, Next: Section plumbing, Up: Plumbing
+
+10.1 Calling Git
+================
+
+Magit provides many specialized functions for calling Git. All of these
+functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and
+have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or
+‘magit-git-’ (which is also used for other things).
+
+ All of these functions accept an indefinite number of arguments,
+which are strings that specify command line arguments for git (or in
+some cases an arbitrary executable). These arguments are flattened
+before being passed on to the executable; so instead of strings they can
+also be lists of strings and arguments that are ‘nil’ are silently
+dropped. Some of these functions also require a single mandatory
+argument before these command line arguments.
+
+ Roughly speaking these functions run Git either to get some value or
+for side-effect. The functions that return a value are useful to
+collect the information necessary to populate a Magit buffer, while the
+others are used to implement Magit commands.
+
+ The functions in the value-only group always run synchronously, and
+they never trigger a refresh. The function in the side-effect group can
+be further divided into subgroups depending on whether they run Git
+synchronously or asynchronously, and depending on whether they trigger a
+refresh when the executable has finished.
+
+* Menu:
+
+* Getting a value from Git::
+* Calling Git for effect::
+
+\1f
+File: magit.info, Node: Getting a value from Git, Next: Calling Git for effect, Up: Calling Git
+
+10.1.1 Getting a value from Git
+-------------------------------
+
+These functions run Git in order to get a value, either its exit status
+or its output. Of course you could also use them to run Git commands
+that have side-effects, but that should be avoided.
+
+ -- Function: magit-git-exit-code &rest args
+
+ Executes git with ARGS and returns its exit code.
+
+ -- Function: magit-git-success &rest args
+
+ Executes git with ARGS and returns ‘t’ if the exit code is ‘0’,
+ ‘nil’ otherwise.
+
+ -- Function: magit-git-failure &rest args
+
+ Executes git with ARGS and returns ‘t’ if the exit code is ‘1’,
+ ‘nil’ otherwise.
+
+ -- Function: magit-git-true &rest args
+
+ Executes git with ARGS and returns ‘t’ if the first line printed by
+ git is the string "true", ‘nil’ otherwise.
+
+ -- Function: magit-git-false &rest args
+
+ Executes git with ARGS and returns ‘t’ if the first line printed by
+ git is the string "false", ‘nil’ otherwise.
+
+ -- Function: magit-git-insert &rest args
+
+ Executes git with ARGS and inserts its output at point.
+
+ -- Function: magit-git-string &rest args
+
+ Executes git with ARGS and returns the first line of its output.
+ If there is no output or if it begins with a newline character,
+ then this returns ‘nil’.
+
+ -- Function: magit-git-lines &rest args
+
+ Executes git with ARGS and returns its output as a list of lines.
+ Empty lines anywhere in the output are omitted.
+
+ -- Function: magit-git-items &rest args
+
+ Executes git with ARGS and returns its null-separated output as a
+ list. Empty items anywhere in the output are omitted.
+
+ If the value of option ‘magit-git-debug’ is non-nil and git exits
+ with a non-zero exit status, then warn about that in the echo area
+ and add a section containing git’s standard error in the current
+ repository’s process buffer.
+
+ When an error occurs when using one of the above functions, then that
+is usually due to a bug, i.e. the use of an argument which is not
+actually supported. Such errors are usually not reported, but when they
+occur we need to be able to debug them.
+
+ -- User Option: magit-git-debug
+
+ Whether to report errors that occur when using ‘magit-git-insert’,
+ ‘magit-git-string’, ‘magit-git-lines’, or ‘magit-git-items’. This
+ does not actually raise an error. Instead a message is shown in
+ the echo area, and git’s standard error is insert into a new
+ section in the current repository’s process buffer.
+
+ -- Function: magit-git-str &rest args
+
+ This is a variant of ‘magit-git-string’ that ignores the option
+ ‘magit-git-debug’. It is mainly intended to be used while handling
+ errors in functions that do respect that option. Using such a
+ function while handing an error could cause yet another error and
+ therefore lead to an infinite recursion. You probably won’t ever
+ need to use this function.
+
+\1f
+File: magit.info, Node: Calling Git for effect, Prev: Getting a value from Git, Up: Calling Git
+
+10.1.2 Calling Git for effect
+-----------------------------
+
+These functions are used to run git to produce some effect. Most Magit
+commands that actually run git do so by using such a function.
+
+ Because we do not need to consume git’s output when using these
+functions, their output is instead logged into a per-repository buffer,
+which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’
+elsewhere.
+
+ These functions can have an effect in two distinct ways. Firstly,
+running git may change something, i.e. create or push a new commit.
+Secondly, that change may require that Magit buffers are refreshed to
+reflect the changed state of the repository. But refreshing isn’t
+always desirable, so only some of these functions do perform such a
+refresh after git has returned.
+
+ Sometimes it is useful to run git asynchronously. For example, when
+the user has just initiated a push, then there is no reason to make her
+wait until that has completed. In other cases it makes sense to wait
+for git to complete before letting the user do something else. For
+example after staging a change it is useful to wait until after the
+refresh because that also automatically moves to the next change.
+
+ -- Function: magit-call-git &rest args
+
+ Calls git synchronously with ARGS.
+
+ -- Function: magit-call-process program &rest args
+
+ Calls PROGRAM synchronously with ARGS.
+
+ -- Function: magit-run-git &rest args
+
+ Calls git synchronously with ARGS and then refreshes.
+
+ -- Function: magit-run-git-with-input input &rest args
+
+ Calls git synchronously with ARGS and sends it INPUT on standard
+ input.
+
+ INPUT should be a buffer or the name of an existing buffer. The
+ content of that buffer is used as the process’ standard input.
+ After the process returns a refresh is performed.
+
+ As a special case, INPUT may also be nil. In that case the content
+ of the current buffer is used as standard input and *no* refresh is
+ performed.
+
+ This function actually runs git asynchronously. But then it waits
+ for the process to return, so the function itself is synchronous.
+
+ -- Function: magit-run-git-with-logfile file &rest args
+
+ Calls git synchronously with ARGS. The process’ output is saved in
+ FILE. This is rarely useful and so this function might be removed
+ in the future.
+
+ This function actually runs git asynchronously. But then it waits
+ for the process to return, so the function itself is synchronous.
+
+ -- Function: magit-git &rest args
+
+ Calls git synchronously with ARGS for side-effects only. This
+ function does not refresh the buffer.
+
+ -- Function: magit-git-wash washer &rest args
+
+ Execute Git with ARGS, inserting washed output at point. Actually
+ first insert the raw output at point. If there is no output call
+ ‘magit-cancel-section’. Otherwise temporarily narrow the buffer to
+ the inserted text, move to its beginning, and then call function
+ WASHER with no argument.
+
+ And now for the asynchronous variants.
+
+ -- Function: magit-run-git-async &rest args
+
+ Start Git, prepare for refresh, and return the process object.
+ ARGS is flattened and then used as arguments to Git.
+
+ Display the command line arguments in the echo area.
+
+ After Git returns some buffers are refreshed: the buffer that was
+ current when this function was called (if it is a Magit buffer and
+ still alive), as well as the respective Magit status buffer.
+ Unmodified buffers visiting files that are tracked in the current
+ repository are reverted if ‘magit-revert-buffers’ is non-nil.
+
+ -- Function: magit-run-git-with-editor &rest args
+
+ Export GIT_EDITOR and start Git. Also prepare for refresh and
+ return the process object. ARGS is flattened and then used as
+ arguments to Git.
+
+ Display the command line arguments in the echo area.
+
+ After Git returns some buffers are refreshed: the buffer that was
+ current when this function was called (if it is a Magit buffer and
+ still alive), as well as the respective Magit status buffer.
+
+ -- Function: magit-start-git &rest args
+
+ Start Git, prepare for refresh, and return the process object.
+
+ If INPUT is non-nil, it has to be a buffer or the name of an
+ existing buffer. The buffer content becomes the processes standard
+ input.
+
+ Option ‘magit-git-executable’ specifies the Git executable and
+ option ‘magit-git-global-arguments’ specifies constant arguments.
+ The remaining arguments ARGS specify arguments to Git. They are
+ flattened before use.
+
+ After Git returns, some buffers are refreshed: the buffer that was
+ current when this function was called (if it is a Magit buffer and
+ still alive), as well as the respective Magit status buffer.
+ Unmodified buffers visiting files that are tracked in the current
+ repository are reverted if ‘magit-revert-buffers’ is non-nil.
+
+ -- Function: magit-start-process &rest args
+
+ Start PROGRAM, prepare for refresh, and return the process object.
+
+ If optional argument INPUT is non-nil, it has to be a buffer or the
+ name of an existing buffer. The buffer content becomes the
+ processes standard input.
+
+ The process is started using ‘start-file-process’ and then setup to
+ use the sentinel ‘magit-process-sentinel’ and the filter
+ ‘magit-process-filter’. Information required by these functions is
+ stored in the process object. When this function returns the
+ process has not started to run yet so it is possible to override
+ the sentinel and filter.
+
+ After the process returns, ‘magit-process-sentinel’ refreshes the
+ buffer that was current when ‘magit-start-process’ was called (if
+ it is a Magit buffer and still alive), as well as the respective
+ Magit status buffer. Unmodified buffers visiting files that are
+ tracked in the current repository are reverted if
+ ‘magit-revert-buffers’ is non-nil.
+
+ -- Variable: magit-this-process
+
+ The child process which is about to start. This can be used to
+ change the filter and sentinel.
+
+ -- Variable: magit-process-raise-error
+
+ When this is non-nil, then ‘magit-process-sentinel’ raises an error
+ if git exits with a non-zero exit status. For debugging purposes.
+
+\1f
+File: magit.info, Node: Section plumbing, Next: Refreshing buffers, Prev: Calling Git, Up: Plumbing
+
+10.2 Section plumbing
+=====================
+
+* Menu:
+
+* Creating sections::
+* Section selection::
+* Matching sections::
+
+\1f
+File: magit.info, Node: Creating sections, Next: Section selection, Up: Section plumbing
+
+10.2.1 Creating sections
+------------------------
+
+ -- Macro: magit-insert-section &rest args
+
+ Insert a section at point.
+
+ TYPE is the section type, a symbol. Many commands that act on the
+ current section behave differently depending on that type. Also if
+ a variable ‘magit-TYPE-section-map’ exists, then use that as the
+ text-property ‘keymap’ of all text belonging to the section (but
+ this may be overwritten in subsections). TYPE can also have the
+ form ‘(eval FORM)’ in which case FORM is evaluated at runtime.
+
+ Optional VALUE is the value of the section, usually a string that
+ is required when acting on the section.
+
+ When optional HIDE is non-nil collapse the section body by default,
+ i.e. when first creating the section, but not when refreshing the
+ buffer. Otherwise, expand it by default. This can be overwritten
+ using ‘magit-section-set-visibility-hook’. When a section is
+ recreated during a refresh, then the visibility of predecessor is
+ inherited and HIDE is ignored (but the hook is still honored).
+
+ BODY is any number of forms that actually insert the section’s
+ heading and body. Optional NAME, if specified, has to be a symbol,
+ which is then bound to the struct of the section being inserted.
+
+ Before BODY is evaluated the ‘start’ of the section object is set
+ to the value of ‘point’ and after BODY was evaluated its ‘end’ is
+ set to the new value of ‘point’; BODY is responsible for moving
+ ‘point’ forward.
+
+ If it turns out inside BODY that the section is empty, then
+ ‘magit-cancel-section’ can be used to abort and remove all traces
+ of the partially inserted section. This can happen when creating a
+ section by washing Git’s output and Git didn’t actually output
+ anything this time around.
+
+ -- Function: magit-insert-heading &rest args
+
+ Insert the heading for the section currently being inserted.
+
+ This function should only be used inside ‘magit-insert-section’.
+
+ When called without any arguments, then just set the ‘content’ slot
+ of the object representing the section being inserted to a marker
+ at ‘point’. The section should only contain a single line when
+ this function is used like this.
+
+ When called with arguments ARGS, which have to be strings, then
+ insert those strings at point. The section should not contain any
+ text before this happens and afterwards it should again only
+ contain a single line. If the ‘face’ property is set anywhere
+ inside any of these strings, then insert all of them unchanged.
+ Otherwise use the ‘magit-section-heading’ face for all inserted
+ text.
+
+ The ‘content’ property of the section struct is the end of the
+ heading (which lasts from ‘start’ to ‘content’) and the beginning
+ of the body (which lasts from ‘content’ to ‘end’). If the value of
+ ‘content’ is nil, then the section has no heading and its body
+ cannot be collapsed. If a section does have a heading then its
+ height must be exactly one line, including a trailing newline
+ character. This isn’t enforced; you are responsible for getting it
+ right. The only exception is that this function does insert a
+ newline character if necessary.
+
+ -- Function: magit-cancel-section
+
+ Cancel the section currently being inserted. This exits the
+ innermost call to ‘magit-insert-section’ and removes all traces of
+ what has already happened inside that call.
+
+ -- Function: magit-define-section-jumper sym title &optional value
+
+ Define an interactive function to go to section SYM. TITLE is the
+ displayed title of the section.
+
+\1f
+File: magit.info, Node: Section selection, Next: Matching sections, Prev: Creating sections, Up: Section plumbing
+
+10.2.2 Section selection
+------------------------
+
+ -- Function: magit-current-section
+
+ Return the section at point.
+
+ -- Function: magit-region-sections
+
+ Return a list of the selected sections.
+
+ When the region is active and constitutes a valid section
+ selection, then return a list of all selected sections. This is
+ the case when the region begins in the heading of a section and
+ ends in the heading of a sibling of that first section. When the
+ selection is not valid then return nil. Most commands that can act
+ on the selected sections, then instead just act on the current
+ section, the one point is in.
+
+ When the region looks like it would in any other buffer then the
+ selection is invalid. When the selection is valid then the region
+ uses the ‘magit-section-highlight’. This does not apply to diffs
+ where things get a bit more complicated, but even here if the
+ region looks like it usually does, then that’s not a valid
+ selection as far as this function is concerned.
+
+ -- Function: magit-region-values &rest types
+
+ Return a list of the values of the selected sections.
+
+ Also see ‘magit-region-sections’ whose doc-string explains when a
+ region is a valid section selection. If the region is not active
+ or is not a valid section selection, then return nil. If optional
+ TYPES is non-nil then the selection not only has to be valid; the
+ types of all selected sections additionally have to match one of
+ TYPES, or nil is returned.
+
+\1f
+File: magit.info, Node: Matching sections, Prev: Section selection, Up: Section plumbing
+
+10.2.3 Matching sections
+------------------------
+
+‘M-x magit-describe-section’ (‘magit-describe-section’)
+
+ Show information about the section at point. This command is
+ intended for debugging purposes.
+
+ -- Function: magit-section-ident
+
+ Return an unique identifier for SECTION. The return value has the
+ form ‘((TYPE . VALUE)...)’.
+
+ -- Function: magit-get-section
+
+ Return the section identified by IDENT. IDENT has to be a list as
+ returned by ‘magit-section-ident’.
+
+ -- Function: magit-section-match condition &optional section
+
+ Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the
+ section at point. If SECTION is not specified and there also is no
+ section at point, then return ‘nil’.
+
+ CONDITION can take the following forms:
+ • ‘(CONDITION...)’
+
+ matches if any of the CONDITIONs matches.
+
+ • ‘[TYPE...]’
+
+ matches if the first TYPE matches the type of the section, the
+ second matches that of its parent, and so on.
+
+ • ‘[* TYPE...]’
+
+ matches sections that match [TYPE…] and also recursively all
+ their child sections.
+
+ • ‘TYPE’
+
+ matches sections of TYPE regardless of the types of the parent
+ sections.
+ Each TYPE is a symbol. Note that it is not necessary to specify
+ all TYPEs up to the root section as printed by
+ ‘magit-describe-type’, unless of course you want to be that
+ precise.
+
+ -- Function: magit-section-when condition &rest body
+
+ If the section at point matches CONDITION evaluate BODY.
+
+ If the section matches, then evaluate BODY forms sequentially with
+ ‘it’ bound to the section and return the value of the last form.
+ If there are no BODY forms, then return the value of the section.
+ If the section does not match or if there is no section at point
+ then return nil.
+
+ See ‘magit-section-match’ for the forms CONDITION can take.
+
+ -- Function: magit-section-case &rest clauses
+
+ Choose among clauses on the type of the section at point.
+
+ Each clause looks like (CONDITION BODY…). The type of the section
+ is compared against each CONDITION; the BODY forms of the first
+ match are evaluated sequentially and the value of the last form is
+ returned. Inside BODY the symbol ‘it’ is bound to the section at
+ point. If no clause succeeds or if there is no section at point
+ return nil.
+
+ See ‘magit-section-match’ for the forms CONDITION can take.
+ Additionally a CONDITION of t is allowed in the final clause and
+ matches if no other CONDITION match, even if there is no section at
+ point.
+
+ -- Variable: magit-root-section
+
+ The root section in the current buffer. All other sections are
+ descendants of this section. The value of this variable is set by
+ ‘magit-insert-section’ and you should never modify it.
+
+ For diff related sections a few additional tools exist.
+
+ -- Function: magit-diff-type &optional section
+
+ Return the diff type of SECTION.
+
+ The returned type is one of the symbols ‘staged’, ‘unstaged’,
+ ‘committed’, or ‘undefined’. This type serves a similar purpose as
+ the general type common to all sections (which is stored in the
+ ‘type’ slot of the corresponding ‘magit-section’ struct) but takes
+ additional information into account. When the SECTION isn’t
+ related to diffs and the buffer containing it also isn’t a
+ diff-only buffer, then return nil.
+
+ Currently the type can also be one of ‘tracked’ and ‘untracked’,
+ but these values are not handled explicitly in every place they
+ should be. A possible fix could be to just return nil here.
+
+ The section has to be a ‘diff’ or ‘hunk’ section, or a section
+ whose children are of type ‘diff’. If optional SECTION is nil,
+ return the diff type for the current section. In buffers whose
+ major mode is ‘magit-diff-mode’ SECTION is ignored and the type is
+ determined using other means. In ‘magit-revision-mode’ buffers the
+ type is always ‘committed’.
+
+ -- Function: magit-diff-scope &optional section strict
+
+ Return the diff scope of SECTION or the selected section(s).
+
+ A diff’s "scope" describes what part of a diff is selected, it is a
+ symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or
+ ‘list’. Do not confuse this with the diff "type", as returned by
+ ‘magit-diff-type’.
+
+ If optional SECTION is non-nil, then return the scope of that,
+ ignoring the sections selected by the region. Otherwise return the
+ scope of the current section, or if the region is active and
+ selects a valid group of diff related sections, the type of these
+ sections, i.e. ‘hunks’ or ‘files’. If SECTION (or if the current
+ section that is nil) is a ‘hunk’ section and the region starts and
+ ends inside the body of a that section, then the type is ‘region’.
+
+ If optional STRICT is non-nil then return nil if the diff type of
+ the section at point is ‘untracked’ or the section at point is not
+ actually a ‘diff’ but a ‘diffstat’ section.
+
+\1f
+File: magit.info, Node: Refreshing buffers, Next: Conventions, Prev: Section plumbing, Up: Plumbing
+
+10.3 Refreshing buffers
+=======================
+
+All commands that create a new Magit buffer or change what is being
+displayed in an existing buffer do so by calling ‘magit-mode-setup’.
+Among other things, that function sets the buffer local values of
+‘default-directory’ (to the top-level of the repository),
+‘magit-refresh-function’, and ‘magit-refresh-args’.
+
+ Buffers are refreshed by calling the function that is the local value
+of ‘magit-refresh-function’ (a function named ‘magit-*-refresh-buffer’,
+where ‘*’ may be something like ‘diff’) with the value of
+‘magit-refresh-args’ as arguments.
+
+ -- Macro: magit-mode-setup buffer switch-func mode refresh-func
+ &optional refresh-args
+
+ This function displays and selects BUFFER, turns on MODE, and
+ refreshes a first time.
+
+ This function displays and optionally selects BUFFER by calling
+ ‘magit-mode-display-buffer’ with BUFFER, MODE and SWITCH-FUNC as
+ arguments. Then it sets the local value of
+ ‘magit-refresh-function’ to REFRESH-FUNC and that of
+ ‘magit-refresh-args’ to REFRESH-ARGS. Finally it creates the buffer
+ content by calling REFRESH-FUNC with REFRESH-ARGS as arguments.
+
+ All arguments are evaluated before switching to BUFFER.
+
+ -- Function: magit-mode-display-buffer buffer mode &optional
+ switch-function
+
+ This function display BUFFER in some window and select it. BUFFER
+ may be a buffer or a string, the name of a buffer. The buffer is
+ returned.
+
+ Unless BUFFER is already displayed in the selected frame, store the
+ previous window configuration as a buffer local value, so that it
+ can later be restored by ‘magit-mode-bury-buffer’.
+
+ The buffer is displayed and selected using SWITCH-FUNCTION. If that
+ is ‘nil’ then ‘pop-to-buffer’ is used if the current buffer’s major
+ mode derives from ‘magit-mode’. Otherwise ‘switch-to-buffer’ is
+ used.
+
+ -- Variable: magit-refresh-function
+
+ The value of this buffer-local variable is the function used to
+ refresh the current buffer. It is called with ‘magit-refresh-args’
+ as arguments.
+
+ -- Variable: magit-refresh-args
+
+ The list of arguments used by ‘magit-refresh-function’ to refresh
+ the current buffer. ‘magit-refresh-function’ is called with these
+ arguments.
+
+ The value is usually set using ‘magit-mode-setup’, but in some
+ cases it’s also useful to provide commands which can change the
+ value. For example, the ‘magit-diff-refresh-popup’ can be used to
+ change any of the arguments used to display the diff, without
+ having to specify again which differences should be shown.
+ ‘magit-diff-more-context’, ‘magit-diff-less-context’, and
+ ‘magit-diff-default-context’ change just the ‘-U<N>’ argument. In
+ both case this is done by changing the value of this variable and
+ then calling this ‘magit-refresh-function’.
+
+\1f
+File: magit.info, Node: Conventions, Prev: Refreshing buffers, Up: Plumbing
+
+10.4 Conventions
+================
+
+* Menu:
+
+* Confirmation and completion::
+* Theming Faces::
+
+\1f
+File: magit.info, Node: Confirmation and completion, Next: Theming Faces, Up: Conventions
+
+10.4.1 Confirmation and completion
+----------------------------------
+
+Dangerous operations that may lead to data loss have to be confirmed by
+default. With a multi-section selection, this is done using questions
+that can be answered with "yes" or "no". When the region isn’t active,
+or if it doesn’t constitute a valid section selection, then such
+commands instead read a single item in the minibuffer. When the value
+of the current section is among the possible choices, then that is
+presented as default choice. To confirm the action on a single item,
+the user has to answer ‘RET’ (instead of "yes"), and to abort, ‘C-g’
+(instead of "no"). But alternatively the user may also select another
+item, just like if the command had been invoked with no suitable section
+at point at all.
+
+\1f
+File: magit.info, Node: Theming Faces, Prev: Confirmation and completion, Up: Conventions
+
+10.4.2 Theming Faces
+--------------------
+
+The default theme uses blue for local branches, green for remote
+branches, and goldenrod (brownish yellow) for tags. When creating a new
+theme, you should probably follow that example. If your theme already
+uses other colors, then stick to that.
+
+ In older releases these reference faces used to have a background
+color and a box around them. The basic default faces no longer do so,
+to make Magit buffers much less noisy, and you should follow that
+example at least with regards to boxes. (Boxes were used in the past to
+work around a conflict between the highlighting overlay and text
+property backgrounds. That’s no longer necessary because highlighting
+no longer causes other background colors to disappear.) Alternatively
+you can keep the background color and/or box, but then have to take
+special care to adjust ‘magit-branch-current’ accordingly. By default
+it looks mostly like ‘magit-branch-local’, but with a box (by default
+the former is the only face that uses a box, exactly so that it sticks
+out). If the former also uses a box, then you have to make sure that it
+differs in some other way from the latter.
+
+ The most difficult faces to theme are those related to diffs,
+headings, highlighting, and the region. There are faces that fall into
+all four groups - expect to spend some time getting this right.
+
+ The ‘region’ face in the default theme, in both the light and dark
+variants, as well as in many other themes, distributed with Emacs or by
+third-parties, is very ugly. It is common to use a background color
+that really sticks out, which is ugly but if that were the only problem
+then it would be acceptable. Unfortunately many themes also set the
+foreground color, which ensures that all text within the region is
+readable. Without doing that there might be cases where some foreground
+color is too close to the region background color to still be readable.
+But it also means that text within the region loses all syntax
+highlighting.
+
+ I consider the work that went into getting the ‘region’ face right to
+be a good indicator for the general quality of a theme. My
+recommendation for the ‘region’ face is this: use a background color
+slightly different from the background color of the ‘default’ face, and
+do not set the foreground color at all. So for a light theme you might
+use a light (possibly tinted) gray as the background color of ‘default’
+and a somewhat darker gray for the background of ‘region’. That should
+usually be enough to not collide with the foreground color of any other
+face. But if some other faces also set a light gray as background
+color, then you should also make sure it doesn’t collide with those (in
+some cases it might be acceptable though).
+
+ Magit only uses the ‘region’ face when the region is "invalid" by its
+own definition. In a Magit buffer the region is used to either select
+multiple sibling sections, so that commands which support it act on all
+of these sections instead of just the current section, or to select
+lines within a single hunk section. In all other cases, the section is
+considered invalid and Magit won’t act on it. But such invalid sections
+happen, either because the user has not moved point enough yet to make
+it valid or because she wants to use a non-magit command to act on the
+region, e.g. ‘kill-region’.
+
+ So using the regular ‘region’ face for invalid sections is a feature.
+It tells the user that Magit won’t be able to act on it. It’s
+acceptable if that face looks a bit odd and even (but less so) if it
+collides with the background colors of section headings and other things
+that have a background color.
+
+ Magit highlights the current section. If a section has subsections,
+then all of them are highlighted. This is done using faces that have
+"highlight" in their names. For most sections,
+‘magit-section-highlight’ is used for both the body and the heading.
+Like the ‘region’ face, it should only set the background color to
+something similar to that of ‘default’. The highlight background color
+must be different from both the ‘region’ background color and the
+‘default’ background color.
+
+ For diff related sections Magit uses various faces to highlight
+different parts of the selected section(s). Note that hunk headings,
+unlike all other section headings, by default have a background color,
+because it is useful to have very visible separators between hunks.
+That face ‘magit-diff-hunk-heading’, should be different from both
+‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as
+well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’.
+By default we do that by changing the foreground color. Changing the
+background color would lead to complications, and there are already
+enough we cannot get around. (Also note that it is generally a good
+idea for section headings to always be bold, but only for sections that
+have subsections).
+
+ When there is a valid region selecting diff-related sibling sections,
+i.e. multiple files or hunks, then the bodies of all these sections use
+the respective highlight faces, but additionally the headings instead
+use one of the faces ‘magit-diff-file-heading-selection’ or
+‘magit-diff-hunk-heading-selection’. These faces have to be different
+from the regular highlight variants to provide explicit visual
+indication that the region is active.
+
+ When theming diff related faces, start by setting the option
+‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only
+refine the current hunk or not use hunk refinement at all, but some of
+the users of your theme want all hunks to be refined, so you have to
+cater to that.
+
+ (Also turn on ‘magit-diff-highlight-indentation’,
+‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and
+insert some whitespace errors into the code you use for testing.)
+
+ For e.g. "added lines" you have to adjust three faces:
+‘magit-diff-added’, ‘magit-diff-added-highlight’, and
+‘smerge-refined-added’. Make sure that the latter works well with both
+of the former, as well as ‘smerge-other’ and ‘diff-added’. Then do the
+same for the removed lines, context lines, lines added by us, and lines
+added by them. Also make sure the respective added, removed, and
+context faces use approximately the same saturation for both the
+highlighted and unhighlighted variants. Also make sure the file and
+diff headings work nicely with context lines (e.g. make them look
+different). Line faces should set both the foreground and the
+background color. For example, for added lines use two different
+greens.
+
+ It’s best if the foreground color of both the highlighted and the
+unhighlighted variants are the same, so you will need to have to find a
+color that works well on the highlight and unhighlighted background, the
+refine background, and the highlight context background. When there is
+an hunk internal region, then the added- and removed-lines background
+color is used only within that region. Outside the region the
+highlighted context background color is used. This makes it easier to
+see what is being staged. With an hunk internal region the hunk heading
+is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin
+lines that are added around the lines that fall within the region. The
+background color of that has to be distinct enough from the various
+other involved background colors.
+
+ Nobody said this would be easy. If your theme restricts itself to a
+certain set of colors, then you should make an exception here.
+Otherwise it would be impossible to make the diffs look good in each and
+every variation. Actually you might want to just stick to the default
+definitions for these faces. You have been warned. Also please note
+that if you do not get this right, this will in some cases look to users
+like bugs in Magit - so please do it right or not at all.
+
+\1f
+File: magit.info, Node: FAQ, Next: Keystroke Index, Prev: Plumbing, Up: Top
+
+Appendix A FAQ
+**************
+
+Below you find a list of frequently asked questions. For a list of
+frequently *and recently* asked questions, i.e. questions that haven’t
+made it into the manual yet, see
+<https://github.com/magit/magit/wiki/FAQ>.
+
+* Menu:
+
+* Magit is slow::
+* I changed several thousand files at once and now Magit is unusable::
+* I am having problems committing::
+* Diffs are collapsed after un-/staging::
+* I don't understand how branching and pushing work::
+* I don’t like the key binding in v2.4: I don't like the key binding in v24.
+* I cannot install the pre-requisites for Magit v2::
+* I am using an Emacs release older than v24.4: I am using an Emacs release older than v244.
+* I am using a Git release older than v1.9.4: I am using a Git release older than v194.
+* I am using MS Windows and cannot push with Magit::
+* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
+* How to install the gitman info manual?::
+* How can I show Git's output?::
+* Diffs contain control sequences::
+* Expanding a file to show the diff causes it to disappear::
+* Point is wrong in the ‘COMMIT_EDITMSG’ buffer::
+* The mode-line information isn't always up-to-date::
+* Can Magit be used as ‘ediff-version-control-package’?::
+* How to show diffs for gpg-encrypted files?::
+* Emacs 24.5 hangs when loading Magit: Emacs 245 hangs when loading Magit.
+* Symbol's value as function is void ‘--some’::
+* Where is the branch manager::
+
+\1f
+File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ
+
+A.1 Magit is slow
+=================
+
+See *note Performance: Performance.
+
+\1f
+File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ
+
+A.2 I changed several thousand files at once and now Magit is unusable
+======================================================================
+
+Magit is *currently* not expected to work under such conditions. It
+sure would be nice if it did, and v2.5 will hopefully be a big step into
+that direction. But it might take until v3.1 to accomplish fully
+satisfactory performance, because that requires some heavy refactoring.
+
+ But for now we recommend you use the command line to complete this
+one commit. Also see *note Performance: Performance.
+
+\1f
+File: magit.info, Node: I am having problems committing, Next: Diffs are collapsed after un-/staging, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ
+
+A.3 I am having problems committing
+===================================
+
+That likely means that Magit is having problems finding an appropriate
+emacsclient executable. See *note (with-editor)Configuring
+With-Editor:: and *note (with-editor)Debugging::.
+
+\1f
+File: magit.info, Node: Diffs are collapsed after un-/staging, Next: I don't understand how branching and pushing work, Prev: I am having problems committing, Up: FAQ
+
+A.4 Diffs are collapsed after un-/staging
+=========================================
+
+This typically happens on Windows and/or large repositories where
+preparing diffs takes longer than ‘magit-diff-expansion-threshold’. The
+default is one second, try increasing it to a larger value.
+
+ Currently when one part of a Magit buffer has to be updated the whole
+buffer is recreated from scratch. That obviously isn’t good for
+performance and will be fixed eventually. Meanwhile we need a kludge
+that prevents the update from taking very long under certain
+circumstances, e.g. when showing the difference for hundrets of changes
+files.
+
+ For that reason the variable ‘magit-diff-expansion-threshold’ was
+added, defaulting to one second. If it takes longer than that to
+recreate a Magit buffer, then no further diff sections are expanded
+because that’s one of the steps that take the longest. If a diff is not
+expanded, then some work can be delayed until it actually is.
+
+ You can then still expand sections manually, but when you refresh the
+complete buffer explicitly using ‘g’ or by performing an action which
+triggers a refresh, then previously expanded diffs could be collapsed.
+You can set ‘magit-diff-expansion-threshold’ to a higher value to
+prevent that from happening.
+
+\1f
+File: magit.info, Node: I don't understand how branching and pushing work, Next: I don't like the key binding in v24, Prev: Diffs are collapsed after un-/staging, Up: FAQ
+
+A.5 I don’t understand how branching and pushing work
+=====================================================
+
+Please see *note Branching: Branching. and
+<http://emacsair.me/2016/01/18/magit-2.4>
+
+\1f
+File: magit.info, Node: I don't like the key binding in v24, Next: I cannot install the pre-requisites for Magit v2, Prev: I don't understand how branching and pushing work, Up: FAQ
+
+A.6 I don’t like the key binding in v2.4
+========================================
+
+Please see <http://emacsair.me/2016/01/1/restore-old-bindings>.
+
+\1f
+File: magit.info, Node: I cannot install the pre-requisites for Magit v2, Next: I am using an Emacs release older than v244, Prev: I don't like the key binding in v24, Up: FAQ
+
+A.7 I cannot install the pre-requisites for Magit v2
+====================================================
+
+An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies is
+available from <http://magit.vc/elpa/v1>. But note that v1.4.2 is
+obsolete and no longer maintained.
+
+\1f
+File: magit.info, Node: I am using an Emacs release older than v244, Next: I am using a Git release older than v194, Prev: I cannot install the pre-requisites for Magit v2, Up: FAQ
+
+A.8 I am using an Emacs release older than v24.4
+================================================
+
+At least Emacs v24.4 is required. There is no way around it, if you
+want to use Magit v2.
+
+ If you own the machine you work on, then consider updating to the
+latest release provided by your distribution. If it doesn’t feature a
+recent enough release, then you will have to use a backport package or
+build Emacs from source.
+
+ Installing Emacs from source is quite simple. See the instructions
+at <http://git.savannah.gnu.org/cgit/emacs.git/tree/INSTALL> and
+<http://git.savannah.gnu.org/cgit/emacs.git/tree/INSTALL.REPO> to get an
+idea of that this involves. But when you perform the installation then
+use the instructions for the release you are actually installing.
+
+ Unfortunately these instructions do not cover the hardest part (which
+is the hardest part exactly because it is not covered there): installing
+the build time dependencies.
+
+ For that you’ll need to perform a web search and find an appropriate
+tutorial for your distribution. If you think you should not have had to
+do that yourself, then consider informing me about the resources that
+helped you figure what to do for your specific setup, so that I can post
+a link here. That way those coming after you have it easier.
+
+ An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies
+is available from <http://magit.vc/elpa/v1>.
+
+\1f
+File: magit.info, Node: I am using a Git release older than v194, Next: I am using MS Windows and cannot push with Magit, Prev: I am using an Emacs release older than v244, Up: FAQ
+
+A.9 I am using a Git release older than v1.9.4
+==============================================
+
+At least Git v1.9.4 is required. There is no way around it, if you want
+to use Magit v2.
+
+ If you own the machine, then consider updating to the latest release
+provided by your distribution. If it doesn’t feature a recent enough
+release, then you will have to use a backport package or build Git from
+source.
+
+ Installing Git from source is quite simple. See the instructions at
+<https://github.com/git/git/blob/master/INSTALL> to get an idea of that
+this involves. But when you perform the installation then use the
+instructions for the release you are actually installing.
+
+ An Elpa archive featuring obsolete Magit v1.4.2 and its dependencies
+is available from <http://magit.vc/elpa/v1>.
+
+\1f
+File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using OS X and SOMETHING works in shell but not in Magit, Prev: I am using a Git release older than v194, Up: FAQ
+
+A.10 I am using MS Windows and cannot push with Magit
+=====================================================
+
+It’s almost certain that Magit is only incidental to this issue. It is
+much more likely that this is a configuration issue, even if you can
+push on the command line.
+
+ Detailed setup instructions can be found at
+<https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows>.
+
+\1f
+File: magit.info, Node: I am using OS X and SOMETHING works in shell but not in Magit, Next: How to install the gitman info manual?, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ
+
+A.11 I am using OS X and SOMETHING works in shell, but not in Magit
+===================================================================
+
+This usually occurs because Emacs doesn’t have the same environment
+variables as your shell. Try installing and configuring
+<https://github.com/purcell/exec-path-from-shell>. By default it
+synchronizes ‘$PATH’, which helps Magit find the same ‘git’ as the one
+you are using on the shell.
+
+ If SOMETHING is "passphrase caching with gpg-agent for commit and/or
+tag signing", then you’ll also need to synchronize ‘$GPG_AGENT_INFO’.
+
+\1f
+File: magit.info, Node: How to install the gitman info manual?, Next: How can I show Git's output?, Prev: I am using OS X and SOMETHING works in shell but not in Magit, Up: FAQ
+
+A.12 How to install the gitman info manual?
+===========================================
+
+Git’s manpages can be exported as an info manual called ‘gitman’.
+Magit’s own info manual links to nodes in that manual instead of the
+actual manpages because texinfo sadly doesn’t support linking to
+manpages.
+
+ Unfortunately many distributions do not install the ‘gitman’ manual
+by default. Some distributions may provide a separate package
+containing the info manual. Please let me know the name of that package
+for your distribution, so that I can mention here.
+
+ If the distribution you are using does not offer a package that
+contains the ‘gitman’ manual, then you have to install it manually.
+Clone Git’s own Git repository, checkout the tag corresponding to the
+Git release you have installed, and follow the instructions in
+‘INSTALL’. The relevant make targets are ‘info’ and ‘install-info’.
+
+ Alternatively you may add this advice to your ‘init.el’ file.
+
+ (defadvice Info-follow-nearest-node (around gitman activate)
+ "When encountering a cross reference to the `gitman' info
+ manual, then instead of following that cross reference show
+ the actual manpage using the function `man'."
+ (let ((node (Info-get-token
+ (point) "\\*note[ \n\t]+"
+ "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
+ (if (and node (string-match "^(gitman)\\(.+\\)" node))
+ (progn (require 'man)
+ (man (match-string 1 node)))
+ ad-do-it)))
+
+ Or if you are using MS Windows and ‘man’ is not available, use this
+variation with used the Emacs Lisp implementation provided by the
+‘woman’ package.
+
+ (defadvice Info-follow-nearest-node (around gitman activate)
+ "When encountering a cross reference to the `gitman' info
+ manual, then instead of following that cross reference show
+ the actual manpage using the function `woman'."
+ (let ((node (Info-get-token
+ (point) "\\*note[ \n\t]+"
+ "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
+ (if (and node (string-match "^(gitman)\\(.+\\)" node))
+ (progn (require 'woman)
+ (woman (match-string 1 node)))
+ ad-do-it)))
+
+ Did I mention that texinfo cross reference are just awful? (This is
+just one of many issues.)
+
+\1f
+File: magit.info, Node: How can I show Git's output?, Next: Diffs contain control sequences, Prev: How to install the gitman info manual?, Up: FAQ
+
+A.13 How can I show Git’s output?
+=================================
+
+To show the output of recently run git commands, press ‘$’ (or, if that
+isn’t available, ‘M-x magit-process-buffer’). This will show a buffer
+containing a section per git invocation; as always press ‘TAB’ to expand
+or collapse them.
+
+ By default git’s output is only inserted into the process buffer if
+it is run for side-effects. When the output is consumed in some way
+then also inserting it into the process buffer would be to expensive.
+For debugging purposes it’s possible to do so anyway by setting
+‘magit-git-debug’ to ‘t’.
+
+\1f
+File: magit.info, Node: Diffs contain control sequences, Next: Expanding a file to show the diff causes it to disappear, Prev: How can I show Git's output?, Up: FAQ
+
+A.14 Diffs contain control sequences
+====================================
+
+This happens when you configure Git to always color diffs and/or all of
+its output. The valid values for relevant Git variables ‘color.ui’ and
+‘color.diff’ are ‘false’, ‘true’ and ‘always’, and the default is
+‘true’. You should leave it that because then you get colorful output
+in terminals but git’s output is consumed by something else, then no
+colors are used.
+
+ If you actually use some other tool which expects that requires that
+you force git to output control sequences (which is highly unlikely),
+then you can override these settings just for Magit by using:
+
+ (setq magit-git-global-arguments
+ (nconc magit-git-global-arguments
+ '("-c" "color.ui=false"
+ "-c" "color.diff=false")))
+
+\1f
+File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the ‘COMMIT_EDITMSG’ buffer, Prev: Diffs contain control sequences, Up: FAQ
+
+A.15 Expanding a file to show the diff causes it to disappear
+=============================================================
+
+This is probably caused by a change of a ‘diff.*’ Git variable. You
+probably set that variable for a reason, and should therefore only undo
+that setting in Magit by customizing ‘magit-git-global-arguments’.
+
+\1f
+File: magit.info, Node: Point is wrong in the ‘COMMIT_EDITMSG’ buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ
+
+A.16 Point is wrong in the ‘COMMIT_EDITMSG’ buffer
+==================================================
+
+Neither Magit nor ‘git-commit‘ fiddle with point in the buffer used to
+write commit messages, so something else must be doing it.
+
+ You have probably globally enabled a mode which does restore point in
+file-visiting buffers. It might be a bit surprising, but when you write
+a commit message, then you are actually editing a file.
+
+ So you have to figure out which package is doing. ‘saveplace’,
+‘pointback’, and ‘session’ are likely candidates. These snippets might
+help:
+
+ (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)")
+
+ (with-eval-after-load 'pointback
+ (lambda ()
+ (when (or git-commit-mode git-rebase-mode)
+ (pointback-mode -1))))
+
+\1f
+File: magit.info, Node: The mode-line information isn't always up-to-date, Next: Can Magit be used as ‘ediff-version-control-package’?, Prev: Point is wrong in the ‘COMMIT_EDITMSG’ buffer, Up: FAQ
+
+A.17 The mode-line information isn’t always up-to-date
+======================================================
+
+Magit is not responsible for the version control information that is
+being displayed in the mode-line and looks something like ‘Git-master’.
+The built-in "Version Control" package, also known as "VC", updates that
+information, and can be told to do so more often:
+
+ (setq auto-revert-check-vc-info t)
+
+ But doing so isn’t good for performance. For more (overly
+optimistic) information see *note (emacs)VC Mode Line::.
+
+ If you don’t really care about seeing that information in the
+mode-line, but just don’t want to see _incorrect_ information, then
+consider disabling VC when using Git:
+
+ (setq vc-handled-backends (delq 'Git vc-handled-backends))
+
+ Or to disable it completely:
+
+ (setq vc-handled-backends nil)
+
+\1f
+File: magit.info, Node: Can Magit be used as ‘ediff-version-control-package’?, Next: How to show diffs for gpg-encrypted files?, Prev: The mode-line information isn't always up-to-date, Up: FAQ
+
+A.18 Can Magit be used as ‘ediff-version-control-package’?
+==========================================================
+
+No, it cannot. For that to work the functions ‘ediff-magit-internal’
+and ‘ediff-magit-merge-internal’ would have to be implemented, and they
+are not. These two functions are only used by the three commands
+‘ediff-revision’, ‘ediff-merge-revisions-with-ancestor’, and
+‘ediff-merge-revisions’.
+
+ These commands only delegate the task of populating buffers with
+certain revisions to the "internal" functions. The equally important
+task of determining which revisions are to be compared/merged is not
+delegated. Instead this is done without any support whatsoever, from
+the version control package/system - meaning that the user has to enter
+the revisions explicitly. Instead of implementing
+‘ediff-magit-internal’ we provide ‘magit-ediff-compare’, which handles
+both tasks like it is 2005.
+
+ The other commands ‘ediff-merge-revisions’ and
+‘ediff-merge-revisions-with-ancestor’ are normally not what you want
+when using a modern version control system like Git. Instead of letting
+the user resolve only those conflicts which Git could not resolve on its
+own, they throw away all work done by Git and then expect the user to
+manually merge all conflicts, including those that had already been
+resolved. That made sense back in the days when version control systems
+couldn’t merge (or so I have been told), but not anymore. Once in a
+blue moon you might actually want to see all conflicts, in which case
+you *can* use these commands, which then use ‘ediff-vc-merge-internal’.
+So we don’t actually have to implement ‘ediff-magit-merge-internal’.
+Instead we provide the more useful command ‘magit-ediff-resolve’ which
+only shows yet-to-be resolved conflicts.
+
+\1f
+File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: Emacs 245 hangs when loading Magit, Prev: Can Magit be used as ‘ediff-version-control-package’?, Up: FAQ
+
+A.19 How to show diffs for gpg-encrypted files?
+===============================================
+
+Git supports showing diffs for encrypted files, but has to be told to do
+so. Since Magit just uses Git to get the diffs, configuring Git also
+affects the diffs displayed inside Magit.
+
+ git config --global diff.gpg.textconv "gpg --no-tty --decrypt"
+ echo "*.gpg filter=gpg diff=gpg" > .gitattributes
+
+\1f
+File: magit.info, Node: Emacs 245 hangs when loading Magit, Next: Symbol's value as function is void ‘--some’, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ
+
+A.20 Emacs 24.5 hangs when loading Magit
+========================================
+
+This is actually triggered by loading Tramp. See
+<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=20015> for details. You
+can work around the problem by setting
+‘tramp-ssh-controlmaster-options’. Changing your DNS server (e.g. to
+Google’s ‘8.8.8.8’) may also be sufficient to work around the issue.
+
+\1f
+File: magit.info, Node: Symbol's value as function is void ‘--some’, Next: Where is the branch manager, Prev: Emacs 245 hangs when loading Magit, Up: FAQ
+
+A.21 Symbol’s value as function is void ‘--some’
+================================================
+
+Update ‘dash’, restart Emacs, and then it will be defined.
+
+\1f
+File: magit.info, Node: Where is the branch manager, Prev: Symbol's value as function is void ‘--some’, Up: FAQ
+
+A.22 Where is the branch manager
+================================
+
+‘y’ is bound to the command that shows the "refs buffer", the successor
+of the "branch manager".
+
+\1f
+File: magit.info, Node: Keystroke Index, Next: Command Index, Prev: FAQ, Up: Top
+
+Appendix B Keystroke Index
+**************************
+
+\0\b[index\0\b]
+* Menu:
+
+* !: Running Git manually.
+ (line 12)
+* ! !: Running Git manually.
+ (line 19)
+* ! a: Running Git manually.
+ (line 51)
+* ! b: Running Git manually.
+ (line 55)
+* ! g: Running Git manually.
+ (line 59)
+* ! k: Running Git manually.
+ (line 47)
+* ! p: Running Git manually.
+ (line 24)
+* ! s: Running Git manually.
+ (line 33)
+* ! S: Running Git manually.
+ (line 38)
+* $: Viewing Git output. (line 11)
+* +: Log Buffer. (line 59)
+* + <1>: Refreshing diffs. (line 58)
+* -: Refreshing diffs. (line 54)
+* 0: Refreshing diffs. (line 62)
+* 1: Section visibility. (line 26)
+* 2: Section visibility. (line 26)
+* 3: Section visibility. (line 26)
+* 4: Section visibility. (line 26)
+* =: Log Buffer. (line 53)
+* = <1>: Log Buffer. (line 63)
+* ^: Section movement. (line 31)
+* a: Applying. (line 33)
+* A: Cherry picking. (line 8)
+* A A: Cherry picking. (line 16)
+* A a: Cherry picking. (line 22)
+* A A <1>: Cherry picking. (line 35)
+* A a <1>: Cherry picking. (line 43)
+* A s: Cherry picking. (line 39)
+* B: Bisecting. (line 8)
+* b: The branch popup. (line 12)
+* B B: Bisecting. (line 16)
+* B b: Bisecting. (line 31)
+* b b: The branch popup. (line 29)
+* b c: The branch popup. (line 47)
+* B g: Bisecting. (line 36)
+* B k: Bisecting. (line 41)
+* b k: The branch popup. (line 99)
+* b n: The branch popup. (line 37)
+* B r: Bisecting. (line 47)
+* b r: The branch popup. (line 105)
+* B s: Bisecting. (line 24)
+* b s: The branch popup. (line 54)
+* b x: The branch popup. (line 82)
+* c: Initiating a commit. (line 8)
+* c <1>: Editing rebase sequences.
+ (line 72)
+* c a: Initiating a commit. (line 18)
+* c A: Initiating a commit. (line 66)
+* c c: Initiating a commit. (line 13)
+* c e: Initiating a commit. (line 22)
+* c f: Initiating a commit. (line 42)
+* c F: Initiating a commit. (line 50)
+* c s: Initiating a commit. (line 54)
+* c S: Initiating a commit. (line 62)
+* c w: Initiating a commit. (line 32)
+* C-<return>: Diff buffer. (line 36)
+* C-<tab>: Section visibility. (line 13)
+* C-c C-a: Editing commit messages.
+ (line 128)
+* C-c C-b: Log Buffer. (line 19)
+* C-c C-b <1>: Refreshing diffs. (line 80)
+* C-c C-c: Popup buffers and prefix commands.
+ (line 20)
+* C-c C-c <1>: Select from log. (line 14)
+* C-c C-c <2>: Editing commit messages.
+ (line 19)
+* C-c C-c <3>: Editing rebase sequences.
+ (line 6)
+* C-c C-d: Refreshing diffs. (line 70)
+* C-c C-d <1>: Editing commit messages.
+ (line 57)
+* C-c C-f: Log Buffer. (line 23)
+* C-c C-f <1>: Refreshing diffs. (line 84)
+* C-c C-i: Editing commit messages.
+ (line 153)
+* C-c C-k: Select from log. (line 20)
+* C-c C-k <1>: Editing commit messages.
+ (line 24)
+* C-c C-k <2>: Editing rebase sequences.
+ (line 11)
+* C-c C-n: Log Buffer. (line 27)
+* C-c C-o: Editing commit messages.
+ (line 144)
+* C-c C-p: Editing commit messages.
+ (line 148)
+* C-c C-r: Editing commit messages.
+ (line 132)
+* C-c C-s: Editing commit messages.
+ (line 136)
+* C-c C-t: Editing commit messages.
+ (line 140)
+* C-c C-w: Editing commit messages.
+ (line 63)
+* C-c M-g: Minor mode for buffers visiting files.
+ (line 19)
+* C-c M-g b: Minor mode for buffers visiting files.
+ (line 76)
+* C-c M-g c: Minor mode for buffers visiting files.
+ (line 33)
+* C-c M-g D: Minor mode for buffers visiting files.
+ (line 39)
+* C-c M-g d: Minor mode for buffers visiting files.
+ (line 47)
+* C-c M-g L: Minor mode for buffers visiting files.
+ (line 58)
+* C-c M-g l: Minor mode for buffers visiting files.
+ (line 65)
+* C-c M-g p: Minor mode for buffers visiting files.
+ (line 82)
+* C-c M-g s: Minor mode for buffers visiting files.
+ (line 24)
+* C-c M-g u: Minor mode for buffers visiting files.
+ (line 28)
+* C-s M-s: Editing commit messages.
+ (line 35)
+* C-w: Common commands. (line 21)
+* C-x g: Status buffer. (line 22)
+* C-x u: Editing rebase sequences.
+ (line 89)
+* d: Diffing. (line 20)
+* D: Refreshing diffs. (line 11)
+* d c: Diffing. (line 67)
+* d d: Diffing. (line 25)
+* D f: Refreshing diffs. (line 45)
+* D g: Refreshing diffs. (line 16)
+* d p: Diffing. (line 59)
+* d r: Diffing. (line 29)
+* D r: Refreshing diffs. (line 40)
+* d s: Diffing. (line 49)
+* D s: Refreshing diffs. (line 21)
+* d t: Diffing. (line 72)
+* D t: Refreshing diffs. (line 36)
+* d u: Diffing. (line 55)
+* d w: Diffing. (line 43)
+* D w: Refreshing diffs. (line 28)
+* DEL: Log Buffer. (line 43)
+* DEL <1>: Diff buffer. (line 63)
+* DEL <2>: Blaming. (line 44)
+* DEL <3>: Editing rebase sequences.
+ (line 28)
+* e: Ediffing. (line 9)
+* E: Ediffing. (line 21)
+* e <1>: Editing rebase sequences.
+ (line 55)
+* E c: Ediffing. (line 65)
+* E i: Ediffing. (line 57)
+* E m: Ediffing. (line 35)
+* E r: Ediffing. (line 26)
+* E s: Ediffing. (line 48)
+* E u: Ediffing. (line 53)
+* E w: Ediffing. (line 61)
+* E z: Ediffing. (line 69)
+* f: Editing rebase sequences.
+ (line 63)
+* f <1>: Fetching. (line 11)
+* F: Pulling. (line 11)
+* f a: Fetching. (line 38)
+* f e: Fetching. (line 24)
+* F e: Pulling. (line 24)
+* f m: Fetching. (line 42)
+* f o: Fetching. (line 28)
+* f p: Fetching. (line 16)
+* F p: Pulling. (line 16)
+* f r: Fetching. (line 33)
+* f u: Fetching. (line 20)
+* F u: Pulling. (line 20)
+* g: Automatic Refreshing of Magit Buffers.
+ (line 22)
+* G: Automatic Refreshing of Magit Buffers.
+ (line 31)
+* j: Diff buffer. (line 53)
+* k: Viewing Git output. (line 19)
+* k <1>: Applying. (line 40)
+* k <2>: Editing rebase sequences.
+ (line 68)
+* k <3>: Stashing. (line 92)
+* l: Logging. (line 26)
+* L: Refreshing logs. (line 11)
+* L <1>: Log Buffer. (line 6)
+* l a: Logging. (line 56)
+* l b: Logging. (line 52)
+* L g: Refreshing logs. (line 16)
+* l h: Logging. (line 44)
+* l H: Reflog. (line 19)
+* l l: Logging. (line 31)
+* l L: Logging. (line 48)
+* l o: Logging. (line 37)
+* l O: Reflog. (line 15)
+* l r: Reflog. (line 11)
+* L s: Refreshing logs. (line 21)
+* L t: Refreshing logs. (line 36)
+* L w: Refreshing logs. (line 28)
+* m: Merging. (line 9)
+* M: Remotes. (line 8)
+* m a: Merging. (line 57)
+* M a: Remotes. (line 13)
+* m e: Merging. (line 30)
+* M k: Remotes. (line 28)
+* m m: Merging. (line 17)
+* m m <1>: Merging. (line 52)
+* m n: Merging. (line 37)
+* m p: Merging. (line 44)
+* M r: Remotes. (line 18)
+* M u: Remotes. (line 23)
+* M-1: Section visibility. (line 34)
+* M-2: Section visibility. (line 34)
+* M-3: Section visibility. (line 34)
+* M-4: Section visibility. (line 34)
+* M-<tab>: Section visibility. (line 17)
+* M-n: Section movement. (line 26)
+* M-n <1>: Editing commit messages.
+ (line 45)
+* M-n <2>: Editing rebase sequences.
+ (line 47)
+* M-p: Section movement. (line 20)
+* M-p <1>: Editing commit messages.
+ (line 39)
+* M-p <2>: Editing rebase sequences.
+ (line 43)
+* M-w: Blaming. (line 75)
+* M-w <1>: Common commands. (line 10)
+* M-x magit-blame: Blaming. (line 8)
+* M-x magit-blame-popup: Blaming. (line 24)
+* M-x magit-checkout-file: Resetting. (line 37)
+* M-x magit-clone: Repository setup. (line 16)
+* M-x magit-describe-section: Section types and values.
+ (line 13)
+* M-x magit-describe-section <1>: Matching sections. (line 6)
+* M-x magit-find-file: Visiting blobs. (line 6)
+* M-x magit-find-file-other-window: Visiting blobs. (line 11)
+* M-x magit-init: Repository setup. (line 6)
+* M-x magit-log-buffer-file: Logging. (line 67)
+* M-x magit-reset-hard: Resetting. (line 32)
+* M-x magit-reset-head: Resetting. (line 21)
+* M-x magit-reset-index: Staging and unstaging.
+ (line 88)
+* M-x magit-reset-index <1>: Resetting. (line 14)
+* M-x magit-reset-soft: Resetting. (line 26)
+* M-x magit-reverse-in-index: Staging and unstaging.
+ (line 63)
+* M-x magit-stage-file: Staging from file-visiting buffers.
+ (line 10)
+* M-x magit-toggle-buffer-lock: Modes and Buffers. (line 17)
+* M-x magit-unstage-file: Staging from file-visiting buffers.
+ (line 18)
+* M-x magit-version: Git executable. (line 17)
+* M-x magit-wip-commit: Wip modes. (line 129)
+* n: Section movement. (line 16)
+* n <1>: Blaming. (line 54)
+* N: Blaming. (line 58)
+* n <2>: Editing rebase sequences.
+ (line 39)
+* n <3>: Minor mode for buffers visiting blobs.
+ (line 16)
+* o: Submodule popup. (line 6)
+* O: Subtree. (line 8)
+* o a: Submodule popup. (line 11)
+* O a: Subtree. (line 20)
+* o b: Submodule popup. (line 17)
+* O c: Subtree. (line 24)
+* o f: Submodule popup. (line 35)
+* O f: Subtree. (line 32)
+* o i: Submodule popup. (line 22)
+* o i <1>: Submodule popup. (line 39)
+* O m: Subtree. (line 28)
+* O p: Subtree. (line 36)
+* o s: Submodule popup. (line 31)
+* O s: Subtree. (line 41)
+* o u: Submodule popup. (line 26)
+* p: Section movement. (line 10)
+* p <1>: Blaming. (line 62)
+* P: Blaming. (line 66)
+* p <2>: Editing rebase sequences.
+ (line 35)
+* P <1>: Pushing. (line 11)
+* p <3>: Minor mode for buffers visiting blobs.
+ (line 12)
+* P e: Pushing. (line 35)
+* P m: Pushing. (line 53)
+* P o: Pushing. (line 39)
+* P p: Pushing. (line 16)
+* P r: Pushing. (line 44)
+* P t: Pushing. (line 59)
+* P T: Pushing. (line 65)
+* P u: Pushing. (line 26)
+* q: Quitting Windows. (line 6)
+* q <1>: Log Buffer. (line 12)
+* q <2>: Blaming. (line 70)
+* q <3>: Minor mode for buffers visiting blobs.
+ (line 20)
+* r: Rebasing. (line 9)
+* r <1>: Editing rebase sequences.
+ (line 51)
+* r a: Rebasing. (line 96)
+* r e: Rebasing. (line 34)
+* r e <1>: Rebasing. (line 92)
+* r f: Rebasing. (line 66)
+* r i: Rebasing. (line 62)
+* r m: Rebasing. (line 70)
+* r o: Rebasing. (line 40)
+* r p: Rebasing. (line 25)
+* r r: Rebasing. (line 81)
+* r s: Rebasing. (line 88)
+* r u: Rebasing. (line 30)
+* r w: Rebasing. (line 74)
+* RET: Diff buffer. (line 6)
+* RET <1>: References buffer. (line 99)
+* RET <2>: Blaming. (line 29)
+* RET <3>: Editing rebase sequences.
+ (line 16)
+* s: Staging and unstaging.
+ (line 29)
+* S: Staging and unstaging.
+ (line 37)
+* s <1>: Editing rebase sequences.
+ (line 59)
+* S-<tab>: Section visibility. (line 22)
+* SPC: Log Buffer. (line 33)
+* SPC <1>: Diff buffer. (line 59)
+* SPC <2>: Blaming. (line 34)
+* SPC <3>: Editing rebase sequences.
+ (line 21)
+* t: Blaming. (line 82)
+* t <1>: Tagging. (line 8)
+* T: Notes. (line 8)
+* T a: Notes. (line 70)
+* T c: Notes. (line 65)
+* t k: Tagging. (line 18)
+* T m: Notes. (line 56)
+* t p: Tagging. (line 24)
+* T p: Notes. (line 29)
+* T r: Notes. (line 21)
+* T s: Notes. (line 33)
+* T S: Notes. (line 44)
+* t t: Tagging. (line 13)
+* T T: Notes. (line 13)
+* TAB: Section visibility. (line 9)
+* u: Staging and unstaging.
+ (line 44)
+* U: Staging and unstaging.
+ (line 53)
+* v: Applying. (line 44)
+* V: Reverting. (line 6)
+* V A: Reverting. (line 30)
+* V a: Reverting. (line 38)
+* V s: Reverting. (line 34)
+* V V: Reverting. (line 14)
+* V v: Reverting. (line 20)
+* W: Creating and sending patches.
+ (line 6)
+* w: Applying patches. (line 8)
+* w a: Applying patches. (line 31)
+* w m: Applying patches. (line 19)
+* W p: Creating and sending patches.
+ (line 11)
+* W r: Creating and sending patches.
+ (line 17)
+* w s: Applying patches. (line 27)
+* w w: Applying patches. (line 13)
+* w w <1>: Applying patches. (line 23)
+* x: Editing rebase sequences.
+ (line 76)
+* x <1>: Resetting. (line 8)
+* Y: Logging. (line 62)
+* y: References buffer. (line 6)
+* y <1>: Editing rebase sequences.
+ (line 85)
+* y c: References buffer. (line 19)
+* y o: References buffer. (line 24)
+* y y: References buffer. (line 14)
+* z: Stashing. (line 8)
+* z a: Stashing. (line 58)
+* z b: Stashing. (line 84)
+* z f: Stashing. (line 88)
+* z i: Stashing. (line 20)
+* z I: Stashing. (line 46)
+* z k: Stashing. (line 71)
+* z l: Stashing. (line 76)
+* z p: Stashing. (line 64)
+* z v: Stashing. (line 80)
+* z w: Stashing. (line 25)
+* z W: Stashing. (line 51)
+* z x: Stashing. (line 32)
+* z z: Stashing. (line 13)
+* z Z: Stashing. (line 39)
+
--- /dev/null
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+\1f
+File: dir, Node: Top This is the top of the INFO tree
+
+ This (the Directory node) gives a menu of major topics.
+ Typing "q" exits, "?" lists all Info commands, "d" returns here,
+ "h" gives a primer for first-timers,
+ "mEmacs<Return>" visits the Emacs manual, etc.
+
+ In Emacs, you can click mouse button 2 on a menu item or cross reference
+ to select it.
+
+* Menu:
+
+Emacs
+* Magit-Popup: (magit-popup). Infix arguments with feedback.
--- /dev/null
+;;; magit-popup-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+\f
+;;;### (autoloads nil nil ("magit-popup-pkg.el" "magit-popup.el")
+;;;;;; (22576 8240 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; magit-popup-autoloads.el ends here
--- /dev/null
+(define-package "magit-popup" "20161009.1506" "Define prefix-infix-suffix command combos"
+ '((emacs "24.4")
+ (async "20160711.223")
+ (dash "20160820.501"))
+ :url "https://github.com/magit/magit" :keywords
+ '("bindings"))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; magit-popup.el --- Define prefix-infix-suffix command combos -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; This library was inspired by and replaces library `magit-key-mode',
+;; which was written by Phil Jackson <philNOSPAMshellarchive.co.uk> and is
+;; distributed under the GNU General Public License version 3 or later.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Package-Requires: ((emacs "24.4") (async "20160711.223") (dash "20160820.501"))
+;; Keywords: bindings
+;; Homepage: https://github.com/magit/magit
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements a generic interface for toggling switches
+;; and setting options and then invoking an Emacs command which does
+;; something with these arguments. The prototypical use is for the
+;; command to call an external process, passing on the arguments as
+;; command line arguments. But this is only one of many possible
+;; uses (though the one this library is optimized for).
+
+;; With the Emacs concept of "prefix arguments" in mind this could be
+;; described as "infix arguments with feedback in a buffer".
+
+;; Commands that set the prefix argument for the subsequent command do
+;; not limit what that next command could be. But entering a command
+;; console popup does limit the selection to the commands defined for
+;; that popup, and so we use the term "infix" instead of "prefix".
+
+;;; Code:
+
+(require 'button)
+(require 'cl-lib)
+(require 'dash)
+(require 'format-spec)
+
+(and (require 'async-bytecomp nil t)
+ (memq 'magit (bound-and-true-p async-bytecomp-allowed-packages))
+ (fboundp 'async-bytecomp-package-mode)
+ (async-bytecomp-package-mode 1))
+
+(declare-function info 'info)
+(declare-function Man-find-section 'man)
+(declare-function Man-next-section 'man)
+
+;; For the `:variable' event type.
+(declare-function magit-git-string 'magit-git)
+(declare-function magit-refresh 'magit-mode)
+(declare-function magit-get 'magit-git)
+(declare-function magit-set 'magit-git)
+
+;; For branch actions.
+(declare-function magit-branch-set-face 'magit-git)
+
+;;; Settings
+;;;; Custom Groups
+
+(defgroup magit-popup nil
+ "Infix arguments with a popup as feedback."
+ :group 'bindings)
+
+(defgroup magit-popup-faces nil
+ "Faces used by Magit-Popup."
+ :group 'magit-popup)
+
+;;;; Custom Options
+
+(defcustom magit-popup-display-buffer-action '((display-buffer-below-selected))
+ "The action used to display a popup buffer.
+
+Popup buffers are displayed using `display-buffer' with the value
+of this option as ACTION argument. You can also set this to nil
+and instead add an entry to `display-buffer-alist'."
+ :package-version '(magit-popup . "2.4.0")
+ :group 'magit-popup
+ :type 'sexp)
+
+(defcustom magit-popup-manpage-package
+ (if (memq system-type '(windows-nt ms-dos)) 'woman 'man)
+ "The package used to display manpages.
+One of `man' or `woman'."
+ :group 'magit-popup
+ :type '(choice (const man) (const woman)))
+
+(defcustom magit-popup-show-help-echo t
+ "Show usage information in the echo area."
+ :group 'magit-popup
+ :type 'boolean)
+
+(defcustom magit-popup-show-common-commands t
+ "Initially show section with commands common to all popups.
+This section can also be toggled temporarily using \
+\\<magit-popup-mode-map>\\[magit-popup-toggle-show-common-commands]."
+ :group 'magit-popup
+ :type 'boolean)
+
+(defcustom magit-popup-use-prefix-argument 'disabled
+ "Control how prefix arguments affect infix argument popups.
+
+This option controls the effect that the use of a prefix argument
+before entering a popup has. The *intended* default is `default',
+but the *actual* default is `disabled'. This is necessary because
+the old popup implementation did simply forward such a pre-popup
+prefix argument to the action invoked from the popup, and changing
+that without users being aware of it could lead to tears.
+
+`disabled' Bring up a Custom option buffer so that the user reads
+ this and then makes an informed choice.
+
+`default' With a prefix argument directly invoke the popup's
+ default action (an Emacs command), instead of bringing
+ up the popup.
+
+`popup' With a prefix argument bring up the popup, otherwise
+ directly invoke the popup's default action.
+
+`nil' Ignore prefix arguments."
+ :group 'magit-popup
+ :type '(choice
+ (const :tag "Call default action instead of showing popup" default)
+ (const :tag "Show popup instead of calling default action" popup)
+ (const :tag "Ignore prefix argument" nil)
+ (const :tag "Abort and show usage information" disabled)))
+
+;;;; Custom Faces
+
+(defface magit-popup-heading
+ '((t :inherit font-lock-keyword-face))
+ "Face for key mode header lines."
+ :group 'magit-popup-faces)
+
+(defface magit-popup-key
+ '((t :inherit font-lock-builtin-face))
+ "Face for key mode buttons."
+ :group 'magit-popup-faces)
+
+(defface magit-popup-argument
+ '((t :inherit font-lock-warning-face))
+ "Face used to display enabled arguments in popups."
+ :group 'magit-popup-faces)
+
+(defface magit-popup-disabled-argument
+ '((t :inherit shadow))
+ "Face used to display disabled arguments in popups."
+ :group 'magit-popup-faces)
+
+(defface magit-popup-option-value
+ '((t :inherit font-lock-string-face))
+ "Face used to display option values in popups."
+ :group 'magit-popup-faces)
+
+;;;; Keymap
+
+(defvar magit-popup-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap self-insert-command] 'magit-invoke-popup-action)
+ (define-key map [?- t] 'magit-invoke-popup-switch)
+ (define-key map [?= t] 'magit-invoke-popup-option)
+ (define-key map [?\C-c ?\C-c] 'magit-popup-set-default-arguments)
+ (define-key map [?\C-x ?\C-s] 'magit-popup-save-default-arguments)
+ (define-key map [?\C-g] 'magit-popup-quit)
+ (define-key map [??] 'magit-popup-help)
+ (define-key map [?\C-h ?k] 'magit-popup-help)
+ (define-key map [?\C-h ?i] 'magit-popup-info)
+ (define-key map [?\C-t] 'magit-popup-toggle-show-common-commands)
+ (define-key map [?\d] 'backward-button)
+ (define-key map [?\C-p] 'backward-button)
+ (define-key map [?\t] 'forward-button)
+ (define-key map [?\C-n] 'forward-button)
+ (define-key map [?\r] 'push-button)
+ map)
+ "Keymap for `magit-popup-mode'.
+
+\\<magit-popup-mode-map>\
+This keymap contains bindings common to all popups. A section
+listing these commands can be shown or hidden using \
+\\[magit-popup-toggle-show-common-commands].
+
+The prefix used to toggle any switch can be changed by binding
+another key to `magit-invoke-popup-switch'. Likewise binding
+another key to `magit-invoke-popup-option' changes the prefixed
+used to set any option. The two prefixes have to be different.
+If you change these bindings you should also change the `prefix'
+property of the button types `magit-popup-switch-button' and
+`magit-popup-option-button'.
+
+If you change any other binding, then you might have to also edit
+`magit-popup-common-commands' for things to align correctly in
+the section listing these commands.
+
+Never bind an alphabetic character in this keymap or you might
+make it impossible to invoke certain actions.")
+
+(defvar magit-popup-common-commands
+ '(("Set defaults" magit-popup-set-default-arguments)
+ ("View popup manual" magit-popup-info)
+ ("Toggle this section" magit-popup-toggle-show-common-commands)
+ ("Save defaults" magit-popup-save-default-arguments)
+ (" Popup help prefix" magit-popup-help)
+ ("Abort" magit-popup-quit)))
+
+;;;; Buttons
+
+(define-button-type 'magit-popup-button
+ 'face nil
+ 'action (lambda (button)
+ (funcall (button-get button 'function)
+ (button-get button 'event))))
+
+(define-button-type 'magit-popup-switch-button
+ 'supertype 'magit-popup-button
+ 'function 'magit-invoke-popup-switch
+ 'property :switches
+ 'heading "Switches\n"
+ 'formatter 'magit-popup-format-argument-button
+ 'format " %k %d (%a)"
+ 'prefix ?-
+ 'maxcols 1)
+
+(define-button-type 'magit-popup-option-button
+ 'supertype 'magit-popup-button
+ 'function 'magit-invoke-popup-option
+ 'property :options
+ 'heading "Options\n"
+ 'formatter 'magit-popup-format-argument-button
+ 'format " %k %d (%a%v)"
+ 'prefix ?=
+ 'maxcols 1)
+
+(define-button-type 'magit-popup-variable-button
+ 'supertype 'magit-popup-button
+ 'function 'magit-invoke-popup-action
+ 'property :variables
+ 'heading "Variables\n"
+ 'formatter 'magit-popup-format-variable-button
+ 'format " %k %d"
+ 'prefix nil
+ 'maxcols 1)
+
+(define-button-type 'magit-popup-action-button
+ 'supertype 'magit-popup-button
+ 'function 'magit-invoke-popup-action
+ 'property :actions
+ 'heading "Actions\n"
+ 'formatter 'magit-popup-format-action-button
+ 'format " %k %d"
+ 'prefix nil
+ 'maxcols :max-action-columns)
+
+(define-button-type 'magit-popup-command-button
+ 'supertype 'magit-popup-action-button
+ 'formatter 'magit-popup-format-command-button
+ 'action (lambda (button)
+ (let ((command (button-get button 'function)))
+ (unless (eq command 'push-button)
+ (call-interactively command)))))
+
+(define-button-type 'magit-popup-internal-command-button
+ 'supertype 'magit-popup-command-button
+ 'heading "Common Commands\n"
+ 'maxcols 3)
+
+;;; Events
+
+(defvar-local magit-this-popup nil
+ "The popup which is currently active.
+This is intended for internal use only.
+Don't confuse this with `magit-current-popup'.")
+
+(defvar-local magit-this-popup-events nil
+ "The events known to the active popup.
+This is intended for internal use only.
+Don't confuse this with `magit-current-popup-args'.")
+
+(defvar-local magit-previous-popup nil)
+
+(defun magit-popup-get (prop)
+ "While a popup is active, get the value of PROP."
+ (if (memq prop '(:switches :options :variables :actions))
+ (plist-get magit-this-popup-events prop)
+ (plist-get (symbol-value magit-this-popup) prop)))
+
+(defun magit-popup-put (prop val)
+ "While a popup is active, set the value of PROP to VAL."
+ (if (memq prop '(:switches :options :variables :actions))
+ (setq magit-this-popup-events
+ (plist-put magit-this-popup-events prop val))
+ (error "Property %s isn't supported" prop)))
+
+(defvar magit-current-popup nil
+ "The popup from which this editing command was invoked.
+
+Use this inside the `interactive' form of a popup aware command
+to determine whether it was invoked from a popup and if so from
+which popup. If the current command was invoked without the use
+of a popup then this is nil.")
+
+(defvar magit-current-popup-action nil
+ "The popup action now being executed.")
+
+(defvar magit-current-popup-args nil
+ "The value of the popup arguments for this editing command.
+
+If the current command was invoked from a popup, then this is
+a list of strings of all the set switches and options. This
+includes arguments which are set by default not only those
+explicitly set during this invocation.
+
+When the value is nil, then that can be because no argument is
+set, or because the current command wasn't invoked from a popup;
+consult `magit-current-popup' to tell the difference.
+
+Generally it is better to use `NAME-arguments', which is created
+by `magit-define-popup', instead of this variable or the function
+by the same name, because `NAME-argument' uses the default value
+for the arguments when the editing command is invoked directly
+instead of from a popup. When the command is bound in several
+popups that might not be feasible though.")
+
+(defun magit-current-popup-args (&rest filter)
+ "Return the value of the popup arguments for this editing command.
+
+The value is the same as that of the variable by the same name
+\(which see), except that FILTER is applied. FILTER is a list
+of regexps; only arguments that match one of them are returned.
+The first element of FILTER may also be `:not' in which case
+only arguments that don't match any of the regexps are returned,
+or `:only' which doesn't change the behaviour."
+ (let ((-compare-fn (lambda (a b) (magit-popup-arg-match b a))))
+ (-filter (if (eq (car filter) :not)
+ (lambda (arg) (not (-contains? (cdr filter) arg)))
+ (when (eq (car filter) :only)
+ (pop filter))
+ (lambda (arg) (-contains? filter arg)))
+ magit-current-popup-args)))
+
+(defun magit-popup-arg-match (pattern string)
+ (if (or (string-match-p "=$" pattern)
+ (string-match-p "^-[A-Z]$" pattern))
+ (string-match (format "^%s\\(.*\\)$" pattern) string)
+ (string-equal string pattern)))
+
+(cl-defstruct magit-popup-event key dsc arg fun use val)
+
+(defun magit-popup-event-keydsc (ev)
+ (let ((key (magit-popup-event-key ev)))
+ (key-description (if (vectorp key) key (vector key)))))
+
+(defun magit-popup-lookup (event type)
+ (--first (equal (magit-popup-event-key it) event)
+ (-filter 'magit-popup-event-p (magit-popup-get type))))
+
+(defun magit-popup-get-args ()
+ (--mapcat (when (and (magit-popup-event-p it)
+ (magit-popup-event-use it))
+ (list (format "%s%s"
+ (magit-popup-event-arg it)
+ (or (magit-popup-event-val it) ""))))
+ (append (magit-popup-get :switches)
+ (magit-popup-get :options))))
+
+(defmacro magit-popup-convert-events (def form)
+ (declare (indent 1) (debug (form form)))
+ `(--map (if (or (null it) (stringp it) (functionp it)) it ,form) ,def))
+
+(defun magit-popup-convert-switches (val def)
+ (magit-popup-convert-events def
+ (let ((a (nth 2 it)))
+ (make-magit-popup-event
+ :key (car it) :dsc (cadr it) :arg a
+ :use (and (member a val) t)))))
+
+(defun magit-popup-convert-options (val def)
+ (magit-popup-convert-events def
+ (let* ((a (nth 2 it))
+ (r (format "^%s\\(.*\\)" a))
+ (v (--first (string-match r it) val)))
+ (make-magit-popup-event
+ :key (car it) :dsc (cadr it) :arg a
+ :use (and v t) :val (and v (match-string 1 v))
+ :fun (or (nth 3 it) 'read-from-minibuffer)))))
+
+(defun magit-popup-convert-variables (_val def)
+ (magit-popup-convert-events def
+ (make-magit-popup-event
+ :key (car it) :dsc (cadr it) :fun (nth 2 it) :arg (nth 3 it))))
+
+(defun magit-popup-convert-actions (_val def)
+ (magit-popup-convert-events def
+ (make-magit-popup-event
+ :key (car it) :dsc (cadr it) :fun (nth 2 it))))
+
+;;; Define
+
+(defmacro magit-define-popup (name doc &rest args)
+ "Define a popup command named NAME.
+
+NAME should begin with the package prefix and by convention end
+with `-popup'. That name is used for the actual command as well
+as for a variable used internally. DOC is used as the doc-string
+of that command.
+
+Also define an option and a function named `SHORTNAME-arguments',
+where SHORTNAME is NAME with the trailing `-popup' removed. The
+name of this option and this function can be overwritten using
+the optional argument OPTION, but that is rarely advisable. As a
+special case if OPTION is specified but nil, do not define this
+option and this function at all.
+
+The option `SHORTNAME-arguments' holds the default value for the
+popup arguments. It can be customized from within the popup or
+using the Custom interface.
+
+The function `SHORTNAME-arguments' is a wrapper around the
+variable `magit-current-popup-args', both of which are intended
+to be used inside the `interactive' form of commands commonly
+invoked from the popup `NAME'. When such a command is invoked
+from that popup, then the function `SHORTNAME-arguments' returns
+the value of the variable `magit-current-popup-args'; however
+when the command is invoked directly, then it returns the default
+value of the variable `SHORTNAME-arguments'.
+
+Optional argument GROUP specifies the Custom group in which the
+option is placed. If omitted then the option is placed in some
+group the same way it is done when directly using `defcustom'.
+
+Optional argument MODE is deprecated, instead use the keyword
+arguments `:setup-function' and/or `:refresh-function'. If MODE
+is non-nil, then it specifies the mode used by the popup buffer,
+instead of the default, which is `magit-popup-mode'.
+
+The remaining arguments should have the form
+
+ [KEYWORD VALUE]...
+
+The following keywords are meaningful (and by convention are
+usually specified in that order):
+
+`:actions'
+ The actions which can be invoked from the popup. VALUE is a
+ list whose members have the form (KEY DESC COMMAND), see
+ `magit-define-popup-action' for details.
+
+ Actions are regular Emacs commands, which usually have an
+ `interactive' form setup to consume the values of the popup
+ `:switches' and `:options' when invoked from the corresponding
+ popup, else when invoked as the default action or directly
+ without using the popup, the default value of the variable
+ `SHORTNAME-arguments'. This is usually done by calling the
+ function `SHORTNAME-arguments'.
+
+ Members of VALUE may also be strings, assuming the first member
+ is also a string. Instead of just one action section with the
+ heading \"Actions\", multiple sections are then inserted into
+ the popup buffer, using these strings as headings.
+
+ Members of VALUE may also be nil. This should only be used
+ together with `:max-action-columns' and allows having gaps in
+ the action grid, which can help arranging actions sensibly.
+
+`:default-action'
+ The default action of the popup which is used directly instead
+ of displaying the popup buffer, when the popup is invoked with
+ a prefix argument. Also see `magit-popup-use-prefix-argument'
+ and `:use-prefix', which can be used to inverse the meaning of
+ the prefix argument.
+
+`:use-prefix'
+ Controls when to display the popup buffer and when to invoke
+ the default action (if any) directly. This overrides the
+ global default set using `magit-popup-use-prefix-argument'.
+ The value, if specified, should be one of `default' or `popup'.
+
+`:max-action-columns'
+ The maximum number of actions to display on a single line.
+ This helps arranging actions more sensibly. If there is not
+ enough room to display that many actions on one line, then
+ this is ignored.
+
+`:switches'
+ The popup arguments which can be toggled on and off. VALUE
+ is a list whose members have the form (KEY DESC SWITCH), see
+ `magit-define-popup-switch' for details.
+
+`:options'
+ The popup arguments which take a value, as in \"--opt=OPTVAL\".
+ VALUE is a list whose members have the form (KEY DESC OPTION
+ READER), see `magit-define-popup-option' for details.
+
+`:default-arguments'
+ The default arguments, a list of switches (which are then
+ enabled by default) and options with there default values, as
+ in \"--OPT=OPTVAL\".
+
+`:sequence-predicate'
+ When this function returns non-nil, then the popup uses
+ `:sequence-actions' instead of `:actions', and does not show
+ the `:switches' and `:options'.
+
+`:sequence-actions'
+ The actions which can be invoked from the popup, when
+ `:sequence-predicate' returns non-nil.
+
+`:setup-function'
+ When this function is specified, then it is used instead of
+ `magit-popup-default-setup'.
+
+`:refresh-function'
+ When this function is specified, then it is used instead of
+ calling `magit-popup-insert-section' three times with symbols
+ `magit-popup-switch-button', `magit-popup-option-button', and
+ finally `magit-popup-action-button' as argument.
+
+`:man-page'
+ The name of the manpage to be displayed when the user requests
+ help for a switch or argument.
+
+\(fn NAME DOC [GROUP [MODE [OPTION]]] :KEYWORD VALUE...)"
+ (declare (indent defun) (doc-string 2))
+ (let* ((grp (unless (keywordp (car args)) (pop args)))
+ (mode (unless (keywordp (car args)) (pop args)))
+ (opt (symbol-name name))
+ (opt (if (keywordp (car args))
+ (intern (concat (if (string-suffix-p "-popup" opt)
+ (substring opt 0 -6)
+ opt)
+ "-arguments"))
+ (eval (pop args)))))
+ `(progn
+ (defun ,name (&optional arg) ,doc
+ (interactive "P")
+ (magit-invoke-popup ',name ,mode arg))
+ (defvar ,name
+ (list :variable ',opt ,@args))
+ (magit-define-popup-keys-deferred ',name)
+ ,@(when opt
+ `((defcustom ,opt (plist-get ,name :default-arguments)
+ ""
+ ,@(and grp (list :group grp))
+ :type '(repeat (string :tag "Argument")))
+ (defun ,opt ()
+ (if (eq magit-current-popup ',name)
+ magit-current-popup-args
+ ,opt))
+ (put ',opt 'definition-name ',name))))))
+
+(defun magit-define-popup-switch (popup key desc switch
+ &optional enable at prepend)
+ "In POPUP, define KEY as SWITCH.
+
+POPUP is a popup command defined using `magit-define-popup'.
+SWITCH is a string representing an argument that takes no value.
+KEY is a character representing the second event in the sequence
+of keystrokes used to toggle the argument. (The first event, the
+prefix, is shared among all switches, defaults to -, and can be
+changed in `magit-popup-mode-keymap').
+
+DESC is a string describing the purpose of the argument, it is
+displayed in the popup.
+
+If optional ENABLE is non-nil then the switch is on by default.
+
+SWITCH is inserted after all other switches already defined for
+POPUP, unless optional PREPEND is non-nil, in which case it is
+placed first. If optional AT is non-nil then it should be the
+KEY of another switch already defined for POPUP, the argument
+is then placed before or after AT, depending on PREPEND."
+ (declare (indent defun))
+ (magit-define-popup-key popup :switches key
+ (list desc switch enable) at prepend))
+
+(defun magit-define-popup-option (popup key desc option
+ &optional reader value at prepend)
+ "In POPUP, define KEY as OPTION.
+
+POPUP is a popup command defined using `magit-define-popup'.
+OPTION is a string representing an argument that takes a value.
+KEY is a character representing the second event in the sequence
+of keystrokes used to set the argument's value. (The first
+event, the prefix, is shared among all options, defaults to =,
+and can be changed in `magit-popup-mode-keymap').
+
+DESC is a string describing the purpose of the argument, it is
+displayed in the popup.
+
+If optional VALUE is non-nil then the option is on by default,
+and VALUE is its default value.
+
+OPTION is inserted after all other options already defined for
+POPUP, unless optional PREPEND is non-nil, in which case it is
+placed first. If optional AT is non-nil then it should be the
+KEY of another option already defined for POPUP, the argument
+is then placed before or after AT, depending on PREPEND."
+ (declare (indent defun))
+ (magit-define-popup-key popup :options key
+ (list desc option reader value) at prepend))
+
+(defun magit-define-popup-variable (popup key desc command formatter
+ &optional at prepend)
+ "In POPUP, define KEY as COMMAND.
+
+POPUP is a popup command defined using `magit-define-popup'.
+COMMAND is a command which calls `magit-popup-set-variable'.
+FORMATTER is a function which calls `magit-popup-format-variable'.
+These two functions have to be called with the same arguments.
+
+KEY is a character representing the event used interactively call
+the COMMAND.
+
+DESC is the variable or a representation thereof. It's not
+actually used for anything.
+
+COMMAND is inserted after all other commands already defined for
+POPUP, unless optional PREPEND is non-nil, in which case it is
+placed first. If optional AT is non-nil then it should be the
+KEY of another command already defined for POPUP, the command
+is then placed before or after AT, depending on PREPEND."
+ (declare (indent defun))
+ (magit-define-popup-key popup :variables key
+ (list desc command formatter) at prepend))
+
+(defun magit-define-popup-action (popup key desc command
+ &optional at prepend)
+ "In POPUP, define KEY as COMMAND.
+
+POPUP is a popup command defined using `magit-define-popup'.
+COMMAND can be any command but should usually consume the popup
+arguments in its `interactive' form.
+KEY is a character representing the event used invoke the action,
+i.e. to interactively call the COMMAND.
+
+DESC is a string describing the purpose of the action, it is
+displayed in the popup.
+
+COMMAND is inserted after all other commands already defined for
+POPUP, unless optional PREPEND is non-nil, in which case it is
+placed first. If optional AT is non-nil then it should be the
+KEY of another command already defined for POPUP, the command
+is then placed before or after AT, depending on PREPEND."
+ (declare (indent defun))
+ (magit-define-popup-key popup :actions key
+ (list desc command) at prepend))
+
+(defun magit-define-popup-sequence-action
+ (popup key desc command &optional at prepend)
+ "Like `magit-define-popup-action' but for `:sequence-action'."
+ (declare (indent defun))
+ (magit-define-popup-key popup :sequence-actions key
+ (list desc command) at prepend))
+
+(defconst magit-popup-type-plural-alist
+ '((:switch . :switches)
+ (:option . :options)
+ (:variable . :variables)
+ (:action . :actions)
+ (:sequence-action . :sequence-actions)))
+
+(defun magit-popup-pluralize-type (type)
+ (or (cdr (assq type magit-popup-type-plural-alist))
+ type))
+
+(defun magit-define-popup-key
+ (popup type key def &optional at prepend)
+ "In POPUP, define KEY as an action, switch, or option.
+It's better to use one of the specialized functions
+ `magit-define-popup-action',
+ `magit-define-popup-sequence-action',
+ `magit-define-popup-switch',
+ `magit-define-popup-option', or
+ `magit-define-popup-variable'."
+ (declare (indent defun))
+ (setq type (magit-popup-pluralize-type type))
+ (if (memq type '(:switches :options :variables :actions :sequence-actions))
+ (if (boundp popup)
+ (let* ((plist (symbol-value popup))
+ (value (plist-get plist type))
+ (elt (assoc key value)))
+ (if elt
+ (setcdr elt def)
+ (setq elt (cons key def)))
+ (if at
+ (when (setq at (cl-member at value :key 'car-safe :test 'equal))
+ (setq value (cl-delete key value :key 'car-safe :test 'equal))
+ (if prepend
+ (progn (push (car at) (cdr at))
+ (setcar at elt))
+ (push elt (cdr at))))
+ (setq value (cl-delete key value :key 'car-safe :test 'equal)))
+ (unless (assoc key value)
+ (setq value (if prepend
+ (cons elt value)
+ (append value (list elt)))))
+ (set popup (plist-put plist type value)))
+ (push (list type key def at prepend)
+ (get popup 'magit-popup-deferred)))
+ (error "Unknown popup event type: %s" type)))
+
+(defun magit-define-popup-keys-deferred (popup)
+ (dolist (args (get popup 'magit-popup-deferred))
+ (condition-case err
+ (apply #'magit-define-popup-key popup args)
+ ((debug error)
+ (display-warning 'magit (error-message-string err) :error))))
+ (put popup 'magit-popup-deferred nil))
+
+(defun magit-change-popup-key (popup type from to)
+ "In POPUP, bind TO to what FROM was bound to.
+TYPE is one of `:action', `:sequence-action', `:switch', or
+`:option'. Bind TO and unbind FROM, both are characters."
+ (--if-let (assoc from (plist-get (symbol-value popup)
+ (magit-popup-pluralize-type type)))
+ (setcar it to)
+ (message "magit-change-popup-key: FROM key %c is unbound" from)))
+
+(defun magit-remove-popup-key (popup type key)
+ "In POPUP, remove KEY's binding of TYPE.
+POPUP is a popup command defined using `magit-define-popup'.
+TYPE is one of `:action', `:sequence-action', `:switch', or
+`:option'. KEY is the character which is to be unbound."
+ (setq type (magit-popup-pluralize-type type))
+ (let* ((plist (symbol-value popup))
+ (alist (plist-get plist type))
+ (value (assoc key alist)))
+ (set popup (plist-put plist type (delete value alist)))))
+
+;;; Invoke
+
+(defvar-local magit-popup-previous-winconf nil)
+
+(defun magit-invoke-popup (popup mode arg)
+ (let* ((def (symbol-value popup))
+ (val (symbol-value (plist-get def :variable)))
+ (default (plist-get def :default-action))
+ (local (plist-get def :use-prefix))
+ (use-prefix (or local magit-popup-use-prefix-argument)))
+ (cond
+ ((and arg (eq magit-popup-use-prefix-argument 'disabled))
+ (customize-option-other-window 'magit-popup-use-prefix-argument)
+ (error (concat "The meaning of prefix arguments has changed. "
+ "Please explicitly enable their use again.")))
+ ((or (and (eq use-prefix 'default) arg)
+ (and (eq use-prefix 'popup) (not arg)))
+ (if default
+ (let ((magit-current-popup (list popup 'default))
+ (magit-current-popup-args
+ (let ((magit-this-popup popup)
+ (magit-this-popup-events nil))
+ (magit-popup-default-setup val def)
+ (magit-popup-get-args))))
+ (when (and arg (listp arg))
+ (setq current-prefix-arg (and (not (= (car arg) 4))
+ (list (/ (car arg) 4)))))
+ (call-interactively default))
+ (message "%s has no default action; showing popup instead." popup)
+ (magit-popup-mode-setup popup mode)))
+ ((memq use-prefix '(disabled default popup nil))
+ (magit-popup-mode-setup popup mode)
+ (when magit-popup-show-help-echo
+ (message (concat "Type C-h i to view popup manual, "
+ "? to describe an argument or action."))))
+ (local
+ (error "Invalid :use-prefix popup property value: %s" use-prefix))
+ (t
+ (error "Invalid magit-popup-use-prefix-argument value: %s" use-prefix)))))
+
+(defun magit-invoke-popup-switch (event)
+ (interactive (list last-command-event))
+ (--if-let (magit-popup-lookup event :switches)
+ (progn
+ (setf (magit-popup-event-use it)
+ (not (magit-popup-event-use it)))
+ (magit-refresh-popup-buffer))
+ (user-error "%c isn't bound to any switch" event)))
+
+(defun magit-invoke-popup-option (event)
+ (interactive (list last-command-event))
+ (--if-let (magit-popup-lookup event :options)
+ (progn
+ (if (magit-popup-event-use it)
+ (setf (magit-popup-event-use it) nil)
+ (let* ((arg (magit-popup-event-arg it))
+ (val (funcall
+ (magit-popup-event-fun it)
+ (concat arg (unless (string-match-p "=$" arg) ": "))
+ (magit-popup-event-val it))))
+ (setf (magit-popup-event-use it) t)
+ (setf (magit-popup-event-val it) val)))
+ (magit-refresh-popup-buffer))
+ (user-error "%c isn't bound to any option" event)))
+
+(defun magit-invoke-popup-action (event)
+ (interactive (list last-command-event))
+ (let ((action (magit-popup-lookup event :actions))
+ (variable (magit-popup-lookup event :variables)))
+ (when (and variable (not (magit-popup-event-arg variable)))
+ (setq action variable)
+ (setq variable nil))
+ (if (or action variable)
+ (let* ((magit-current-popup magit-this-popup)
+ (magit-current-popup-args (magit-popup-get-args))
+ (command (magit-popup-event-fun (or action variable)))
+ (magit-current-popup-action command))
+ (when action
+ (magit-popup-quit))
+ (call-interactively command)
+ (setq this-command command)
+ (unless action
+ (magit-refresh-popup-buffer)))
+ (if (eq event ?q)
+ (progn (magit-popup-quit)
+ (when magit-previous-popup
+ (magit-popup-mode-setup magit-previous-popup nil)))
+ (user-error "%c isn't bound to any action" event)))))
+
+(defun magit-popup-set-variable
+ (variable choices &optional default other)
+ (magit-set (--if-let (magit-git-string "config" "--local" variable)
+ (cadr (member it choices))
+ (car choices))
+ variable)
+ (magit-refresh)
+ (message "%s %s" variable
+ (magit-popup-format-variable-1 variable choices default other)))
+
+(defun magit-popup-quit ()
+ "Quit the current popup command without invoking an action."
+ (interactive)
+ (let ((winconf magit-popup-previous-winconf))
+ (if (derived-mode-p 'magit-popup-mode)
+ (kill-buffer)
+ (magit-popup-help-mode -1)
+ (kill-local-variable 'magit-popup-previous-winconf))
+ (when winconf
+ (set-window-configuration winconf))))
+
+(defun magit-popup-read-number (prompt &optional default)
+ "Like `read-number' but DEFAULT may be a numeric string."
+ (read-number prompt (if (stringp default)
+ (string-to-number default)
+ default)))
+
+;;; Save
+
+(defun magit-popup-set-default-arguments (arg)
+ "Set default value for the arguments for the current popup.
+Then close the popup without invoking an action; unless a prefix
+argument is used in which case the popup remains open.
+
+For a popup named `NAME-popup' that usually means setting the
+value of the custom option `NAME-arguments'."
+ (interactive "P")
+ (-if-let (var (magit-popup-get :variable))
+ (progn (customize-set-variable var (magit-popup-get-args))
+ (unless arg (magit-popup-quit)))
+ (user-error "Nothing to set")))
+
+(defun magit-popup-save-default-arguments (arg)
+ "Save default value for the arguments for the current popup.
+Then close the popup without invoking an action; unless a prefix
+argument is used in which case the popup remains open.
+
+For a popup named `NAME-popup' that usually means saving the
+value of the custom option `NAME-arguments'."
+ (interactive "P")
+ (-if-let (var (magit-popup-get :variable))
+ (progn (customize-save-variable var (magit-popup-get-args))
+ (unless arg (magit-popup-quit)))
+ (user-error "Nothing to save")))
+
+;;; Help
+
+(defun magit-popup-toggle-show-common-commands ()
+ "Show or hide an additional section with common commands.
+The commands listed in this section are common to all popups
+and are defined in `magit-popup-mode-map' (which see)."
+ (interactive)
+ (setq magit-popup-show-common-commands
+ (not magit-popup-show-common-commands))
+ (magit-refresh-popup-buffer)
+ (fit-window-to-buffer))
+
+(defun magit-popup-help ()
+ "Show help for the argument or action at point."
+ (interactive)
+ (let* ((man (magit-popup-get :man-page))
+ (key (read-key-sequence
+ (concat "Describe key" (and man " (? for manpage)") ": ")))
+ (int (aref key (1- (length key))))
+ (def (or (lookup-key (current-local-map) key t)
+ (lookup-key (current-global-map) key))))
+ (pcase def
+ (`magit-invoke-popup-switch
+ (magit-popup-manpage man (magit-popup-lookup int :switches)))
+ (`magit-invoke-popup-option
+ (magit-popup-manpage man (magit-popup-lookup int :options)))
+ (`magit-popup-help
+ (magit-popup-manpage man nil))
+ ((or `self-insert-command
+ `magit-invoke-popup-action)
+ (setq def (or (magit-popup-lookup int :actions)
+ (magit-popup-lookup int :variables)))
+ (if def
+ (magit-popup-describe-function (magit-popup-event-fun def))
+ (ding)
+ (message nil)))
+ (`nil (ding)
+ (message nil))
+ (_ (magit-popup-describe-function def)))))
+
+(defun magit-popup-manpage (topic arg)
+ (unless topic
+ (user-error "No man page associated with %s"
+ (magit-popup-get :man-page)))
+ (when arg
+ (setq arg (magit-popup-event-arg arg)))
+ (let ((winconf (current-window-configuration)) buffer)
+ (pcase magit-popup-manpage-package
+ (`woman (delete-other-windows)
+ (split-window-below)
+ (with-no-warnings ; display-buffer-function is obsolete
+ (let ((display-buffer-alist nil)
+ (display-buffer-function nil))
+ (woman topic)))
+ (setq buffer (current-buffer)))
+ (`man (cl-letf (((symbol-function #'fboundp) (lambda (_) nil)))
+ (setq buffer (man topic)))
+ (delete-other-windows)
+ (split-window-below)
+ (set-window-buffer (selected-window) buffer)))
+ (with-current-buffer buffer
+ (setq magit-popup-previous-winconf winconf)
+ (magit-popup-help-mode)
+ (fit-window-to-buffer (next-window))
+ (if (and arg
+ (Man-find-section "OPTIONS")
+ (re-search-forward (format "^[\t\s]+\\(-., \\)*?%s[=\n]" arg)
+ (save-excursion
+ (Man-next-section 1)
+ (point))
+ t))
+ (goto-char (1+ (match-beginning 0)))
+ (goto-char (point-min))))))
+
+(defun magit-popup-describe-function (function)
+ (let ((winconf (current-window-configuration)))
+ (delete-other-windows)
+ (split-window-below)
+ (other-window 1)
+ (with-no-warnings ; display-buffer-function is obsolete
+ (let ((display-buffer-alist '(("" display-buffer-use-some-window)))
+ (display-buffer-function nil))
+ (describe-function function)))
+ (fit-window-to-buffer)
+ (other-window 1)
+ (setq magit-popup-previous-winconf winconf)
+ (magit-popup-help-mode)))
+
+(defun magit-popup-info ()
+ "Show the popup manual."
+ (interactive)
+ (let ((winconf (current-window-configuration)))
+ (delete-other-windows)
+ (split-window-below)
+ (info "(magit-popup.info)Usage")
+ (magit-popup-help-mode)
+ (setq magit-popup-previous-winconf winconf))
+ (magit-popup-help-mode)
+ (fit-window-to-buffer (next-window)))
+
+(define-minor-mode magit-popup-help-mode
+ "Auxiliary minor mode used to restore previous window configuration.
+When some sort of help buffer is created from within a popup,
+then this minor mode is turned on in that buffer, so that when
+the user quits it, the previous window configuration is also
+restored."
+ :keymap '(([remap Man-quit] . magit-popup-quit)
+ ([remap Info-exit] . magit-popup-quit)
+ ([remap quit-window] . magit-popup-quit)))
+
+;;; Modes
+
+(define-derived-mode magit-popup-mode fundamental-mode "MagitPopup"
+ "Major mode for infix argument popups."
+ :mode 'magit-popup
+ (setq truncate-lines t)
+ (setq buffer-read-only t)
+ (setq-local scroll-margin 0)
+ (setq-local magit-popup-show-common-commands magit-popup-show-common-commands)
+ (hack-dir-local-variables-non-file-buffer))
+
+(put 'magit-popup-mode 'mode-class 'special)
+
+(defun magit-popup-default-setup (val def)
+ (if (--when-let (magit-popup-get :sequence-predicate)
+ (funcall it))
+ (magit-popup-put :actions (magit-popup-convert-actions
+ val (magit-popup-get :sequence-actions)))
+ (magit-popup-put :variables (magit-popup-convert-variables
+ val (plist-get def :variables)))
+ (magit-popup-put :switches (magit-popup-convert-switches
+ val (plist-get def :switches)))
+ (magit-popup-put :options (magit-popup-convert-options
+ val (plist-get def :options)))
+ (magit-popup-put :actions (magit-popup-convert-actions
+ val (plist-get def :actions)))))
+
+(defun magit-popup-mode-setup (popup mode)
+ (setq magit-previous-popup magit-current-popup)
+ (let ((val (symbol-value (plist-get (symbol-value popup) :variable)))
+ (def (symbol-value popup)))
+ (magit-popup-mode-display-buffer (get-buffer-create
+ (format "*%s*" popup))
+ (or mode 'magit-popup-mode))
+ (setq magit-this-popup popup)
+ (if (bound-and-true-p magit-popup-setup-hook) ; obsolete
+ (run-hook-with-args 'magit-popup-setup-hook val def)
+ (funcall (or (magit-popup-get :setup-function)
+ 'magit-popup-default-setup)
+ val def)))
+ (magit-refresh-popup-buffer)
+ (fit-window-to-buffer nil nil (line-number-at-pos (point-max))))
+
+(defun magit-popup-mode-display-buffer (buffer mode)
+ (let ((winconf (current-window-configuration)))
+ (select-window (display-buffer buffer magit-popup-display-buffer-action))
+ (funcall mode)
+ (setq magit-popup-previous-winconf winconf)))
+
+(defvar magit-refresh-popup-buffer-hook nil
+ "Hook run by `magit-refresh-popup-buffer'.
+
+The hook is run right after inserting the representation of the
+popup events but before optionally inserting the representation
+of events shared by all popups and before point is adjusted.")
+
+(defun magit-refresh-popup-buffer ()
+ (let* ((inhibit-read-only t)
+ (button (button-at (point)))
+ (prefix (and button (button-get button 'prefix)))
+ (event (and button (button-get button 'event))))
+ (erase-buffer)
+ (save-excursion
+ (--if-let (magit-popup-get :refresh-function)
+ (funcall it)
+ (magit-popup-insert-section 'magit-popup-switch-button)
+ (magit-popup-insert-section 'magit-popup-option-button)
+ (magit-popup-insert-section 'magit-popup-variable-button)
+ (magit-popup-insert-section 'magit-popup-action-button))
+ (run-hooks 'magit-refresh-popup-buffer-hook)
+ (when magit-popup-show-common-commands
+ (magit-popup-insert-command-section
+ 'magit-popup-internal-command-button
+ magit-popup-common-commands)))
+ (set-buffer-modified-p nil)
+ (when event
+ (while (and (ignore-errors (forward-button 1))
+ (let ((b (button-at (point))))
+ (or (not (equal (button-get b 'prefix) prefix))
+ (not (equal (button-get b 'event) event)))))))))
+
+;;; Draw
+
+(defvar magit-popup-min-padding 3
+ "Minimal amount of whitespace between columns in popup buffers.")
+
+(defun magit-popup-insert-section (type &optional spec heading)
+ (if (not spec)
+ (progn (setq spec (magit-popup-get (button-type-get type 'property)))
+ (when spec
+ (if (or (stringp (car spec))
+ (functionp (car spec)))
+ (--each (--partition-by-header
+ (or (stringp it) (functionp it))
+ spec)
+ (magit-popup-insert-section type (cdr it) (car it)))
+ (magit-popup-insert-section type spec))))
+ (let* ((formatter (button-type-get type 'formatter))
+ (items (mapcar (lambda (ev)
+ (and ev (or (funcall formatter type ev) '(""))))
+ (or spec (magit-popup-get
+ (button-type-get type 'property)))))
+ (maxcols (button-type-get type 'maxcols))
+ (pred (magit-popup-get :sequence-predicate)))
+ (if (and pred (funcall pred))
+ (setq maxcols nil)
+ (cl-typecase maxcols
+ (keyword (setq maxcols (magit-popup-get maxcols)))
+ (symbol (setq maxcols (symbol-value maxcols)))))
+ (when items
+ (if (functionp heading)
+ (when (setq heading (funcall heading))
+ (insert heading ?\n))
+ (unless heading
+ (setq heading (button-type-get type 'heading)))
+ (insert (propertize heading 'face 'magit-popup-heading))
+ (unless (string-match "\n$" heading)
+ (insert "\n")))
+ (when heading
+ (let ((colwidth
+ (+ (apply 'max (mapcar (lambda (e) (length (car e))) items))
+ magit-popup-min-padding)))
+ (dolist (item items)
+ (unless (bolp)
+ (let ((padding (- colwidth (% (current-column) colwidth))))
+ (if (and (< (+ (current-column) padding colwidth)
+ (window-width))
+ (< (ceiling (/ (current-column) (* colwidth 1.0)))
+ (or maxcols 1000)))
+ (insert (make-string padding ?\s))
+ (insert "\n"))))
+ (unless (equal item '(""))
+ (if item
+ (apply 'insert-button item)
+ (insert ?\s)))))
+ (insert (if (= (char-before) ?\n) "\n" "\n\n")))))))
+
+(defun magit-popup-format-argument-button (type ev)
+ (list (format-spec
+ (button-type-get type 'format)
+ `((?k . ,(propertize (concat
+ (--when-let (button-type-get type 'prefix)
+ (char-to-string it))
+ (magit-popup-event-keydsc ev))
+ 'face 'magit-popup-key))
+ (?d . ,(magit-popup-event-dsc ev))
+ (?a . ,(propertize (magit-popup-event-arg ev)
+ 'face (if (magit-popup-event-use ev)
+ 'magit-popup-argument
+ 'magit-popup-disabled-argument)))
+ (?v . ,(let ((val (magit-popup-event-val ev)))
+ (if (and (magit-popup-event-use ev)
+ (not (equal val "")))
+ (propertize (format "\"%s\"" val)
+ 'face 'magit-popup-option-value)
+ "")))))
+ 'type type 'event (magit-popup-event-key ev)))
+
+(defun magit-popup-format-variable-button (type ev)
+ (if (not (magit-popup-event-arg ev))
+ (magit-popup-format-action-button 'magit-popup-action-button ev)
+ (list (format-spec
+ (button-type-get type 'format)
+ `((?k . ,(propertize (magit-popup-event-keydsc ev)
+ 'face 'magit-popup-key))
+ (?d . ,(funcall (magit-popup-event-arg ev)))))
+ 'type type 'event (magit-popup-event-key ev))))
+
+(defun magit-popup-format-variable
+ (variable choices &optional default other width)
+ (concat variable
+ (if width (make-string (- width (length variable)) ?\s) " ")
+ (magit-popup-format-variable-1 variable choices default other)))
+
+(defun magit-popup-format-variable-1
+ (variable choices &optional default other)
+ "Print popup entry for git VARIABLE with possible CHOICES.
+DEFAULT is git's default choice for VARIABLE. OTHER is a git
+variable whose value may be used as a default."
+ (let ((local (magit-git-string "config" "--local" variable))
+ (global (magit-git-string "config" "--global" variable)))
+ (when other
+ (setq other (--when-let (magit-get other)
+ (concat other ":" it))))
+ (concat
+ (propertize "[" 'face 'magit-popup-disabled-argument)
+ (mapconcat
+ (lambda (choice)
+ (propertize choice 'face (if (equal choice local)
+ 'magit-popup-option-value
+ 'magit-popup-disabled-argument)))
+ choices
+ (propertize "|" 'face 'magit-popup-disabled-argument))
+ (when (or global other default)
+ (concat
+ (propertize "|" 'face 'magit-popup-disabled-argument)
+ (cond (global
+ (propertize (concat "global:" global)
+ 'face (cond (local
+ 'magit-popup-disabled-argument)
+ ((member global choices)
+ 'magit-popup-option-value)
+ (t
+ 'font-lock-warning-face))))
+ (other
+ (propertize other
+ 'face (if local
+ 'magit-popup-disabled-argument
+ 'magit-popup-option-value)))
+ (default
+ (propertize (concat "default:" default)
+ 'face (if local
+ 'magit-popup-disabled-argument
+ 'magit-popup-option-value))))))
+ (propertize "]" 'face 'magit-popup-disabled-argument))))
+
+(defun magit-popup-format-action-button (type ev)
+ (let* ((dsc (magit-popup-event-dsc ev))
+ (fun (and (functionp dsc) dsc)))
+ (when fun
+ (setq dsc
+ (-when-let (branch (funcall fun))
+ (if (next-single-property-change 0 'face (concat "0" branch))
+ branch
+ (magit-branch-set-face branch)))))
+ (when dsc
+ (list (format-spec
+ (button-type-get type 'format)
+ `((?k . ,(propertize (magit-popup-event-keydsc ev)
+ 'face 'magit-popup-key))
+ (?d . ,dsc)
+ (?D . ,(if (and (not fun)
+ (eq (magit-popup-event-fun ev)
+ (magit-popup-get :default-action)))
+ (propertize dsc 'face 'bold)
+ dsc))))
+ 'type type 'event (magit-popup-event-key ev)))))
+
+(defun magit-popup-insert-command-section (type spec)
+ (magit-popup-insert-section
+ type (mapcar (lambda (elt)
+ (list (car (where-is-internal (cadr elt)
+ (current-local-map)))
+ (car elt)))
+ spec)))
+
+(defun magit-popup-format-command-button (type elt)
+ (nconc (magit-popup-format-action-button
+ type (make-magit-popup-event :key (car elt)
+ :dsc (cadr elt)))
+ (list 'function (lookup-key (current-local-map) (car elt)))))
+
+;;; Utilities
+
+(defun magit-popup-import-file-args (args files)
+ (if files
+ (cons (concat "-- " (mapconcat #'identity files ",")) args)
+ args))
+
+(defun magit-popup-export-file-args (args)
+ (let ((files (--first (string-prefix-p "-- " it) args)))
+ (when files
+ (setq args (remove files args)
+ files (split-string (substring files 3) ",")))
+ (list args files)))
+
+;;; magit-popup.el ends soon
+
+(defconst magit-popup-font-lock-keywords
+ (eval-when-compile
+ `((,(concat "(\\(magit-define-popup\\)\\_>"
+ "[ \t'\(]*"
+ "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
+ (1 'font-lock-keyword-face)
+ (2 'font-lock-function-name-face nil t)))))
+
+(font-lock-add-keywords 'emacs-lisp-mode magit-popup-font-lock-keywords)
+
+(provide 'magit-popup)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; magit-popup.el ends here
--- /dev/null
+This is magit-popup.info, produced by makeinfo version 5.2 from
+magit-popup.texi.
+
+Taking inspiration from regular prefix commands and prefix arguments,
+this library implements a similar abstraction; a new kind of prefix
+command that is associated with a specific set of infix arguments and
+suffix commands.
+
+ Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* Magit-Popup: (magit-popup). Infix arguments with feedback.
+END-INFO-DIR-ENTRY
+
+\1f
+File: magit-popup.info, Node: Top, Next: Introduction, Up: (dir)
+
+Magit-Popup User Manual
+***********************
+
+Taking inspiration from regular prefix commands and prefix arguments,
+this library implements a similar abstraction; a new kind of prefix
+command that is associated with a specific set of infix arguments and
+suffix commands.
+
+ Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+* Menu:
+
+* Introduction::
+* Usage::
+* Defining prefix and suffix commands::
+
+— The Detailed Node Listing —
+
+
+Usage
+
+* Customizing existing popups::
+* Other options::
+
+
+
+Defining prefix and suffix commands
+
+* Defining prefix commands::
+* Defining suffix commands::
+
+\1f
+File: magit-popup.info, Node: Introduction, Next: Usage, Prev: Top, Up: Top
+
+1 Introduction
+**************
+
+Taking inspiration from regular prefix commands and prefix arguments,
+this library implements a similar abstraction; a new kind of prefix
+command that is associated with a specific set of infix arguments and
+suffix commands.
+
+ Invoking such a prefix command displays a popup buffer which lists
+the associated infix arguments and suffix commands. In that buffer each
+argument is prefixes with the key sequence that can be used to toggle it
+or change its value. Likewise each suffix command is prefixed with the
+key used to invoke it. Such a popup buffer might look like this:
+
+,-----------------------------------------
+|Switches
+| -l Show graph (--graph)
+| -d Show refnames (--decorate)
+|
+|Options
+| =m Search messages (--grep="popup")
+| =p Search patches (-G)
+|
+|Action
+| l Show log for current branch
+| o Show log for another branch
+'-----------------------------------------
+
+ The user could then for example type ‘-l’ to toggle the ‘--graph’
+*switch* (when it is on then it is shown in green, otherwise in gray),
+or ‘=m’ to change the value of the *option* ‘--grep’.
+
+ Once all arguments are as desired one invokes a suffix command, which
+causes the popup buffer to disappears. The suffix command should then
+retrieve the infix arguments in its ‘interactive’ form like this is done
+for prefix arguments.
+
+ While such "prefix-infix-suffix" combos were inspired by regular
+prefix commands and prefix arguments, they are also quite different.
+This should illustrate the most basic differences:
+
+ • A regular prefix commands
+
+ /- command1
+ prefix --- command2
+ \- command3
+
+ • Prefix arguments
+
+ /- command1
+ C-u ... --- command2
+ \- well *any* command
+
+ • A Prefix-Infix-Suffix combo
+
+ /- argument1 -\ /- suffix1
+ prefix----- argument2 --+-- suffix2
+ ^ \- argument3 -/
+ | |
+ '--------'
+ (refresh buffer)
+
+ This library was written as a replacement for ‘magit-key-mode’ which
+was used in Magit releases before 2.1.0. It is used to implement all
+"popups" in the current Magit release but a future release will switch
+to yet another implementation.
+
+ This library does not depend on any other Magit libraries and it is
+distributed as a separate package, which makes it possible to use it in
+packages that are not related to Magit. But keep in mind that it will
+be deprecated eventually.
+
+\1f
+File: magit-popup.info, Node: Usage, Next: Defining prefix and suffix commands, Prev: Introduction, Up: Top
+
+2 Usage
+*******
+
+Every popup buffers created with a prefix command contains a section
+named "Actions" listing the available suffix commands. Most buffers
+also contain a "Switches" and/or an "Options" section which list the two
+types of infix arguments separately.
+
+ Switches are arguments that can be toggled on or off. When a switch
+is active then it is shown in color, when it is off then it is shown in
+gray (of course the details depend on the color theme in use).
+
+ Options are arguments that have a value. When an option has a value
+then that is shown after the option itself. Because for some options
+the empty string is a valid value, options are additionally colorized
+like switches to indicate whether they are active or not.
+
+ The events bound to suffix commands are always single alphabetic
+characters. The bindings for arguments are always two events long. For
+switches the first key is always ‘-’, for options it is always ‘=’. The
+second key is always an alphabetic character.
+
+ By default popup buffers also feature a section listing commands
+common to all popups. To avoid conflicts with suffix commands, the
+bindings of these common commands are not alphabetic characters. This
+section is shown by default so that documentation-resistant users get a
+chance to notice them.
+
+ -- User Option: magit-popup-show-common-commands
+
+ This option controls whether the section which lists the commands
+ that are common to all popups is initially show. We recommend you
+ set this to ‘nil’ - after you have memorized that it can be shown
+ on demand using ‘C-t’.
+
+‘C-t’ (‘magit-popup-toggle-show-common-commands’)
+
+ Show or hide the section listing the commands shared by all popups.
+
+‘C-g’ (‘magit-popup-quit’)
+
+ Quit popup buffer without invoking a suffix command.
+
+ Without further action, setting arguments only affects the next
+suffix command. Invoking the same prefix command again resets the
+arguments to their default value, but the defaults can be changed
+directly from the popup buffer itself. For a prefix command named
+‘NAME-popup’ the default values are stored as the value of the custom
+option named ‘NAME-arguments’. While this option can be customized
+using the Custom interface, it is better to do so directly from the
+popup buffer.
+
+‘C-c C-c’ (‘magit-popup-set-default-arguments’)
+
+ This sets the default value for the arguments for the current
+ popup.
+
+ Then the popup buffer is closed without invoking a suffix command;
+ unless a prefix argument is used in which case the popup remains
+ open.
+
+‘C-x C-s’ (‘magit-popup-save-default-arguments’)
+
+ This sets the default value for the arguments for the current popup
+ and saves it for future Emacs sessions.
+
+ Then the popup buffer is closed without invoking an action; unless
+ a prefix argument is used in which case the popup remains open.
+
+ It is also possible to add additional arguments and commands to an
+existing popup, but that cannot be done directly from the popup (or the
+Custom interface). See *note Customizing existing popups: Customizing
+existing popups.
+
+ Documentation about a popup’s arguments and commands can be shown
+directly from the popup.
+
+‘C-h i’ (‘magit-popup-info’)
+
+ Show this manual.
+
+‘?’ (‘magit-popup-help’)
+
+ This command reads a key sequence and then shows the documentation
+ of the argument or command that sequence is bound to. In other
+ words type the same keys that you would use to invoke the argument
+ or command, but prefix the sequence with ‘?’.
+
+ For suffix commands this shows the doc-string. For arguments this
+ command can only show something for popups that have an associated
+ man-page. If the man-page is set, then this command displays it in
+ a separate buffer and puts point on the entry about the argument in
+ question.
+
+ The buffer which is used to display the documentation is selected.
+ Simply press ‘q’ to leave that buffer and restore the old window
+ configuration.
+
+ While it isn’t very useful, it is possible to move around in a popup
+buffer using ‘C-p’ and ‘C-n’, and to invoke the argument or command at
+point using ‘RET’. But it is much more efficient to use the dedicated
+key bindings instead, so these commands are not listed in popup buffers
+along with the other common commands.
+
+* Menu:
+
+* Customizing existing popups::
+* Other options::
+
+\1f
+File: magit-popup.info, Node: Customizing existing popups, Next: Other options, Up: Usage
+
+2.1 Customizing existing popups
+===============================
+
+It is possible to define additional infix arguments and suffix commands
+to an existing popup using the following functions.
+
+ You can find some examples which use the below commands at
+<https://github.com/magit/magit/wiki/Additional-proposed-infix-arguments-and-suffix-commands>.
+
+ -- Function: magit-define-popup-switch popup key desc switch &optional
+ enable at prepend
+
+ In POPUP, define KEY as SWITCH.
+
+ POPUP is a popup command defined using ‘magit-define-popup’.
+ SWITCH is a string representing an argument that takes no value.
+ KEY is a character representing the second event in the sequence of
+ keystrokes used to toggle the argument. (The first event, the
+ prefix, is shared among all switches, defaults to ‘-’, and can be
+ changed in ‘magit-popup-mode-keymap’).
+
+ DESC is a string describing the purpose of the argument, it is
+ displayed in the popup.
+
+ If optional ENABLE is non-nil then the switch is on by default.
+
+ SWITCH is inserted after all other switches already defined for
+ POPUP, unless optional PREPEND is non-nil, in which case it is
+ placed first. If optional AT is non-nil then it should be the KEY
+ of another switch already defined for POPUP, the argument is then
+ placed before or after AT, depending on PREPEND.
+
+ -- Function: magit-define-popup-option popup key desc option &optional
+ reader value at prepend
+
+ In POPUP, define KEY as OPTION.
+
+ POPUP is a popup command defined using ‘magit-define-popup’.
+ OPTION is a string representing an argument that takes a value.
+ KEY is a character representing the second event in the sequence of
+ keystrokes used to set the argument’s value. (The first event, the
+ prefix, is shared among all options, defaults to ‘=’, and can be
+ changed in ‘magit-popup-mode-keymap’).
+
+ DESC is a string describing the purpose of the argument, it is
+ displayed in the popup.
+
+ If optional VALUE is non-nil then the option is on by default, and
+ VALUE is its default value.
+
+ OPTION is inserted after all other options already defined for
+ POPUP, unless optional PREPEND is non-nil, in which case it is
+ placed first. If optional AT is non-nil then it should be the KEY
+ of another option already defined for POPUP, the argument is then
+ placed before or after AT, depending on PREPEND.
+
+ -- Function: magit-define-popup-action popup key desc command &optional
+ at prepend
+
+ In POPUP, define KEY as COMMAND.
+
+ POPUP is a popup command defined using ‘magit-define-popup’.
+ COMMAND can be any command but should usually consume the popup
+ arguments in its ‘interactive’ form. KEY is a character
+ representing the event used invoke the action, i.e. to
+ interactively call the COMMAND.
+
+ DESC is a string describing the purpose of the action, it is
+ displayed in the popup.
+
+ COMMAND is inserted after all other commands already defined for
+ POPUP, unless optional PREPEND is non-nil, in which case it is
+ placed first. If optional AT is non-nil then it should be the KEY
+ of another command already defined for POPUP, the command is then
+ placed before or after AT, depending on PREPEND.
+
+ -- Function: magit-define-popup-sequence-action popup key desc command
+ &optional at prepend
+
+ Like ‘magit-define-popup-action’, but modifies the value of the
+ ‘:sequence-actions’ property instead of ‘:actions’.
+
+ -- Function: magit-define-popup-variable popup key desc command
+ formatter &optional at prepend
+
+ In POPUP, define KEY as COMMAND.
+
+ POPUP is a popup command defined using ‘magit-define-popup’.
+ COMMAND is a command which calls ‘magit-popup-set-variable’.
+ FORMATTER is a function which calls ‘magit-popup-format-variable’.
+ These two functions have to be called with the same arguments.
+
+ KEY is a character representing the event used interactively call
+ the COMMAND.
+
+ DESC is the variable or a representation thereof. It’s not
+ actually used for anything.
+
+ COMMAND is inserted after all other commands already defined for
+ POPUP, unless optional PREPEND is non-nil, in which case it is
+ placed first. If optional AT is non-nil then it should be the KEY
+ of another command already defined for POPUP, the command is then
+ placed before or after AT, depending on PREPEND."
+
+ -- Function: magit-change-popup-key popup type from to
+
+ In POPUP, bind TO to what FROM was bound to. TYPE is one of
+ ‘:action’, ‘:sequence-action’, ‘:switch’, or ‘:option’. Bind TO
+ and unbind FROM, both are characters.
+
+ -- Function: magit-remove-popup-key popup type key
+
+ In POPUP, remove KEY’s binding of TYPE. POPUP is a popup command
+ defined using ‘magit-define-popup’. TYPE is one of ‘:action’,
+ ‘:sequence-action’, ‘:switch’, or ‘:option’. KEY is the character
+ which is to be unbound.
+
+ It is also possible to change other aspects of a popup by setting a
+property using ‘plist-put’. See *note Defining prefix commands:
+Defining prefix commands. for valid properties. The most likely change
+Magit users might want to make is:
+
+ (plist-put magit-show-refs-popup :use-prefix nil)
+
+\1f
+File: magit-popup.info, Node: Other options, Prev: Customizing existing popups, Up: Usage
+
+2.2 Other options
+=================
+
+ -- User Option: magit-popup-use-prefix-argument
+
+ This option controls the effect that the use of a prefix argument
+ before entering a popup has. The *intended* default is ‘default’,
+ but the *actual* default is ‘disabled’. This is necessary because
+ the old popup implementation did simply forward such a pre-popup
+ prefix argument to the suffix command invoked from the popup, and
+ changing that without users being aware of it could lead to tears.
+
+ • ‘disabled’
+
+ Bring up a Custom option buffer so that the user reads this
+ and then makes an informed choice.
+
+ • ‘default’
+
+ With a prefix argument directly invoke the popup’s default
+ action (an Emacs command), instead of bringing up the popup.
+
+ • ‘popup’
+
+ With a prefix argument bring up the popup, otherwise directly
+ invoke the popup’s default action.
+
+ • ‘nil’
+
+ Ignore prefix arguments.
+ This option can be overridden for individual popups.
+ ‘magit-show-refs-popup’ for example defaults to invoking the
+ default action directly. It only shows the popup buffer when a
+ prefix argument is used. See *note Customizing existing popups:
+ Customizing existing popups.
+
+ -- User Option: magit-popup-manpage-package
+
+ The Emacs package used to display man-pages, one of ‘man’ or
+ ‘woman’.
+
+ -- User Option: magit-popup-display-buffer-action
+
+ The option controls how the window used to display a popup buffer
+ is created. Popup buffers are displayed using ‘display-buffer’
+ with the value of this option as ACTION argument. You can also set
+ this to nil and instead add an entry to ‘display-buffer-alist’.
+
+ To emphasize the default action by making it bold use this:
+
+ (button-type-put 'magit-popup-action-button 'format " %k %D")
+
+\1f
+File: magit-popup.info, Node: Defining prefix and suffix commands, Prev: Usage, Up: Top
+
+3 Defining prefix and suffix commands
+*************************************
+
+If you write an extension for Magit then you should use this library now
+and later when ‘transient’ is released port to that.
+
+ If you are considering using this library to define popups for
+packages not related to Magit, then keep in mind that it will be
+superseded eventually. Once ‘transient’ has been released I will only
+fix bugs in ‘magit-popup’ but not implement any new features.
+
+ Also consider using ‘hydra’ instead. To some extend ‘magit-popup’
+and ‘hydra’ are similar but have a different focus. The main purpose of
+‘magit-popup’ is to pass infix arguments to suffix commands. If all you
+need is a command dispatcher then you are better of using ‘hydra’. Of
+course ‘hydra’ may also be a better fit not only because of the features
+it lacks, but also because of the features it provides, which are in
+turn missing from ‘magit-popup’.
+
+ Here is an example of how one defines a prefix command along with its
+infix arguments, and then also one of its suffix commands.
+
+ ;;;###autoload (autoload 'magit-tag-popup "magit" nil t)
+ (magit-define-popup magit-tag-popup
+ "Show popup buffer featuring tagging commands."
+ 'magit-commands
+ :man-page "git-tag"
+ :switches '((?a "Annotate" "--annotate")
+ (?s "Sign" "--sign")
+ (?f "Force" "--force"))
+ :actions '((?t "Create" magit-tag)
+ (?k "Delete" magit-tag-delete)
+ (?p "Prune" magit-tag-prune))
+ :default-action 'magit-tag)
+
+ ;;;###autoload
+ (defun magit-tag (name rev &optional args)
+ "Create a new tag with the given NAME at REV."
+ (interactive (list (magit-read-tag "Tag name")
+ (magit-read-branch-or-commit "Place tag on")
+ (magit-tag-arguments)))
+ (magit-run-git-with-editor "tag" args name rev))
+
+* Menu:
+
+* Defining prefix commands::
+* Defining suffix commands::
+
+\1f
+File: magit-popup.info, Node: Defining prefix commands, Next: Defining suffix commands, Up: Defining prefix and suffix commands
+
+3.1 Defining prefix commands
+============================
+
+Prefix commands and their infix arguments are defined using the macro
+‘magit-define-popup’. The key bindings and descriptions of suffix
+commands are also defined using that macro, but the actual interactive
+commands have to be defined separately using plain ‘defun’.
+
+ -- Macro: magit-define-popup name doc [group [mode [option]]] :keyword
+ value…
+
+ This macro defines a popup named NAME. The NAME should begin with
+ the package prefix and by convention end with ‘-popup’, it is used
+ as the name of the command which shows the popup and for an
+ internal variable (whose value is used to store information about
+ the popup and should not be accessed directly). DOC is the
+ doc-string of the popup command.
+
+ This macro also defines an option and a function both named
+ ‘SHORTNAME-arguments’, where SHORTNAME is NAME with the trailing
+ ‘-popup’ removed. The name of this option and this function can be
+ overwritten using the optional argument OPTION, but that is rarely
+ advisable. As a special case if OPTION is specified but ‘nil’,
+ then this option and this function are not defined at all, which is
+ useful for popups that are used as simple dispatchers that offer no
+ arguments.
+
+ The option ‘SHORTNAME-arguments’ holds the value for the popup
+ arguments. It can be customized from within the popup or using the
+ Custom interface. It can also have a buffer local value in any
+ non-popup buffer. The local value for the buffer from which the
+ popup command was invoked, can be set from within the popup buffer.
+
+ The function ‘SHORTNAME-arguments’ returns the currently effective
+ value of the variable by the same name. See below for more
+ information.
+
+ The optional argument GROUP specifies the Custom group in which the
+ option is placed. If omitted then the option is placed in some
+ group the same way it is done when directly using ‘defcustom’ and
+ omitting the group.
+
+ The optional argument MODE specifies the mode used by the popup
+ buffer. If it is omitted or ‘nil’ then ‘magit-popup-mode’ is used.
+
+ The remaining arguments should have the form ‘[KEYWORD VALUE]...’.
+
+ The following keywords are meaningful (and by convention are
+ usually specified in that order):
+
+ • ‘:actions’
+
+ The actions which can be invoked from the popup. VALUE is a
+ list whose members have the form (KEY DESC COMMAND), see
+ ‘magit-define-popup-action’ for details.
+
+ How the actions are split into rows and columns currently
+ depends on the available space and ‘:max-action-columns’.
+
+ WARNING: This will likely be change to use a more explicit
+ format (((KEY DESC COMMAND)…)…) before the release.
+
+ Actions are regular Emacs commands, which usually have an
+ ‘interactive’ form setup to consume the values of the popup
+ ‘:switches’ and ‘:options’ when invoked from the corresponding
+ popup, else when invoked as the default action or directly
+ without using the popup, the default value of the variable
+ ‘SHORTNAME-arguments’. This is usually done by calling the
+ function ‘SHORTNAME-arguments’.
+
+ Members of VALUE may also be strings, assuming the first
+ member is also a string. Instead of just one action section
+ with the heading \"Actions\", multiple sections are then
+ inserted into the popup buffer, using these strings as
+ headings.
+
+ Members of VALUE may also be nil. This should only be used
+ together with ‘:max-action-columns’ and allows having gaps in
+ the action grit, which can help arranging actions sensibly.
+
+ • ‘:default-action’
+
+ The default action of the popup which is used directly instead
+ of displaying the popup buffer, when the popup is invoked with
+ a prefix argument. Also see ‘magit-popup-use-prefix-argument’
+ and ‘:use-prefix’, which can be used to inverse the meaning of
+ the prefix argument.
+
+ • ‘:use-prefix’
+
+ Controls when to display the popup buffer and when to invoke
+ the default action (if any) directly. This overrides the
+ global default set using ‘magit-popup-use-prefix-argument’.
+ The value, if specified, should be one of ‘default’ or
+ ‘prefix’.
+
+ • ‘:switches’
+
+ The popup arguments which can be toggled on and off. VALUE is
+ a list whose members have the form ‘(KEY DESC SWITCH)’, see
+ ‘magit-define-popup-switch’ for details.
+
+ • ‘:options’
+
+ The popup arguments which take a value, as in "–opt~OPTVAL".
+ VALUE is a list whose members have the form (KEY DESC OPTION
+ READER), see ‘magit-define-popup-option’ for details.
+
+ • ‘:variables’
+
+ Git variables which can be set from the popup. VALUE is a
+ list whose members have the form (KEY DESC COMMAND FORMATTER),
+ see ‘magit-define-popup-variable’ for details.
+
+ • ‘:default-arguments’
+
+ The default arguments, a list of switches (which are then
+ enabled by default) and options with there default values, as
+ in "–OPT~OPTVAL\".
+
+ • ‘:sequence-predicate’
+
+ When this function returns non-nil, then the popup uses
+ ‘:sequence-actions’ instead of ‘:actions’, and does not show
+ the ‘:switches’ and ‘:options’.
+
+ • ‘:sequence-actions’
+
+ The actions which can be invoked from the popup, when
+ ‘:sequence-predicate’ returns non-nil.
+
+ • ‘:setup-function’
+
+ When this function is specified, then it is used instead of
+ ‘magit-popup-default-setup’.
+
+ • ‘:refresh-function’
+
+ When this function is specified, then it is used instead of
+ calling ‘magit-popup-insert-section’ three times with symbols
+ ‘magit-popup-switch-button’, ‘magit-popup-option-button’, and
+ finally ‘magit-popup-action-button’ as argument.
+
+ • ‘:man-page’
+
+ The name of the manpage to be displayed when the user requests
+ help for an argument.
+
+\1f
+File: magit-popup.info, Node: Defining suffix commands, Prev: Defining prefix commands, Up: Defining prefix and suffix commands
+
+3.2 Defining suffix commands
+============================
+
+Commands intended to be invoked from a particular popup should determine
+the currently effective arguments by calling the function
+‘SHORTNAME-arguments’ inside their ‘interactive’ form. This function is
+created by the ‘magit-define-popup’ macro. For a popup named
+‘prefix-foo-popup’ the name of this function is ‘prefix-foo-arguments’.
+
+ When the command was invoked as an action in the respective popup,
+then this function returns the arguments that were set in the popup.
+Otherwise when the command was invoked as the default of the popup (by
+calling the popup command with a prefix argument), or without using the
+popup command at all, then this function returns the buffer-local or
+global value of the variable ‘SHORTNAME-arguments’.
+
+ Internally arguments are handled as a list of strings. This might
+not be appropriate for the intended use inside commands, or it might be
+necessary to manipulate that list somehow, i.e. to split "–ARG=VAL"
+into "–ARG""VAL". This should be done by advising or redefining the
+function ‘SHORTNAME-arguments’.
+
+ Internally ‘SHORNAME-arguments’ used following variables and
+function. Except when redefining the former, you should not use these
+directly.
+
+ -- Variable: magit-current-popup
+
+ The popup from which this editing command was invoked.
+
+ -- Variable: magit-current-popup-args
+
+ The value of the popup arguments for this editing command.
+
+ If the current command was invoked from a popup, then this is a
+ list of strings of all the set switches and options. This includes
+ arguments which are set by default not only those explicitly set
+ during this invocation.
+
+ When the value is nil, then that can be because no argument is set,
+ or because the current command wasn’t invoked from a popup at all.
+
+ -- Function: magit-current-popup-args &rest args
+
+ This function returns the value of the popup arguments for this
+ editing command. The value is the same as that of the variable by
+ the same name, except that FILTER is applied. FILTER is a list of
+ regexps; only arguments that match one of them are returned. The
+ first element of FILTER may also be ‘:not’ in which case only
+ arguments that don’t match any of the regexps are returned, or
+ ‘:only’ which doesn’t change the behavior.
+
+
+\1f
+Tag Table:
+Node: Top\7f994
+Node: Introduction\7f2170
+Node: Usage\7f4747
+Node: Customizing existing popups\7f9404
+Node: Other options\7f14932
+Node: Defining prefix and suffix commands\7f16981
+Node: Defining prefix commands\7f19077
+Node: Defining suffix commands\7f25757
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End:
--- /dev/null
+This is the file .../info/dir, which contains the
+topmost node of the Info hierarchy, called (dir)Top.
+The first time you invoke Info you start off looking at this node.
+\1f
+File: dir, Node: Top This is the top of the INFO tree
+
+ This (the Directory node) gives a menu of major topics.
+ Typing "q" exits, "?" lists all Info commands, "d" returns here,
+ "h" gives a primer for first-timers,
+ "mEmacs<Return>" visits the Emacs manual, etc.
+
+ In Emacs, you can click mouse button 2 on a menu item or cross reference
+ to select it.
+
+* Menu:
+
+Emacs
+* With-Editor: (with-editor). Using the Emacsclient as $EDITOR.
--- /dev/null
+;;; with-editor-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+(add-to-list 'load-path (directory-file-name (or (file-name-directory #$) (car load-path))))
+\f
+;;;### (autoloads nil nil ("with-editor-pkg.el" "with-editor.el")
+;;;;;; (22576 8240 0 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+;;; with-editor-autoloads.el ends here
--- /dev/null
+(define-package "with-editor" "20161109.403" "Use the Emacsclient as $EDITOR"
+ '((emacs "24.4")
+ (async "1.9")
+ (dash "2.13.0"))
+ :url "https://github.com/magit/with-editor" :keywords
+ '("tools"))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; with-editor.el --- Use the Emacsclient as $EDITOR -*- lexical-binding: t -*-
+
+;; Copyright (C) 2014-2016 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file. If not,
+;; see https://github.com/magit/with-editor/blob/master/AUTHORS.md.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Package-Requires: ((emacs "24.4") (async "1.9") (dash "2.13.0"))
+;; Keywords: tools
+;; Homepage: https://github.com/magit/with-editor
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library makes it possible to reliably use the Emacsclient as
+;; the `$EDITOR' of child processes. It makes sure that they know how
+;; to call home. For remote processes a substitute is provided, which
+;; communicates with Emacs on standard output/input instead of using a
+;; socket as the Emacsclient does.
+
+;; It provides the commands `with-editor-async-shell-command' and
+;; `with-editor-shell-command', which are intended as replacements
+;; for `async-shell-command' and `shell-command'. They automatically
+;; export `$EDITOR' making sure the executed command uses the current
+;; Emacs instance as "the editor". With a prefix argument these
+;; commands prompt for an alternative environment variable such as
+;; `$GIT_EDITOR'. To always use these variants add this to your init
+;; file:
+;;
+;; (define-key (current-global-map)
+;; [remap async-shell-command] 'with-editor-async-shell-command)
+;; (define-key (current-global-map)
+;; [remap shell-command] 'with-editor-shell-command)
+
+;; Alternatively use the global `shell-command-with-editor-mode',
+;; which always sets `$EDITOR' for all Emacs commands which ultimately
+;; use `shell-command' to asynchronously run some shell command.
+
+;; The command `with-editor-export-editor' exports `$EDITOR' or
+;; another such environment variable in `shell-mode', `term-mode' and
+;; `eshell-mode' buffers. Use this Emacs command before executing a
+;; shell command which needs the editor set, or always arrange for the
+;; current Emacs instance to be used as editor by adding it to the
+;; appropriate mode hooks:
+;;
+;; (add-hook 'shell-mode-hook 'with-editor-export-editor)
+;; (add-hook 'term-exec-hook 'with-editor-export-editor)
+;; (add-hook 'eshell-mode-hook 'with-editor-export-editor)
+
+;; Some variants of this function exist, these two forms are
+;; equivalent:
+;;
+;; (add-hook 'shell-mode-hook
+;; (apply-partially 'with-editor-export-editor "GIT_EDITOR"))
+;; (add-hook 'shell-mode-hook 'with-editor-export-git-editor)
+
+;; This library can also be used by other packages which need to use
+;; the current Emacs instance as editor. In fact this library was
+;; written for Magit and its `git-commit-mode' and `git-rebase-mode'.
+;; Consult `git-rebase.el' and the related code in `magit-sequence.el'
+;; for a simple example.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+(require 'server)
+(require 'tramp)
+(require 'tramp-sh nil t)
+
+(and (require 'async-bytecomp nil t)
+ (memq 'magit (bound-and-true-p async-bytecomp-allowed-packages))
+ (fboundp 'async-bytecomp-package-mode)
+ (async-bytecomp-package-mode 1))
+
+(eval-when-compile
+ (progn (require 'dired nil t)
+ (require 'eshell nil t)
+ (require 'term nil t)
+ (require 'warnings nil t)))
+(declare-function dired-get-filename 'dired)
+(declare-function term-emulate-terminal 'term)
+(defvar eshell-preoutput-filter-functions)
+
+;;; Options
+
+(defgroup with-editor nil
+ "Use the Emacsclient as $EDITOR."
+ :group 'external
+ :group 'server)
+
+(defun with-editor-locate-emacsclient ()
+ "Search for a suitable Emacsclient executable."
+ (--if-let (with-editor-locate-emacsclient-1 (with-editor-emacsclient-path) 3)
+ it
+ (display-warning 'with-editor (format "\
+Cannot determine a suitable Emacsclient
+
+Determining an Emacsclient executable suitable for the
+current Emacs instance failed. For more information
+please see https://github.com/magit/magit/wiki/Emacsclient."))
+ nil))
+
+(defun with-editor-locate-emacsclient-1 (path depth)
+ (let* ((version-lst (-take depth (split-string emacs-version "\\.")))
+ (version-reg (concat "^" (mapconcat #'identity version-lst "\\."))))
+ (or (locate-file-internal
+ "emacsclient" path
+ (cl-mapcan
+ (lambda (v) (cl-mapcar (lambda (e) (concat v e)) exec-suffixes))
+ (nconc (and (boundp 'debian-emacs-flavor)
+ (list (format ".%s" debian-emacs-flavor)))
+ (cl-mapcon (lambda (v)
+ (setq v (mapconcat #'identity (reverse v) "."))
+ (list v (concat "-" v) (concat ".emacs" v)))
+ (reverse version-lst))
+ (list "" "-snapshot" ".emacs-snapshot")))
+ (lambda (exec)
+ (ignore-errors
+ (string-match-p version-reg
+ (with-editor-emacsclient-version exec)))))
+ (and (> depth 1)
+ (with-editor-locate-emacsclient-1 path (1- depth))))))
+
+(defun with-editor-emacsclient-version (exec)
+ (-when-let (1st-line (car (process-lines exec "--version")))
+ (cadr (split-string 1st-line))))
+
+(defun with-editor-emacsclient-path ()
+ (let ((path exec-path))
+ (when invocation-directory
+ (push (directory-file-name invocation-directory) path)
+ (let* ((linkname (expand-file-name invocation-name invocation-directory))
+ (truename (file-chase-links linkname)))
+ (unless (equal truename linkname)
+ (push (directory-file-name (file-name-directory truename)) path)))
+ (when (eq system-type 'darwin)
+ (let ((dir (expand-file-name "bin" invocation-directory)))
+ (when (file-directory-p dir)
+ (push dir path)))
+ (when (string-match-p "Cellar" invocation-directory)
+ (let ((dir (expand-file-name "../../../bin" invocation-directory)))
+ (when (file-directory-p dir)
+ (push dir path))))))
+ (cl-remove-duplicates path :test 'equal)))
+
+(defcustom with-editor-emacsclient-executable (with-editor-locate-emacsclient)
+ "The Emacsclient executable used by the `with-editor' macro."
+ :group 'with-editor
+ :type '(choice (string :tag "Executable")
+ (const :tag "Don't use Emacsclient" nil)))
+
+(defcustom with-editor-sleeping-editor "\
+sh -c '\
+echo \"WITH-EDITOR: $$ OPEN $0\"; \
+sleep 604800 & sleep=$!; \
+trap \"kill $sleep; exit 0\" USR1; \
+trap \"kill $sleep; exit 1\" USR2; \
+wait $sleep'"
+ "The sleeping editor, used when the Emacsclient cannot be used.
+
+This fallback is used for asynchronous process started inside the
+macro `with-editor', when the process runs on a remote machine or
+for local processes when `with-editor-emacsclient-executable' is
+nil (i.e. when no suitable Emacsclient was found, or the user
+decided not to use it).
+
+Where the latter uses a socket to communicate with Emacs' server,
+this substitute prints edit requests to its standard output on
+which a process filter listens for such requests. As such it is
+not a complete substitute for a proper Emacsclient, it can only
+be used as $EDITOR of child process of the current Emacs instance.
+
+Some shells do not execute traps immediately when waiting for a
+child process, but by default we do use such a blocking child
+process.
+
+If you use such a shell (e.g. `csh' on FreeBSD, but not Debian),
+then you have to edit this option. You can either replace \"sh\"
+with \"bash\" (and install that), or you can use the older, less
+performant implementation:
+
+ \"sh -c '\\
+ echo \\\"WITH-EDITOR: $$ OPEN $0\\\"; \\
+ trap \\\"exit 0\\\" USR1; \\
+ trap \\\"exit 1\" USR2; \\
+ while true; do sleep 1; done'\"
+
+Note that this leads to a delay of up to a second. The delay can
+be shortened by replacing \"sleep 1\" with \"sleep 0.01\", or if your
+implementation does not support floats, then by using `nanosleep'
+instead."
+ :group 'with-editor
+ :type 'string)
+
+(defcustom with-editor-finish-query-functions nil
+ "List of functions called to query before finishing session.
+
+The buffer in question is current while the functions are called.
+If any of them returns nil, then the session is not finished and
+the buffer is not killed. The user should then fix the issue and
+try again. The functions are called with one argument. If it is
+non-nil then that indicates that the user used a prefix argument
+to force finishing the session despite issues. Functions should
+usually honor that and return non-nil."
+ :group 'with-editor
+ :type 'hook)
+(put 'with-editor-finish-query-functions 'permanent-local t)
+
+(defcustom with-editor-cancel-query-functions nil
+ "List of functions called to query before canceling session.
+
+The buffer in question is current while the functions are called.
+If any of them returns nil, then the session is not canceled and
+the buffer is not killed. The user should then fix the issue and
+try again. The functions are called with one argument. If it is
+non-nil then that indicates that the user used a prefix argument
+to force canceling the session despite issues. Functions should
+usually honor that and return non-nil."
+ :group 'with-editor
+ :type 'hook)
+(put 'with-editor-cancel-query-functions 'permanent-local t)
+
+(defcustom with-editor-mode-lighter " WE"
+ "The mode-line lighter of the With-Editor mode."
+ :group 'with-editor
+ :type '(choice (const :tag "No lighter" "") string))
+
+(defvar with-editor-server-window-alist nil
+ "Alist of filename patterns vs corresponding `server-window'.
+
+Each element looks like (REGEXP . FUNCTION). Files matching
+REGEXP are selected using FUNCTION instead of the default in
+`server-window'.
+
+Note that when a package adds an entry here then it probably
+has a reason to disrespect `server-window' and it likely is
+not a good idea to change such entries.")
+
+(defvar with-editor-file-name-history-exclude nil
+ "List of regexps for filenames `server-visit' should no remember.
+When a filename matches any of the regexps, then `server-visit'
+does not add it to the variable `file-name-history', which is
+used when reading a filename in the minibuffer.")
+
+;;; Mode Commands
+
+(defvar with-editor-pre-finish-hook nil)
+(defvar with-editor-pre-cancel-hook nil)
+(defvar with-editor-post-finish-hook nil)
+(defvar with-editor-post-finish-hook-1 nil)
+(defvar with-editor-post-cancel-hook nil)
+(defvar with-editor-post-cancel-hook-1 nil)
+(defvar with-editor-cancel-alist nil)
+(put 'with-editor-pre-finish-hook 'permanent-local t)
+(put 'with-editor-pre-cancel-hook 'permanent-local t)
+(put 'with-editor-post-finish-hook 'permanent-local t)
+(put 'with-editor-post-cancel-hook 'permanent-local t)
+
+(defvar with-editor-show-usage t)
+(defvar with-editor-cancel-message nil)
+(defvar with-editor-previous-winconf nil)
+(make-variable-buffer-local 'with-editor-show-usage)
+(make-variable-buffer-local 'with-editor-cancel-message)
+(make-variable-buffer-local 'with-editor-previous-winconf)
+(put 'with-editor-cancel-message 'permanent-local t)
+(put 'with-editor-previous-winconf 'permanent-local t)
+
+(defvar-local with-editor--pid nil "For internal use.")
+(put 'with-editor--pid 'permanent-local t)
+
+(defun with-editor-finish (force)
+ "Finish the current edit session."
+ (interactive "P")
+ (when (run-hook-with-args-until-failure
+ 'with-editor-finish-query-functions force)
+ (let ((with-editor-post-finish-hook-1
+ (ignore-errors (delq t with-editor-post-finish-hook))))
+ (run-hooks 'with-editor-pre-finish-hook)
+ (with-editor-return nil)
+ (accept-process-output nil 0.1)
+ (run-hooks 'with-editor-post-finish-hook-1))))
+
+(defun with-editor-cancel (force)
+ "Cancel the current edit session."
+ (interactive "P")
+ (when (run-hook-with-args-until-failure
+ 'with-editor-cancel-query-functions force)
+ (let ((message with-editor-cancel-message))
+ (when (functionp message)
+ (setq message (funcall message)))
+ (let ((with-editor-post-cancel-hook-1
+ (ignore-errors (delq t with-editor-post-cancel-hook)))
+ (with-editor-cancel-alist nil))
+ (run-hooks 'with-editor-pre-cancel-hook)
+ (with-editor-return t)
+ (accept-process-output nil 0.1)
+ (run-hooks 'with-editor-post-cancel-hook-1))
+ (message (or message "Canceled by user")))))
+
+(defun with-editor-return (cancel)
+ (let ((winconf with-editor-previous-winconf)
+ (clients server-buffer-clients)
+ (dir default-directory)
+ (pid with-editor--pid))
+ (remove-hook 'kill-buffer-query-functions
+ 'with-editor-kill-buffer-noop t)
+ (cond (cancel
+ (save-buffer)
+ (if clients
+ (dolist (client clients)
+ (ignore-errors
+ (server-send-string client "-error Canceled by user"))
+ (delete-process client))
+ ;; Fallback for when emacs was used as $EDITOR instead
+ ;; of emacsclient or the sleeping editor. See #2258.
+ (ignore-errors (delete-file buffer-file-name))
+ (kill-buffer)))
+ (t
+ (save-buffer)
+ (if clients
+ ;; Don't use `server-edit' because we do not want to show
+ ;; another buffer belonging to another client. See #2197.
+ (server-done)
+ (kill-buffer))))
+ (when pid
+ (let ((default-directory dir))
+ (process-file "kill" nil nil nil
+ "-s" (if cancel "USR2" "USR1") pid)))
+ (when (and winconf (eq (window-configuration-frame winconf)
+ (selected-frame)))
+ (set-window-configuration winconf))))
+
+;;; Mode
+
+(defvar with-editor-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\C-c\C-c" 'with-editor-finish)
+ (define-key map [remap server-edit] 'with-editor-finish)
+ (define-key map [remap evil-save-and-close] 'with-editor-finish)
+ (define-key map [remap evil-save-modified-and-close] 'with-editor-finish)
+ (define-key map "\C-c\C-k" 'with-editor-cancel)
+ (define-key map [remap kill-buffer] 'with-editor-cancel)
+ (define-key map [remap ido-kill-buffer] 'with-editor-cancel)
+ (define-key map [remap iswitchb-kill-buffer] 'with-editor-cancel)
+ (define-key map [remap evil-quit] 'with-editor-cancel)
+ map))
+
+(define-minor-mode with-editor-mode
+ "Edit a file as the $EDITOR of an external process."
+ :lighter with-editor-mode-lighter
+ ;; Protect the user from killing the buffer without using
+ ;; either `with-editor-finish' or `with-editor-cancel',
+ ;; and from removing the key bindings for these commands.
+ (unless with-editor-mode
+ (error "With-Editor mode cannot be turned off"))
+ (add-hook 'kill-buffer-query-functions
+ 'with-editor-kill-buffer-noop nil t)
+ ;; `server-execute' displays a message which is not
+ ;; correct when using this mode.
+ (when with-editor-show-usage
+ (with-editor-usage-message)))
+
+(put 'with-editor-mode 'permanent-local t)
+
+(defun with-editor-kill-buffer-noop ()
+ (message (substitute-command-keys "\
+Don't kill this buffer. Instead cancel using \\[with-editor-cancel]")))
+
+(defun with-editor-usage-message ()
+ ;; Run after `server-execute', which is run using
+ ;; a timer which starts immediately.
+ (run-with-timer
+ 0.01 nil `(lambda ()
+ (with-current-buffer ,(current-buffer)
+ (message (substitute-command-keys "\
+Type \\[with-editor-finish] to finish, \
+or \\[with-editor-cancel] to cancel"))))))
+
+;;; Wrappers
+
+(defvar with-editor--envvar nil "For internal use.")
+
+(defmacro with-editor (&rest body)
+ "Use the Emacsclient as $EDITOR while evaluating BODY.
+Modify the `process-environment' for processes started in BODY,
+instructing them to use the Emacsclient as $EDITOR. If optional
+ENVVAR is provided then bind that environment variable instead.
+\n(fn [ENVVAR] BODY...)"
+ (declare (indent defun) (debug (body)))
+ `(let ((with-editor--envvar ,(if (stringp (car body))
+ (pop body)
+ '(or with-editor--envvar "EDITOR")))
+ (process-environment process-environment))
+ (if (or (not with-editor-emacsclient-executable)
+ (file-remote-p default-directory))
+ (push (concat with-editor--envvar "=" with-editor-sleeping-editor)
+ process-environment)
+ ;; Make sure server-use-tcp's value is valid.
+ (unless (featurep 'make-network-process '(:family local))
+ (setq server-use-tcp t))
+ ;; Make sure the server is running.
+ (unless server-process
+ (when (server-running-p server-name)
+ (setq server-name (format "server%s" (emacs-pid)))
+ (when (server-running-p server-name)
+ (server-force-delete server-name)))
+ (server-start))
+ ;; Tell $EDITOR to use the Emacsclient.
+ (push (concat with-editor--envvar "="
+ (shell-quote-argument with-editor-emacsclient-executable)
+ ;; Tell the process where the server file is.
+ (and (not server-use-tcp)
+ (concat " --socket-name="
+ (shell-quote-argument
+ (expand-file-name server-name
+ server-socket-dir)))))
+ process-environment)
+ (when server-use-tcp
+ (push (concat "EMACS_SERVER_FILE="
+ (expand-file-name server-name server-auth-dir))
+ process-environment))
+ ;; As last resort fallback to the sleeping editor.
+ (push (concat "ALTERNATE_EDITOR=" with-editor-sleeping-editor)
+ process-environment))
+ ,@body))
+
+(defun with-editor-server-window ()
+ (or (and buffer-file-name
+ (cdr (--first (string-match-p (car it) buffer-file-name)
+ with-editor-server-window-alist)))
+ server-window))
+
+(defun server-switch-buffer--with-editor-server-window-alist
+ (fn &optional next-buffer killed-one filepos)
+ "Honor `with-editor-server-window-alist' (which see)."
+ (let ((server-window (with-current-buffer
+ (or next-buffer (current-buffer))
+ (when with-editor-mode
+ (setq with-editor-previous-winconf
+ (current-window-configuration)))
+ (with-editor-server-window))))
+ (funcall fn next-buffer killed-one filepos)))
+
+(advice-add 'server-switch-buffer :around
+ 'server-switch-buffer--with-editor-server-window-alist)
+
+(defun start-file-process--with-editor-process-filter
+ (fn name buffer program &rest program-args)
+ "When called inside a `with-editor' form and the Emacsclient
+cannot be used, then give the process the filter function
+`with-editor-process-filter'. To avoid overriding the filter
+being added here you should use `with-editor-set-process-filter'
+instead of `set-process-filter' inside `with-editor' forms.
+
+When the `default-directory' is located on a remote machine,
+then also manipulate PROGRAM and PROGRAM-ARGS in order to set
+the appropriate editor environment variable."
+ (if (not with-editor--envvar)
+ (apply fn name buffer program program-args)
+ (when (file-remote-p default-directory)
+ (unless (equal program "env")
+ (push program program-args)
+ (setq program "env"))
+ (push (concat with-editor--envvar "=" with-editor-sleeping-editor)
+ program-args))
+ (let ((process (apply fn name buffer program program-args)))
+ (set-process-filter process 'with-editor-process-filter)
+ (process-put process 'default-dir default-directory)
+ process)))
+
+(advice-add 'start-file-process :around
+ 'start-file-process--with-editor-process-filter)
+
+(defun with-editor-set-process-filter (process filter)
+ "Like `set-process-filter' but keep `with-editor-process-filter'.
+Give PROCESS the new FILTER but keep `with-editor-process-filter'
+if that was added earlier by the adviced `start-file-process'.
+
+Do so by wrapping the two filter functions using a lambda, which
+becomes the actual filter. It calls `with-editor-process-filter'
+first, passing t as NO-STANDARD-FILTER. Then it calls FILTER,
+which may or may not insert the text into the PROCESS' buffer."
+ (set-process-filter
+ process
+ (if (eq (process-filter process) 'with-editor-process-filter)
+ `(lambda (proc str)
+ (,filter proc str)
+ (with-editor-process-filter proc str t))
+ filter)))
+
+(defvar with-editor-filter-visit-hook nil)
+
+(defun with-editor-output-filter (string)
+ (save-match-data
+ (if (string-match "^WITH-EDITOR: \\([0-9]+\\) OPEN \\(.+?\\)\r?$" string)
+ (let ((pid (match-string 1 string))
+ (file (match-string 2 string)))
+ (with-current-buffer
+ (find-file-noselect
+ (if (file-name-absolute-p file)
+ (if (tramp-tramp-file-p default-directory)
+ (with-parsed-tramp-file-name default-directory nil
+ (tramp-make-tramp-file-name method user host file hop))
+ file)
+ (expand-file-name file)))
+ (with-editor-mode 1)
+ (setq with-editor--pid pid)
+ (run-hooks 'with-editor-filter-visit-hook)
+ (funcall (or (with-editor-server-window) 'switch-to-buffer)
+ (current-buffer))
+ (kill-local-variable 'server-window))
+ nil)
+ string)))
+
+(defun with-editor-process-filter
+ (process string &optional no-default-filter)
+ "Listen for edit requests by child processes."
+ (let ((default-directory (process-get process 'default-dir)))
+ (with-editor-output-filter string))
+ (unless no-default-filter
+ (internal-default-process-filter process string)))
+
+(advice-add 'server-visit-files :after
+ 'server-visit-files--with-editor-file-name-history-exclude)
+
+(defun server-visit-files--with-editor-file-name-history-exclude
+ (files _proc &optional _nowait)
+ (dolist (file files)
+ (setq file (car file))
+ (when (--any (string-match-p it file)
+ with-editor-file-name-history-exclude)
+ (setq file-name-history (delete file file-name-history)))))
+
+;;; Augmentations
+
+(cl-defun with-editor-export-editor (&optional (envvar "EDITOR"))
+ "Teach subsequent commands to use current Emacs instance as editor.
+
+Set and export the environment variable ENVVAR, by default
+\"EDITOR\". The value is automatically generated to teach
+commands to use the current Emacs instance as \"the editor\".
+
+This works in `shell-mode', `term-mode' and `eshell-mode'."
+ (interactive (list (with-editor-read-envvar)))
+ (cond
+ ((derived-mode-p 'comint-mode 'term-mode)
+ (let* ((process (get-buffer-process (current-buffer)))
+ (filter (process-filter process)))
+ (goto-char (process-mark process))
+ (process-send-string
+ process (format "export %s=%s\n" envvar
+ (shell-quote-argument with-editor-sleeping-editor)))
+ (while (accept-process-output process 0.1))
+ (set-process-filter process filter)
+ (if (derived-mode-p 'term-mode)
+ (with-editor-set-process-filter process 'with-editor-emulate-terminal)
+ (add-hook 'comint-output-filter-functions 'with-editor-output-filter
+ nil t))))
+ ((derived-mode-p 'eshell-mode)
+ (add-to-list 'eshell-preoutput-filter-functions
+ 'with-editor-output-filter)
+ (setenv envvar with-editor-sleeping-editor))
+ (t
+ (error "Cannot export environment variables in this buffer")))
+ (message "Successfully exported %s" envvar))
+
+(defun with-editor-export-git-editor ()
+ "Like `with-editor-export-editor' but always set `$GIT_EDITOR'."
+ (interactive)
+ (with-editor-export-editor "GIT_EDITOR"))
+
+(defun with-editor-export-hg-editor ()
+ "Like `with-editor-export-editor' but always set `$HG_EDITOR'."
+ (interactive)
+ (with-editor-export-editor "HG_EDITOR"))
+
+(defun with-editor-emulate-terminal (process string)
+ "Like `term-emulate-terminal' but also handle edit requests."
+ (when (with-editor-output-filter string)
+ (term-emulate-terminal process string)))
+
+(defvar with-editor-envvars '("EDITOR" "GIT_EDITOR" "HG_EDITOR"))
+
+(cl-defun with-editor-read-envvar
+ (&optional (prompt "Set environment variable")
+ (default "EDITOR"))
+ (let ((reply (completing-read (if default
+ (format "%s (%s): " prompt default)
+ (concat prompt ": "))
+ with-editor-envvars nil nil nil nil default)))
+ (if (string= reply "") (user-error "Nothing selected") reply)))
+
+(define-minor-mode shell-command-with-editor-mode
+ "Teach `shell-command' to use current Emacs instance as editor.
+
+Teach `shell-command', and all commands that ultimately call that
+command, to use the current Emacs instance as editor by executing
+\"EDITOR=CLIENT COMMAND&\" instead of just \"COMMAND&\".
+
+CLIENT is automatically generated; EDITOR=CLIENT instructs
+COMMAND to use to the current Emacs instance as \"the editor\",
+assuming no other variable overrides the effect of \"$EDITOR\".
+CLIENT may be the path to an appropriate emacsclient executable
+with arguments, or a script which also works over Tramp.
+
+Alternatively you can use the `with-editor-async-shell-command',
+which also allows the use of another variable instead of
+\"EDITOR\"."
+ :global t)
+
+(defun with-editor-async-shell-command
+ (command &optional output-buffer error-buffer envvar)
+ "Like `async-shell-command' but with `$EDITOR' set.
+
+Execute string \"ENVVAR=CLIENT COMMAND\" in an inferior shell;
+display output, if any. With a prefix argument prompt for an
+environment variable, otherwise the default \"EDITOR\" variable
+is used. With a negative prefix argument additionally insert
+the COMMAND's output at point.
+
+CLIENT is automatically generated; ENVVAR=CLIENT instructs
+COMMAND to use to the current Emacs instance as \"the editor\",
+assuming it respects ENVVAR as an \"EDITOR\"-like variable.
+CLIENT maybe the path to an appropriate emacsclient executable
+with arguments, or a script which also works over Tramp.
+
+Also see `async-shell-command' and `shell-command'."
+ (interactive (with-editor-shell-command-read-args "Async shell command: " t))
+ (let ((with-editor--envvar envvar))
+ (with-editor
+ (async-shell-command command output-buffer error-buffer))))
+
+(defun with-editor-shell-command
+ (command &optional output-buffer error-buffer envvar)
+ "Like `shell-command' or `with-editor-async-shell-command'.
+If COMMAND ends with \"&\" behave like the latter,
+else like the former."
+ (interactive (with-editor-shell-command-read-args "Shell command: "))
+ (if (string-match "&[ \t]*\\'" command)
+ (with-editor-async-shell-command
+ command output-buffer error-buffer envvar)
+ (shell-command command output-buffer error-buffer)))
+
+(defun with-editor-shell-command-read-args (prompt &optional async)
+ (let ((command (read-shell-command
+ prompt nil nil
+ (--when-let (or buffer-file-name
+ (and (eq major-mode 'dired-mode)
+ (dired-get-filename nil t)))
+ (file-relative-name it)))))
+ (list command
+ (if (or async (setq async (string-match-p "&[ \t]*\\'" command)))
+ (< (prefix-numeric-value current-prefix-arg) 0)
+ current-prefix-arg)
+ shell-command-default-error-buffer
+ (and async current-prefix-arg (with-editor-read-envvar)))))
+
+(defun shell-command--shell-command-with-editor-mode
+ (fn command &optional output-buffer error-buffer)
+ ;; `shell-mode' and its hook are intended for buffers in which an
+ ;; interactive shell is running, but `shell-command' also turns on
+ ;; that mode, even though it only runs the shell to run a single
+ ;; command. The `with-editor-export-editor' hook function is only
+ ;; intended to be used in buffers in which an interactive shell is
+ ;; running, so it has to be remove here.
+ (let ((shell-mode-hook (remove 'with-editor-export-editor shell-mode-hook)))
+ (cond ((or (not (or with-editor--envvar shell-command-with-editor-mode))
+ (not (string-match-p "&\\'" command)))
+ (funcall fn command output-buffer error-buffer))
+ ((and with-editor-emacsclient-executable
+ (not (file-remote-p default-directory)))
+ (with-editor (funcall fn command output-buffer error-buffer)))
+ (t
+ (apply fn (format "%s=%s %s"
+ (or with-editor--envvar "EDITOR")
+ (shell-quote-argument with-editor-sleeping-editor)
+ command)
+ output-buffer error-buffer)
+ (ignore-errors
+ (let ((process (get-buffer-process
+ (or output-buffer
+ (get-buffer "*Async Shell Command*")))))
+ (set-process-filter
+ process (lambda (proc str)
+ (comint-output-filter proc str)
+ (with-editor-process-filter proc str t)))
+ process))))))
+
+(advice-add 'shell-command :around
+ 'shell-command--shell-command-with-editor-mode)
+
+;;; with-editor.el ends soon
+
+(defun with-editor-debug ()
+ "Debug configuration issues.
+See `with-editor.info' for instructions."
+ (interactive)
+ (with-current-buffer (get-buffer-create "*with-editor-debug*")
+ (pop-to-buffer (current-buffer))
+ (erase-buffer)
+ (ignore-errors (with-editor))
+ (insert
+ (format "with-editor: %s\n" (locate-library "with-editor.el"))
+ (format "emacs: %s (%s)\n"
+ (expand-file-name invocation-name invocation-directory)
+ emacs-version)
+ "system:\n"
+ (format " system-type: %s\n" system-type)
+ (format " system-configuration: %s\n" system-configuration)
+ (format " system-configuration-options: %s\n" system-configuration-options)
+ "server:\n"
+ (format " server-running-p: %s\n" (server-running-p))
+ (format " server-process: %S\n" server-process)
+ (format " server-use-tcp: %s\n" server-use-tcp)
+ (format " server-name: %s\n" server-name)
+ (format " server-socket-dir: %s\n" server-socket-dir))
+ (if (and server-socket-dir (file-accessible-directory-p server-socket-dir))
+ (--each (directory-files server-socket-dir nil "^[^.]")
+ (insert (format " %s\n" it)))
+ (insert (format " %s: not an accessible directory\n"
+ (if server-use-tcp "WARNING" "ERROR"))))
+ (insert (format " server-auth-dir: %s\n" server-auth-dir))
+ (if (file-accessible-directory-p server-auth-dir)
+ (--each (directory-files server-auth-dir nil "^[^.]")
+ (insert (format " %s\n" it)))
+ (insert (format " %s: not an accessible directory\n"
+ (if server-use-tcp "ERROR" "WARNING"))))
+ (let ((val with-editor-emacsclient-executable)
+ (def (default-value 'with-editor-emacsclient-executable))
+ (fun (let ((warning-minimum-level :error)
+ (warning-minimum-log-level :error))
+ (with-editor-locate-emacsclient))))
+ (insert "magit-emacsclient-executable:\n"
+ (format " value: %s (%s)\n" val
+ (and val (with-editor-emacsclient-version val)))
+ (format " default: %s (%s)\n" def
+ (and def (with-editor-emacsclient-version def)))
+ (format " funcall: %s (%s)\n" fun
+ (and fun (with-editor-emacsclient-version fun)))))
+ (insert "path:\n"
+ (format " $PATH: %S\n" (getenv "PATH"))
+ (format " exec-path: %s\n" exec-path))
+ (insert (format " with-editor-emacsclient-path:\n"))
+ (--each (with-editor-emacsclient-path)
+ (insert (format " %s (%s)\n" it (car (file-attributes it))))
+ (when (file-directory-p it)
+ (dolist (exec (directory-files it t "emacsclient"))
+ (insert (format " %s (%s)\n" exec
+ (with-editor-emacsclient-version exec))))))))
+
+(defconst with-editor-font-lock-keywords
+ '(("(\\(with-\\(?:git-\\)?editor\\)\\_>" (1 'font-lock-keyword-face))))
+(font-lock-add-keywords 'emacs-lisp-mode with-editor-font-lock-keywords)
+
+(provide 'with-editor)
+;; Local Variables:
+;; indent-tabs-mode: nil
+;; End:
+;;; with-editor.el ends here
--- /dev/null
+This is with-editor.info, produced by makeinfo version 5.2 from
+with-editor.texi.
+
+The library ‘with-editor’ makes it easy to use the Emacsclient as the
+‘$EDITOR’ of child processes, making sure they know how to call home.
+For remote processes a substitute is provided, which communicates with
+Emacs on standard output instead of using a socket as the Emacsclient
+does.
+
+ This library was written because Magit has to be able to do the above
+to allow the user to edit commit messages gracefully and to edit rebase
+sequences, which wouldn’t be possible at all otherwise.
+
+ Because other packages can benefit from such functionality, this
+library is made available as a separate package. It also defines some
+additional functionality which makes it useful even for end-users, who
+don’t use Magit or another package which uses it internally.
+
+ Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+INFO-DIR-SECTION Emacs
+START-INFO-DIR-ENTRY
+* With-Editor: (with-editor). Using the Emacsclient as $EDITOR.
+END-INFO-DIR-ENTRY
+
+\1f
+File: with-editor.info, Node: Top, Next: Using the With-Editor package, Up: (dir)
+
+With-Editor User Manual
+***********************
+
+The library ‘with-editor’ makes it easy to use the Emacsclient as the
+‘$EDITOR’ of child processes, making sure they know how to call home.
+For remote processes a substitute is provided, which communicates with
+Emacs on standard output instead of using a socket as the Emacsclient
+does.
+
+ This library was written because Magit has to be able to do the above
+to allow the user to edit commit messages gracefully and to edit rebase
+sequences, which wouldn’t be possible at all otherwise.
+
+ Because other packages can benefit from such functionality, this
+library is made available as a separate package. It also defines some
+additional functionality which makes it useful even for end-users, who
+don’t use Magit or another package which uses it internally.
+
+ Copyright (C) 2015-2016 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+* Menu:
+
+* Using the With-Editor package::
+* Using With-Editor as a library::
+* Debugging::
+
+— The Detailed Node Listing —
+
+Using the With-Editor package
+
+* Configuring With-Editor::
+* Using With-Editor commands::
+
+\1f
+File: with-editor.info, Node: Using the With-Editor package, Next: Using With-Editor as a library, Prev: Top, Up: Top
+
+1 Using the With-Editor package
+*******************************
+
+The ‘With-Editor’ package is used internally by Magit when editing
+commit messages and rebase sequences. It also provides some commands
+and features which are useful by themselves, even if you don’t use
+Magit.
+
+ For information about using this library in you own package, see
+*note Using With-Editor as a library: Using With-Editor as a library.
+
+* Menu:
+
+* Configuring With-Editor::
+* Using With-Editor commands::
+
+\1f
+File: with-editor.info, Node: Configuring With-Editor, Next: Using With-Editor commands, Up: Using the With-Editor package
+
+1.1 Configuring With-Editor
+===========================
+
+With-Editor tries very hard to locate a suitable emacsclient executable,
+so ideally you should never have to customize the option
+‘with-editor-emacsclient-executable’. When it fails to do so, then the
+most likely reason is that someone found yet another way to package
+Emacs (most likely on OS X) without putting the executable on ‘$PATH’,
+and we have to add another kludge to find it anyway.
+
+ -- User Option: with-editor-emacsclient-executable
+
+ The emacsclient executable used as the editor by child process of
+ this Emacs instance. By using this executable, child processes can
+ call home to their parent process.
+
+ This option is automatically set at startup by looking in
+ ‘exec-path’, and other places where the executable could be
+ installed, to find the emacsclient executable most suitable for the
+ current emacs instance.
+
+ You should *not* customize this option permanently. If you have to
+ do it, then you should consider that a temporary kludge and inform
+ the Magit maintainer as described in *note Debugging: Debugging.
+
+ If With-Editor fails to find a suitable emacsclient on you system,
+ then this should be fixed for all users at once, by teaching
+ ‘with-editor-locate-emacsclient’ how to so on your system and
+ system like yours. Doing it this way has the advantage, that you
+ won’t have do it again every time you update Emacs, and that other
+ users who have installed Emacs the same way as you have, won’t have
+ to go through the same trouble.
+
+ Note that there also is a nuclear option; setting this variable to
+ ‘nil’ causes the "sleeping editor" described below to be used even
+ for local child processes. Obviously we don’t recommend that you
+ use this except in "emergencies", i.e. before we had a change to
+ add a kludge appropriate for you setup.
+
+ -- Function: with-editor-locate-emacsclient
+
+ The function used to set the initial value of the option
+ ‘with-editor-emacsclient-executable’. There’s a lot of voodoo
+ here.
+
+ The emacsclient cannot be used when using Tramp to run a process on a
+remote machine. (Theoretically it could, but that would be hard to
+setup, very fragile, and rather insecure).
+
+ With-Editor provides an alternative "editor" which can be used by
+remote processes in much the same way as local processes use an
+emacsclient executable. This alternative is known as the "sleeping
+editor" because it is implemented as a shell script which sleeps until
+it receives a signal.
+
+ -- User Option: with-editor-sleeping-editor
+
+ The sleeping editor is a shell script used as the editor of child
+ processes when the emacsclient executable cannot be used.
+
+ This fallback is used for asynchronous process started inside the
+ macro ‘with-editor’, when the process runs on a remote machine or
+ for local processes when ‘with-editor-emacsclient-executable’ is
+ ‘nil’.
+
+ Where the latter uses a socket to communicate with Emacs’ server,
+ this substitute prints edit requests to its standard output on
+ which a process filter listens for such requests. As such it is
+ not a complete substitute for a proper Emacsclient, it can only be
+ used as ‘$EDITOR’ of child process of the current Emacs instance.
+
+ Some shells do not execute traps immediately when waiting for a
+ child process, but by default we do use such a blocking child
+ process.
+
+ If you use such a shell (e.g. ‘csh’ on FreeBSD, but not Debian),
+ then you have to edit this option. You can either replace ‘sh’
+ with ‘bash’ (and install that), or you can use the older, less
+ performant implementation:
+
+ "sh -c '\
+ echo \"WITH-EDITOR: $$ OPEN $0\"; \
+ trap \"exit 0\" USR1; \
+ trap \"exit 1\" USR2; \
+ while true; do sleep 1; done'"
+
+ This leads to a delay of up to a second. The delay can be
+ shortened by replacing ‘sleep 1’ with ‘sleep 0.01’, or if your
+ implementation does not support floats, then by using ‘nanosleep
+ 0.01’ instead.
+
+\1f
+File: with-editor.info, Node: Using With-Editor commands, Prev: Configuring With-Editor, Up: Using the With-Editor package
+
+1.2 Using With-Editor commands
+==============================
+
+This section describes how to use the ‘with-editor’ library _outside_ of
+Magit. You don’t need to know any of this just to create commits using
+Magit.
+
+ The commands ‘with-editor-async-shell-command’ and
+‘with-editor-shell-command’ are intended as drop in replacements for
+‘async-shell-command’ and ‘shell-command’. They automatically export
+‘$EDITOR’ making sure the executed command uses the current Emacs
+instance as "the editor". With a prefix argument these commands prompt
+for an alternative environment variable such as ‘$GIT_EDITOR’.
+
+ -- Command: with-editor-async-shell-command
+
+ Like ‘async-shell-command’, but the command is run with the current
+ Emacs instance exported as ‘$EDITOR’.
+
+ -- Command: with-editor-shell-command
+
+ Like ‘async-shell-command’, but the command is run with the current
+ Emacs instance exported as ‘$EDITOR’. This only has an effect if
+ the command is run asynchronously, i.e. when the command ends with
+ ‘&’.
+
+ To always use these variants add this to you init file:
+
+ (define-key (current-global-map)
+ [remap async-shell-command] 'with-editor-async-shell-command)
+ (define-key (current-global-map)
+ [remap shell-command] 'with-editor-shell-command)
+
+ Alternatively use the global ‘shell-command-with-editor-mode’.
+
+ -- Variable: shell-command-with-editor-mode
+
+ When this mode is active, then ‘$EDITOR’ is exported whenever
+ ultimately ‘shell-command’ is called to asynchronously run some
+ shell command. This affects most variants of that command, whether
+ they are defined in Emacs or in some third-party package.
+
+ The command ‘with-editor-export-editor’ exports ‘$EDITOR’ or another
+such environment variable in ‘shell-mode’, ‘term-mode’ and ‘eshell-mode’
+buffers. Use this Emacs command before executing a shell command which
+needs the editor set, or always arrange for the current Emacs instance
+to be used as editor by adding it to the appropriate mode hooks:
+
+ (add-hook 'shell-mode-hook 'with-editor-export-editor)
+ (add-hook 'term-exec-hook 'with-editor-export-editor)
+ (add-hook 'eshell-mode-hook 'with-editor-export-editor)
+
+ Some variants of this function exist; these two forms are equivalent:
+
+ (add-hook 'shell-mode-hook
+ (apply-partially 'with-editor-export-editor "GIT_EDITOR"))
+ (add-hook 'shell-mode-hook 'with-editor-export-git-editor)
+
+ -- Command: with-editor-export-editor
+
+ When invoked in a ‘shell-mode’, ‘term-mode’, or ‘eshell-mode’
+ buffer, this command teaches shell commands to use the current
+ Emacs instance as the editor, by exporting ‘$EDITOR’.
+
+ -- Command: with-editor-export-git-editor
+
+ Like ‘with-editor-export-editor’ but exports ‘$GIT_EDITOR’.
+
+ -- Command: with-editor-export-hg-editor
+
+ Like ‘with-editor-export-editor’ but exports ‘$HG_EDITOR’.
+
+\1f
+File: with-editor.info, Node: Using With-Editor as a library, Next: Debugging, Prev: Using the With-Editor package, Up: Top
+
+2 Using With-Editor as a library
+********************************
+
+This section describes how to use the with-editor library _outside_ of
+Magit to teach another package how to have its child processes call
+home, just like Magit does. You don’t need to know any of this just to
+create commits using Magit. You can also ignore this if you use
+‘with-editor’ outside of Magit, but only as an end-user.
+
+ For information about interactive use and options which affect both
+interactive and non-interactive use, see *note Using the With-Editor
+package: Using the With-Editor package.
+
+ -- Macro: with-editor &rest body
+
+ This macro arranges for the emacsclient or the sleeping editor to
+ be used as the editor of child processes, effectively teaching them
+ to call home to the current emacs instance when they require that
+ the user edits a file.
+
+ This is essentially done by establishing a local binding for
+ ‘process-environment’ and changing the value of the ‘$EDITOR’
+ environment variable. This affects all processes started by forms
+ inside BODY.
+
+ -- Function: with-editor-set-process-filter process filter
+
+ This function is like ‘set-process-filter’ but ensures that adding
+ the new FILTER does not remove the ‘with-editor-process-filter’.
+ This is done by wrapping the two filter functions using a lambda,
+ which becomes the actual filter. It calls
+ ‘with-editor-process-filter’ first, passing ‘t’ as
+ NO-STANDARD-FILTER. Then it calls FILTER.
+
+\1f
+File: with-editor.info, Node: Debugging, Prev: Using With-Editor as a library, Up: Top
+
+3 Debugging
+***********
+
+With-Editor tries very hard to locate a suitable emacsclient executable,
+and then sets option ‘with-editor-emacsclient-executable’ accordingly.
+In very rare cases this fails. When it does fail, then the most likely
+reason is that someone found yet another way to package Emacs (most
+likely on OS X) without putting the executable on ‘$PATH’, and we have
+to add another kludge to find it anyway.
+
+ If you are having problems using ‘with-editor’, e.g. you cannot
+commit in Magit, then please open a new issue at
+<https://github.com/magit/with-editor/issues> and provide information
+about your Emacs installation. Most importantly how did you install
+Emacs and what is the output of ‘M-x with-editor-debug’?
+
+
+\1f
+Tag Table:
+Node: Top\7f1545
+Node: Using the With-Editor package\7f3236
+Node: Configuring With-Editor\7f3852
+Node: Using With-Editor commands\7f8201
+Node: Using With-Editor as a library\7f11364
+Node: Debugging\7f13036
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End: