magit-gitignore.el (7561B)
1 ;;; magit-gitignore.el --- intentionally untracked files -*- lexical-binding: t -*- 2 3 ;; Copyright (C) 2008-2021 The Magit Project Contributors 4 ;; 5 ;; You should have received a copy of the AUTHORS.md file which 6 ;; lists all contributors. If not, see http://magit.vc/authors. 7 8 ;; Author: Jonas Bernoulli <jonas@bernoul.li> 9 ;; Maintainer: Jonas Bernoulli <jonas@bernoul.li> 10 11 ;; SPDX-License-Identifier: GPL-3.0-or-later 12 13 ;; Magit is free software; you can redistribute it and/or modify it 14 ;; under the terms of the GNU General Public License as published by 15 ;; the Free Software Foundation; either version 3, or (at your option) 16 ;; any later version. 17 ;; 18 ;; Magit is distributed in the hope that it will be useful, but WITHOUT 19 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 20 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 21 ;; License for more details. 22 ;; 23 ;; You should have received a copy of the GNU General Public License 24 ;; along with Magit. If not, see http://www.gnu.org/licenses. 25 26 ;;; Commentary: 27 28 ;; This library implements gitignore commands. 29 30 ;;; Code: 31 32 (require 'magit) 33 34 ;;; Transient 35 36 ;;;###autoload (autoload 'magit-gitignore "magit-gitignore" nil t) 37 (transient-define-prefix magit-gitignore () 38 "Instruct Git to ignore a file or pattern." 39 :man-page "gitignore" 40 ["Gitignore" 41 ("t" "shared at toplevel (.gitignore)" 42 magit-gitignore-in-topdir) 43 ("s" "shared in subdirectory (path/to/.gitignore)" 44 magit-gitignore-in-subdir) 45 ("p" "privately (.git/info/exclude)" 46 magit-gitignore-in-gitdir) 47 ("g" magit-gitignore-on-system 48 :if (lambda () (magit-get "core.excludesfile")) 49 :description (lambda () 50 (format "privately for all repositories (%s)" 51 (magit-get "core.excludesfile"))))] 52 ["Skip worktree" 53 (7 "w" "do skip worktree" magit-skip-worktree) 54 (7 "W" "do not skip worktree" magit-no-skip-worktree)] 55 ["Assume unchanged" 56 (7 "u" "do assume unchanged" magit-assume-unchanged) 57 (7 "U" "do not assume unchanged" magit-no-assume-unchanged)]) 58 59 ;;; Gitignore Commands 60 61 ;;;###autoload 62 (defun magit-gitignore-in-topdir (rule) 63 "Add the Git ignore RULE to the top-level \".gitignore\" file. 64 Since this file is tracked, it is shared with other clones of the 65 repository. Also stage the file." 66 (interactive (list (magit-gitignore-read-pattern))) 67 (magit-with-toplevel 68 (magit--gitignore rule ".gitignore") 69 (magit-run-git "add" ".gitignore"))) 70 71 ;;;###autoload 72 (defun magit-gitignore-in-subdir (rule directory) 73 "Add the Git ignore RULE to a \".gitignore\" file in DIRECTORY. 74 Prompt the user for a directory and add the rule to the 75 \".gitignore\" file in that directory. Since such files are 76 tracked, they are shared with other clones of the repository. 77 Also stage the file." 78 (interactive (list (magit-gitignore-read-pattern) 79 (read-directory-name "Limit rule to files in: "))) 80 (magit-with-toplevel 81 (let ((file (expand-file-name ".gitignore" directory))) 82 (magit--gitignore rule file) 83 (magit-run-git "add" (magit-convert-filename-for-git file))))) 84 85 ;;;###autoload 86 (defun magit-gitignore-in-gitdir (rule) 87 "Add the Git ignore RULE to \"$GIT_DIR/info/exclude\". 88 Rules in that file only affects this clone of the repository." 89 (interactive (list (magit-gitignore-read-pattern))) 90 (magit--gitignore rule (magit-git-dir "info/exclude")) 91 (magit-refresh)) 92 93 ;;;###autoload 94 (defun magit-gitignore-on-system (rule) 95 "Add the Git ignore RULE to the file specified by `core.excludesFile'. 96 Rules that are defined in that file affect all local repositories." 97 (interactive (list (magit-gitignore-read-pattern))) 98 (magit--gitignore rule 99 (or (magit-get "core.excludesFile") 100 (error "Variable `core.excludesFile' isn't set"))) 101 (magit-refresh)) 102 103 (defun magit--gitignore (rule file) 104 (when-let ((directory (file-name-directory file))) 105 (make-directory directory t)) 106 (with-temp-buffer 107 (when (file-exists-p file) 108 (insert-file-contents file)) 109 (goto-char (point-max)) 110 (unless (bolp) 111 (insert "\n")) 112 (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule)) 113 (insert "\n") 114 (write-region nil nil file))) 115 116 (defun magit-gitignore-read-pattern () 117 (let* ((default (magit-current-file)) 118 (base (car magit-buffer-diff-files)) 119 (base (and base (file-directory-p base) base)) 120 (choices 121 (delete-dups 122 (--mapcat 123 (cons (concat "/" it) 124 (when-let ((ext (file-name-extension it))) 125 (list (concat "/" (file-name-directory it) "*." ext) 126 (concat "*." ext)))) 127 (sort (nconc 128 (magit-untracked-files nil base) 129 ;; The untracked section of the status buffer lists 130 ;; directories containing only untracked files. 131 ;; Add those as candidates. 132 (-filter #'directory-name-p 133 (magit-list-files 134 "--other" "--exclude-standard" "--directory" 135 "--no-empty-directory" "--" base))) 136 #'string-lessp))))) 137 (when default 138 (setq default (concat "/" default)) 139 (unless (member default choices) 140 (setq default (concat "*." (file-name-extension default))) 141 (unless (member default choices) 142 (setq default nil)))) 143 (magit-completing-read "File or pattern to ignore" 144 choices nil nil nil nil default))) 145 146 ;;; Skip Worktree Commands 147 148 ;;;###autoload 149 (defun magit-skip-worktree (file) 150 "Call \"git update-index --skip-worktree -- FILE\"." 151 (interactive 152 (list (magit-read-file-choice "Skip worktree for" 153 (magit-with-toplevel 154 (cl-set-difference 155 (magit-list-files) 156 (magit-skip-worktree-files)))))) 157 (magit-with-toplevel 158 (magit-run-git "update-index" "--skip-worktree" "--" file))) 159 160 ;;;###autoload 161 (defun magit-no-skip-worktree (file) 162 "Call \"git update-index --no-skip-worktree -- FILE\"." 163 (interactive 164 (list (magit-read-file-choice "Do not skip worktree for" 165 (magit-with-toplevel 166 (magit-skip-worktree-files))))) 167 (magit-with-toplevel 168 (magit-run-git "update-index" "--no-skip-worktree" "--" file))) 169 170 ;;; Assume Unchanged Commands 171 172 ;;;###autoload 173 (defun magit-assume-unchanged (file) 174 "Call \"git update-index --assume-unchanged -- FILE\"." 175 (interactive 176 (list (magit-read-file-choice "Assume file to be unchanged" 177 (magit-with-toplevel 178 (cl-set-difference 179 (magit-list-files) 180 (magit-assume-unchanged-files)))))) 181 (magit-with-toplevel 182 (magit-run-git "update-index" "--assume-unchanged" "--" file))) 183 184 ;;;###autoload 185 (defun magit-no-assume-unchanged (file) 186 "Call \"git update-index --no-assume-unchanged -- FILE\"." 187 (interactive 188 (list (magit-read-file-choice "Do not assume file to be unchanged" 189 (magit-with-toplevel 190 (magit-assume-unchanged-files))))) 191 (magit-with-toplevel 192 (magit-run-git "update-index" "--no-assume-unchanged" "--" file))) 193 194 ;;; _ 195 (provide 'magit-gitignore) 196 ;;; magit-gitignore.el ends here