magit-stash.el (26489B)
1 ;;; magit-stash.el --- Stash support for Magit -*- lexical-binding:t -*- 2 3 ;; Copyright (C) 2008-2024 The Magit Project Contributors 4 5 ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> 6 ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> 7 8 ;; SPDX-License-Identifier: GPL-3.0-or-later 9 10 ;; Magit is free software: you can redistribute it and/or modify it 11 ;; under the terms of the GNU General Public License as published by 12 ;; the Free Software Foundation, either version 3 of the License, or 13 ;; (at your option) any later version. 14 ;; 15 ;; Magit is distributed in the hope that it will be useful, but WITHOUT 16 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 18 ;; License for more details. 19 ;; 20 ;; You should have received a copy of the GNU General Public License 21 ;; along with Magit. If not, see <https://www.gnu.org/licenses/>. 22 23 ;;; Commentary: 24 25 ;; Support for Git stashes. 26 27 ;;; Code: 28 29 (require 'magit) 30 (require 'magit-reflog) 31 (require 'magit-sequence) 32 33 ;;; Options 34 35 (defgroup magit-stash nil 36 "List stashes and show stash diffs." 37 :group 'magit-modes) 38 39 ;;;; Diff options 40 41 (defcustom magit-stash-sections-hook 42 '(magit-insert-stash-notes 43 magit-insert-stash-worktree 44 magit-insert-stash-index 45 magit-insert-stash-untracked) 46 "Hook run to insert sections into stash diff buffers." 47 :package-version '(magit . "2.1.0") 48 :group 'magit-stash 49 :type 'hook) 50 51 ;;;; Log options 52 53 (defcustom magit-stashes-margin 54 (list (nth 0 magit-log-margin) 55 (nth 1 magit-log-margin) 56 'magit-log-margin-width nil 57 (nth 4 magit-log-margin)) 58 "Format of the margin in `magit-stashes-mode' buffers. 59 60 The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). 61 62 If INIT is non-nil, then the margin is shown initially. 63 STYLE controls how to format the author or committer date. 64 It can be one of `age' (to show the age of the commit), 65 `age-abbreviated' (to abbreviate the time unit to a character), 66 or a string (suitable for `format-time-string') to show the 67 actual date. Option `magit-log-margin-show-committer-date' 68 controls which date is being displayed. 69 WIDTH controls the width of the margin. This exists for forward 70 compatibility and currently the value should not be changed. 71 AUTHOR controls whether the name of the author is also shown by 72 default. 73 AUTHOR-WIDTH has to be an integer. When the name of the author 74 is shown, then this specifies how much space is used to do so." 75 :package-version '(magit . "2.9.0") 76 :group 'magit-stash 77 :group 'magit-margin 78 :type magit-log-margin--custom-type 79 :initialize #'magit-custom-initialize-reset 80 :set-after '(magit-log-margin) 81 :set (apply-partially #'magit-margin-set-variable 'magit-stashes-mode)) 82 83 ;;;; Variables 84 85 (defvar magit-stash-read-message-function #'magit-stash-read-message 86 "Function used to read the message when creating a stash.") 87 88 ;;; Commands 89 90 ;;;###autoload (autoload 'magit-stash "magit-stash" nil t) 91 (transient-define-prefix magit-stash () 92 "Stash uncommitted changes." 93 :man-page "git-stash" 94 ["Arguments" 95 ("-u" "Also save untracked files" ("-u" "--include-untracked")) 96 ("-a" "Also save untracked and ignored files" ("-a" "--all"))] 97 [["Stash" 98 ("z" "both" magit-stash-both) 99 ("i" "index" magit-stash-index) 100 ("w" "worktree" magit-stash-worktree) 101 ("x" "keeping index" magit-stash-keep-index) 102 ("P" "push" magit-stash-push :level 5)] 103 ["Snapshot" 104 ("Z" "both" magit-snapshot-both) 105 ("I" "index" magit-snapshot-index) 106 ("W" "worktree" magit-snapshot-worktree) 107 ("r" "to wip ref" magit-wip-commit)] 108 ["Use" 109 ("a" "Apply" magit-stash-apply) 110 ("p" "Pop" magit-stash-pop) 111 ("k" "Drop" magit-stash-drop)] 112 ["Inspect" 113 ("l" "List" magit-stash-list) 114 ("v" "Show" magit-stash-show)] 115 ["Transform" 116 ("b" "Branch" magit-stash-branch) 117 ("B" "Branch here" magit-stash-branch-here) 118 ("f" "Format patch" magit-stash-format-patch)]]) 119 120 (defun magit-stash-arguments () 121 (transient-args 'magit-stash)) 122 123 ;;;###autoload 124 (defun magit-stash-both (message &optional include-untracked) 125 "Create a stash of the index and working tree. 126 Untracked files are included according to infix arguments. 127 One prefix argument is equivalent to `--include-untracked' 128 while two prefix arguments are equivalent to `--all'." 129 (interactive 130 (progn (when (and (magit-merge-in-progress-p) 131 (not (magit-y-or-n-p "\ 132 Stashing and resetting during a merge conflict. \ 133 Applying the resulting stash won't restore the merge state. \ 134 Proceed anyway? "))) 135 (user-error "Abort")) 136 (magit-stash-read-args))) 137 (magit-stash-save message t t include-untracked t)) 138 139 ;;;###autoload 140 (defun magit-stash-index (message) 141 "Create a stash of the index only. 142 Unstaged and untracked changes are not stashed. The stashed 143 changes are applied in reverse to both the index and the 144 worktree. This command can fail when the worktree is not clean. 145 Applying the resulting stash has the inverse effect." 146 (interactive (list (magit-stash-read-message))) 147 (magit-stash-save message t nil nil t 'worktree)) 148 149 ;;;###autoload 150 (defun magit-stash-worktree (message &optional include-untracked) 151 "Create a stash of unstaged changes in the working tree. 152 Untracked files are included according to infix arguments. 153 One prefix argument is equivalent to `--include-untracked' 154 while two prefix arguments are equivalent to `--all'." 155 (interactive (magit-stash-read-args)) 156 (magit-stash-save message nil t include-untracked t 'index)) 157 158 ;;;###autoload 159 (defun magit-stash-keep-index (message &optional include-untracked) 160 "Create a stash of the index and working tree, keeping index intact. 161 Untracked files are included according to infix arguments. 162 One prefix argument is equivalent to `--include-untracked' 163 while two prefix arguments are equivalent to `--all'." 164 (interactive (magit-stash-read-args)) 165 (magit-stash-save message t t include-untracked t 'index)) 166 167 (defun magit-stash-read-args () 168 (list (funcall magit-stash-read-message-function) 169 (magit-stash-read-untracked))) 170 171 (defun magit-stash-read-message () 172 "Read a message from the minibuffer, to be used for a stash. 173 174 The message that Git would have picked, is available as the 175 default (used when the user enters the empty string) and as 176 the next history element (which can be accessed with \ 177 \\<minibuffer-local-map>\\[next-history-element])." 178 (read-string (format "Stash message (default: On%s:%s): " 179 (magit--ellipsis) (magit--ellipsis)) 180 nil nil 181 (format "On %s: %s" 182 (or (magit-get-current-branch) "(no branch)") 183 (magit-rev-format "%h %s")))) 184 185 (defun magit-stash-read-message-traditional () 186 "Read a message from the minibuffer, to be used for a stash. 187 188 If the user confirms the initial-input unmodified, then the 189 abbreviated commit hash and commit summary are appended. 190 The resulting message is what Git would have used." 191 (let* ((default (format "On %s: " 192 (or (magit-get-current-branch) "(no branch)"))) 193 (input (magit-read-string "Stash message" default))) 194 (if (equal input default) 195 (concat default (magit-rev-format "%h %s")) 196 input))) 197 198 (defun magit-stash-read-untracked () 199 (let ((prefix (prefix-numeric-value current-prefix-arg)) 200 (args (magit-stash-arguments))) 201 (cond ((or (= prefix 16) (member "--all" args)) 'all) 202 ((or (= prefix 4) (member "--include-untracked" args)) t)))) 203 204 ;;;###autoload 205 (defun magit-snapshot-both (&optional include-untracked) 206 "Create a snapshot of the index and working tree. 207 Untracked files are included according to infix arguments. 208 One prefix argument is equivalent to `--include-untracked' 209 while two prefix arguments are equivalent to `--all'." 210 (interactive (magit-snapshot-read-args)) 211 (magit-snapshot-save t t include-untracked t)) 212 213 ;;;###autoload 214 (defun magit-snapshot-index () 215 "Create a snapshot of the index only. 216 Unstaged and untracked changes are not stashed." 217 (interactive) 218 (magit-snapshot-save t nil nil t)) 219 220 ;;;###autoload 221 (defun magit-snapshot-worktree (&optional include-untracked) 222 "Create a snapshot of unstaged changes in the working tree. 223 Untracked files are included according to infix arguments. 224 One prefix argument is equivalent to `--include-untracked' 225 while two prefix arguments are equivalent to `--all'." 226 (interactive (magit-snapshot-read-args)) 227 (magit-snapshot-save nil t include-untracked t)) 228 229 (defun magit-snapshot-read-args () 230 (list (magit-stash-read-untracked))) 231 232 (defun magit-snapshot-save (index worktree untracked &optional refresh) 233 (magit-stash-save (concat "WIP on " (magit-stash-summary)) 234 index worktree untracked refresh t)) 235 236 ;;;###autoload (autoload 'magit-stash-push "magit-stash" nil t) 237 (transient-define-prefix magit-stash-push (&optional transient args) 238 "Create stash using \"git stash push\". 239 240 This differs from Magit's other stashing commands, which don't 241 use \"git stash\" and are generally more flexible but don't allow 242 specifying a list of files to be stashed." 243 :man-page "git-stash" 244 ["Arguments" 245 (magit:-- :reader (lambda (prompt initial-input history) 246 (magit-read-files prompt initial-input history 247 #'magit-modified-files))) 248 ("-u" "Also save untracked files" ("-u" "--include-untracked")) 249 ("-a" "Also save untracked and ignored files" ("-a" "--all")) 250 ("-k" "Keep index" ("-k" "--keep-index")) 251 ("-K" "Don't keep index" "--no-keep-index")] 252 ["Actions" 253 ("P" "push" magit-stash-push)] 254 (interactive (if (eq transient-current-command 'magit-stash-push) 255 (list nil (transient-args 'magit-stash-push)) 256 (list t))) 257 (if transient 258 (transient-setup 'magit-stash-push) 259 (magit-run-git "stash" "push" args))) 260 261 ;;;###autoload 262 (defun magit-stash-apply (stash) 263 "Apply a stash to the working tree. 264 265 First try \"git stash apply --index\", which tries to preserve 266 the index stored in the stash, if any. This may fail because 267 applying the stash could result in conflicts and those have to 268 be stored in the index, making it impossible to also store the 269 stash's index there as well. 270 271 If the above failed, then try \"git stash apply\". This fails 272 \(with or without \"--index\") if there are any uncommitted 273 changes to files that are also modified in the stash. 274 275 If both of the above failed, then apply using \"git apply\". 276 If there are no conflicting files, use \"--3way\". If there are 277 conflicting files, then using \"--3way\" requires that those 278 files are staged first, which may be undesirable, so prompt 279 the user whether to use \"--3way\" or \"--reject\"." 280 (interactive (list (magit-read-stash "Apply stash"))) 281 (magit-stash--apply "apply" stash)) 282 283 ;;;###autoload 284 (defun magit-stash-pop (stash) 285 "Apply a stash to the working tree, on success remove it from stash list. 286 287 First try \"git stash pop --index\", which tries to preserve 288 the index stored in the stash, if any. This may fail because 289 applying the stash could result in conflicts and those have to 290 be stored in the index, making it impossible to also store the 291 stash's index there as well. 292 293 If the above failed, then try \"git stash apply\". This fails 294 \(with or without \"--index\") if there are any uncommitted 295 changes to files that are also modified in the stash. 296 297 If both of the above failed, then apply using \"git apply\". 298 If there are no conflicting files, use \"--3way\". If there are 299 conflicting files, then using \"--3way\" requires that those 300 files are staged first, which may be undesirable, so prompt 301 the user whether to use \"--3way\" or \"--reject\"." 302 (interactive (list (magit-read-stash "Pop stash"))) 303 (magit-stash--apply "pop" stash)) 304 305 (defun magit-stash--apply (action stash) 306 (or (= (magit-call-git "stash" action "--index" stash) 0) 307 ;; The stash's index could not be applied, so always keep the stash. 308 (= (magit-call-git "stash" "apply" stash) 0) 309 (let* ((range (format "%s^..%s" stash stash)) 310 (stashed (magit-git-items "diff" "-z" "--name-only" range "--")) 311 (conflicts (cl-sort (cl-union (magit-unstaged-files t stashed) 312 (magit-untracked-files t stashed) 313 :test #'equal) 314 #'string<)) 315 (arg (cond 316 ((not conflicts) "--3way") 317 ((magit-confirm-files 318 'stash-apply-3way conflicts 319 "Apply stash using `--3way', which requires first staging" 320 "(else use `--reject')" 321 t) 322 (magit-stage-1 nil conflicts) 323 "--3way") 324 ("--reject")))) 325 (with-temp-buffer 326 (magit-git-insert "diff" range) 327 (magit-run-git-with-input "apply" arg "-")))) 328 (magit-refresh)) 329 330 ;;;###autoload 331 (defun magit-stash-drop (stash) 332 "Remove a stash from the stash list. 333 When the region is active offer to drop all contained stashes." 334 (interactive 335 (list (if-let ((values (magit-region-values 'stash))) 336 (magit-confirm 'drop-stashes nil "Drop %d stashes" nil values) 337 (magit-read-stash "Drop stash")))) 338 (dolist (stash (if (listp stash) 339 (nreverse (prog1 stash (setq stash (car stash)))) 340 (list stash))) 341 (message "Deleted refs/%s (was %s)" stash 342 (magit-rev-parse "--short" stash)) 343 (magit-call-git "rev-parse" stash) 344 (magit-call-git "stash" "drop" stash)) 345 (magit-refresh)) 346 347 ;;;###autoload 348 (defun magit-stash-clear (ref) 349 "Remove all stashes saved in REF's reflog by deleting REF." 350 (interactive (let ((ref (or (magit-section-value-if 'stashes) "refs/stash"))) 351 (magit-confirm t (list "Drop all stashes in %s" ref)) 352 (list ref))) 353 (magit-run-git "update-ref" "-d" ref)) 354 355 ;;;###autoload 356 (defun magit-stash-branch (stash branch) 357 "Create and checkout a new BRANCH from an existing STASH. 358 The new branch starts at the commit that was current when the 359 stash was created. If the stash applies cleanly, then drop it." 360 (interactive (list (magit-read-stash "Branch stash") 361 (magit-read-string-ns "Branch name"))) 362 (magit-run-git "stash" "branch" branch stash)) 363 364 ;;;###autoload 365 (defun magit-stash-branch-here (stash branch) 366 "Create and checkout a new BRANCH from an existing STASH. 367 Use the current branch or `HEAD' as the starting-point of BRANCH. 368 Then apply STASH, dropping it if it applies cleanly." 369 (interactive (list (magit-read-stash "Branch stash") 370 (magit-read-string-ns "Branch name"))) 371 (let ((start-point (or (magit-get-current-branch) "HEAD"))) 372 (magit-call-git "checkout" "-b" branch start-point) 373 (magit-branch-maybe-adjust-upstream branch start-point)) 374 (magit-stash-apply stash)) 375 376 ;;;###autoload 377 (defun magit-stash-format-patch (stash) 378 "Create a patch from STASH" 379 (interactive (list (magit-read-stash "Create patch from stash"))) 380 (with-temp-file (magit-rev-format "0001-%f.patch" stash) 381 (magit-git-insert "stash" "show" "-p" stash)) 382 (magit-refresh)) 383 384 ;;; Plumbing 385 386 (defun magit-stash-save (message index worktree untracked 387 &optional refresh keep noerror ref) 388 (if (or (and index (magit-staged-files t)) 389 (and worktree (magit-unstaged-files t)) 390 (and untracked (magit-untracked-files (eq untracked 'all)))) 391 (magit-with-toplevel 392 (magit-stash-store message (or ref "refs/stash") 393 (magit-stash-create message index worktree untracked)) 394 (if (eq keep 'worktree) 395 (with-temp-buffer 396 (magit-git-insert "diff" "--cached" "--no-ext-diff") 397 (magit-run-git-with-input 398 "apply" "--reverse" "--cached" "--ignore-space-change" "-") 399 (magit-run-git-with-input 400 "apply" "--reverse" "--ignore-space-change" "-")) 401 (unless (eq keep t) 402 (if (eq keep 'index) 403 (magit-call-git "checkout" "--" ".") 404 (magit-call-git "reset" "--hard" "HEAD" "--")) 405 (when untracked 406 (magit-call-git "clean" "--force" "-d" 407 (and (eq untracked 'all) "-x"))))) 408 (when refresh 409 (magit-refresh))) 410 (unless noerror 411 (user-error "No %s changes to save" (cond ((not index) "unstaged") 412 ((not worktree) "staged") 413 (t "local")))))) 414 415 (defun magit-stash-store (message ref commit) 416 (magit-update-ref ref message commit t)) 417 418 (defun magit-stash-create (message index worktree untracked) 419 (unless (magit-rev-parse "--verify" "HEAD") 420 (error "You do not have the initial commit yet")) 421 (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false") 422 magit-git-global-arguments)) 423 (default-directory (magit-toplevel)) 424 (summary (magit-stash-summary)) 425 (head "HEAD")) 426 (when (and worktree (not index)) 427 (setq head (or (magit-commit-tree "pre-stash index" nil "HEAD") 428 (error "Cannot save the current index state")))) 429 (or (setq index (magit-commit-tree (concat "index on " summary) nil head)) 430 (error "Cannot save the current index state")) 431 (and untracked 432 (setq untracked (magit-untracked-files (eq untracked 'all))) 433 (setq untracked (magit-with-temp-index nil nil 434 (or (and (magit-update-files untracked) 435 (magit-commit-tree 436 (concat "untracked files on " summary))) 437 (error "Cannot save the untracked files"))))) 438 (magit-with-temp-index index "-m" 439 (when worktree 440 (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head)) 441 (error "Cannot save the current worktree state"))) 442 (or (magit-commit-tree message nil head index untracked) 443 (error "Cannot save the current worktree state"))))) 444 445 (defun magit-stash-summary () 446 (concat (or (magit-get-current-branch) "(no branch)") 447 ": " (magit-rev-format "%h %s"))) 448 449 ;;; Sections 450 451 (defvar-keymap magit-stashes-section-map 452 :doc "Keymap for `stashes' section." 453 "<remap> <magit-delete-thing>" #'magit-stash-clear 454 "<remap> <magit-visit-thing>" #'magit-stash-list 455 "<2>" (magit-menu-item "Clear %t" #'magit-stash-clear) 456 "<1>" (magit-menu-item "List %t" #'magit-stash-list)) 457 458 (defvar-keymap magit-stash-section-map 459 :doc "Keymap for `stash' sections." 460 "<remap> <magit-cherry-pick>" #'magit-stash-pop 461 "<remap> <magit-cherry-apply>" #'magit-stash-apply 462 "<remap> <magit-delete-thing>" #'magit-stash-drop 463 "<remap> <magit-visit-thing>" #'magit-stash-show 464 "<4>" (magit-menu-item "Pop %M" #'magit-stash-pop) 465 "<3>" (magit-menu-item "Apply %M" #'magit-stash-apply) 466 "<2>" (magit-menu-item "Delete %M" #'magit-stash-drop) 467 "<1>" (magit-menu-item "Visit %v" #'magit-stash-show)) 468 469 (magit-define-section-jumper magit-jump-to-stashes 470 "Stashes" stashes "refs/stash" magit-insert-stashes) 471 472 (cl-defun magit-insert-stashes (&optional (ref "refs/stash") 473 (heading "Stashes:")) 474 "Insert `stashes' section showing reflog for \"refs/stash\". 475 If optional REF is non-nil, show reflog for that instead. 476 If optional HEADING is non-nil, use that as section heading 477 instead of \"Stashes:\"." 478 (let ((verified (magit-rev-verify ref)) 479 (autostash (magit-rebase--get-state-lines "autostash"))) 480 (when (or autostash verified) 481 (magit-insert-section (stashes ref) 482 (magit-insert-heading heading) 483 (when autostash 484 (pcase-let ((`(,author ,date ,msg) 485 (split-string 486 (car (magit-git-lines 487 "show" "-q" "--format=%aN%x00%at%x00%s" 488 autostash)) 489 "\0"))) 490 (magit-insert-section (stash autostash) 491 (insert (propertize "AUTOSTASH" 'font-lock-face 'magit-hash)) 492 (insert " " msg "\n") 493 (save-excursion 494 (backward-char) 495 (magit-log-format-margin autostash author date))))) 496 (if verified 497 (magit-git-wash (apply-partially #'magit-log-wash-log 'stash) 498 "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" ref) 499 (insert ?\n) 500 (save-excursion 501 (backward-char) 502 (magit-make-margin-overlay))))))) 503 504 ;;; List Stashes 505 506 ;;;###autoload 507 (defun magit-stash-list () 508 "List all stashes in a buffer." 509 (interactive) 510 (magit-stashes-setup-buffer)) 511 512 (define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes" 513 "Mode for looking at lists of stashes." 514 :interactive nil 515 :group 'magit-log 516 (magit-hack-dir-local-variables)) 517 518 (defun magit-stashes-setup-buffer () 519 (magit-setup-buffer #'magit-stashes-mode nil 520 (magit-buffer-refname "refs/stash"))) 521 522 (defun magit-stashes-refresh-buffer () 523 (magit-insert-section (stashesbuf) 524 (magit-insert-heading t 525 (if (equal magit-buffer-refname "refs/stash") 526 "Stashes" 527 (format "Stashes [%s]" magit-buffer-refname))) 528 (magit-git-wash (apply-partially #'magit-log-wash-log 'stash) 529 "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" magit-buffer-refname))) 530 531 (cl-defmethod magit-buffer-value (&context (major-mode magit-stashes-mode)) 532 magit-buffer-refname) 533 534 (defvar magit--update-stash-buffer nil) 535 536 (defun magit-stashes-maybe-update-stash-buffer (&optional _) 537 "When moving in the stashes buffer, update the stash buffer. 538 If there is no stash buffer in the same frame, then do nothing." 539 (when (derived-mode-p 'magit-stashes-mode) 540 (magit--maybe-update-stash-buffer))) 541 542 (defun magit--maybe-update-stash-buffer () 543 (when-let* ((stash (magit-section-value-if 'stash)) 544 (buffer (magit-get-mode-buffer 'magit-stash-mode nil t))) 545 (if magit--update-stash-buffer 546 (setq magit--update-stash-buffer (list stash buffer)) 547 (setq magit--update-stash-buffer (list stash buffer)) 548 (run-with-idle-timer 549 magit-update-other-window-delay nil 550 (let ((args (with-current-buffer buffer 551 (let ((magit-direct-use-buffer-arguments 'selected)) 552 (magit-show-commit--arguments))))) 553 (lambda () 554 (pcase-let ((`(,stash ,buf) magit--update-stash-buffer)) 555 (setq magit--update-stash-buffer nil) 556 (when (buffer-live-p buf) 557 (let ((magit-display-buffer-noselect t)) 558 (apply #'magit-stash-show stash args)))) 559 (setq magit--update-stash-buffer nil))))))) 560 561 ;;; Show Stash 562 563 ;;;###autoload 564 (defun magit-stash-show (stash &optional args files) 565 "Show all diffs of a stash in a buffer." 566 (interactive (cons (or (and (not current-prefix-arg) 567 (magit-stash-at-point)) 568 (magit-read-stash "Show stash")) 569 (pcase-let ((`(,args ,files) 570 (magit-diff-arguments 'magit-stash-mode))) 571 (list (delete "--stat" args) files)))) 572 (magit-stash-setup-buffer stash args files)) 573 574 (define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash" 575 "Mode for looking at individual stashes." 576 :interactive nil 577 :group 'magit-diff 578 (magit-hack-dir-local-variables) 579 (setq magit--imenu-group-types '(commit))) 580 581 (defun magit-stash-setup-buffer (stash args files) 582 (magit-setup-buffer #'magit-stash-mode nil 583 (magit-buffer-revision stash) 584 (magit-buffer-range (format "%s^..%s" stash stash)) 585 (magit-buffer-diff-args args) 586 (magit-buffer-diff-files files))) 587 588 (defun magit-stash-refresh-buffer () 589 (magit-set-header-line-format 590 (concat (capitalize magit-buffer-revision) " " 591 (propertize (magit-rev-format "%s" magit-buffer-revision) 592 'font-lock-face 593 (list :weight 'normal :foreground 594 (face-attribute 'default :foreground))))) 595 (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision)) 596 (magit-insert-section (stash) 597 (magit-run-section-hook 'magit-stash-sections-hook))) 598 599 (cl-defmethod magit-buffer-value (&context (major-mode magit-stash-mode)) 600 magit-buffer-revision) 601 602 (defun magit-stash-insert-section (commit range message &optional files) 603 (magit-insert-section (commit commit) 604 (magit-insert-heading message) 605 (magit--insert-diff nil 606 "diff" range "-p" "--no-prefix" magit-buffer-diff-args 607 "--" (or files magit-buffer-diff-files)))) 608 609 (defun magit-insert-stash-notes () 610 "Insert section showing notes for a stash. 611 This shows the notes for stash@{N} but not for the other commits 612 that make up the stash." 613 (magit-insert-section (note) 614 (magit-insert-heading t "Notes") 615 (magit-git-insert "notes" "show" magit-buffer-revision) 616 (magit-cancel-section 'if-empty) 617 (insert "\n"))) 618 619 (defun magit-insert-stash-index () 620 "Insert section showing staged changes of the stash." 621 (magit-stash-insert-section 622 (format "%s^2" magit-buffer-revision) 623 (format "%s^..%s^2" magit-buffer-revision magit-buffer-revision) 624 "Staged")) 625 626 (defun magit-insert-stash-worktree () 627 "Insert section showing unstaged changes of the stash." 628 (magit-stash-insert-section 629 magit-buffer-revision 630 (format "%s^2..%s" magit-buffer-revision magit-buffer-revision) 631 "Unstaged")) 632 633 (defun magit-insert-stash-untracked () 634 "Insert section showing the untracked files commit of the stash." 635 (let ((stash magit-buffer-revision) 636 (rev (concat magit-buffer-revision "^3"))) 637 (when (magit-rev-verify rev) 638 (magit-stash-insert-section (format "%s^3" stash) 639 (format "%s^..%s^3" stash stash) 640 "Untracked files" 641 (magit-git-items "ls-tree" "-z" "--name-only" 642 "-r" "--full-tree" rev))))) 643 644 ;;; _ 645 (provide 'magit-stash) 646 ;;; magit-stash.el ends here