config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

magit-gitignore.el (7606B)


      1 ;;; magit-gitignore.el --- Intentionally untracked files  -*- 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 ;; This library implements gitignore commands.
     26 
     27 ;;; Code:
     28 
     29 (require 'magit)
     30 
     31 ;;; Transient
     32 
     33 ;;;###autoload (autoload 'magit-gitignore "magit-gitignore" nil t)
     34 (transient-define-prefix magit-gitignore ()
     35   "Instruct Git to ignore a file or pattern."
     36   :man-page "gitignore"
     37   ["Gitignore"
     38    ("t" "shared at toplevel (.gitignore)"
     39     magit-gitignore-in-topdir)
     40    ("s" "shared in subdirectory (path/to/.gitignore)"
     41     magit-gitignore-in-subdir)
     42    ("p" "privately (.git/info/exclude)"
     43     magit-gitignore-in-gitdir)
     44    ("g" magit-gitignore-on-system
     45     :if (lambda () (magit-get "core.excludesfile"))
     46     :description (lambda ()
     47                    (format "privately for all repositories (%s)"
     48                            (magit-get "core.excludesfile"))))]
     49   ["Skip worktree"
     50    (7 "w" "do skip worktree"     magit-skip-worktree)
     51    (7 "W" "do not skip worktree" magit-no-skip-worktree)]
     52   ["Assume unchanged"
     53    (7 "u" "do assume unchanged"     magit-assume-unchanged)
     54    (7 "U" "do not assume unchanged" magit-no-assume-unchanged)])
     55 
     56 ;;; Gitignore Commands
     57 
     58 ;;;###autoload
     59 (defun magit-gitignore-in-topdir (rule)
     60   "Add the Git ignore RULE to the top-level \".gitignore\" file.
     61 Since this file is tracked, it is shared with other clones of the
     62 repository.  Also stage the file."
     63   (interactive (list (magit-gitignore-read-pattern)))
     64   (magit-with-toplevel
     65     (magit--gitignore rule ".gitignore")
     66     (magit-run-git "add" ".gitignore")))
     67 
     68 ;;;###autoload
     69 (defun magit-gitignore-in-subdir (rule directory)
     70   "Add the Git ignore RULE to a \".gitignore\" file in DIRECTORY.
     71 Prompt the user for a directory and add the rule to the
     72 \".gitignore\" file in that directory.  Since such files are
     73 tracked, they are shared with other clones of the repository.
     74 Also stage the file."
     75   (interactive (list (magit-gitignore-read-pattern)
     76                      (read-directory-name "Limit rule to files in: ")))
     77   (magit-with-toplevel
     78     (let ((file (expand-file-name ".gitignore" directory)))
     79       (magit--gitignore rule file)
     80       (magit-run-git "add" (magit-convert-filename-for-git file)))))
     81 
     82 ;;;###autoload
     83 (defun magit-gitignore-in-gitdir (rule)
     84   "Add the Git ignore RULE to \"$GIT_DIR/info/exclude\".
     85 Rules in that file only affects this clone of the repository."
     86   (interactive (list (magit-gitignore-read-pattern)))
     87   (magit--gitignore rule (expand-file-name "info/exclude" (magit-gitdir)))
     88   (magit-refresh))
     89 
     90 ;;;###autoload
     91 (defun magit-gitignore-on-system (rule)
     92   "Add the Git ignore RULE to the file specified by `core.excludesFile'.
     93 Rules that are defined in that file affect all local repositories."
     94   (interactive (list (magit-gitignore-read-pattern)))
     95   (magit--gitignore rule
     96                     (or (magit-get "core.excludesFile")
     97                         (error "Variable `core.excludesFile' isn't set")))
     98   (magit-refresh))
     99 
    100 (defun magit--gitignore (rule file)
    101   (when-let ((directory (file-name-directory file)))
    102     (make-directory directory t))
    103   (with-temp-buffer
    104     (when (file-exists-p file)
    105       (insert-file-contents file))
    106     (goto-char (point-max))
    107     (unless (bolp)
    108       (insert "\n"))
    109     (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule))
    110     (insert "\n")
    111     (write-region nil nil file)))
    112 
    113 (defun magit-gitignore-read-pattern ()
    114   (let* ((default (magit-current-file))
    115          (base (car magit-buffer-diff-files))
    116          (base (and base (file-directory-p base) base))
    117          (choices
    118           (delete-dups
    119            (--mapcat
    120             (cons (concat "/" it)
    121                   (and-let* ((ext (file-name-extension it)))
    122                     (list (concat "/" (file-name-directory it) "*." ext)
    123                           (concat "*." ext))))
    124             (sort (nconc
    125                    (magit-untracked-files nil base)
    126                    ;; The untracked section of the status buffer lists
    127                    ;; directories containing only untracked files.
    128                    ;; Add those as candidates.
    129                    (seq-filter #'directory-name-p
    130                                (magit-list-files
    131                                 "--other" "--exclude-standard" "--directory"
    132                                 "--no-empty-directory" "--" base)))
    133                   #'string-lessp)))))
    134     (when default
    135       (setq default (concat "/" default))
    136       (unless (member default choices)
    137         (setq default (concat "*." (file-name-extension default)))
    138         (unless (member default choices)
    139           (setq default nil))))
    140     (magit-completing-read "File or pattern to ignore"
    141                            choices nil nil nil nil default)))
    142 
    143 ;;; Skip Worktree Commands
    144 
    145 ;;;###autoload
    146 (defun magit-skip-worktree (file)
    147   "Call \"git update-index --skip-worktree -- FILE\"."
    148   (interactive
    149    (list (magit-read-file-choice "Skip worktree for"
    150                                  (magit-with-toplevel
    151                                    (cl-set-difference
    152                                     (magit-list-files)
    153                                     (magit-skip-worktree-files)
    154                                     :test #'equal)))))
    155   (magit-with-toplevel
    156     (magit-run-git "update-index" "--skip-worktree" "--" file)))
    157 
    158 ;;;###autoload
    159 (defun magit-no-skip-worktree (file)
    160   "Call \"git update-index --no-skip-worktree -- FILE\"."
    161   (interactive
    162    (list (magit-read-file-choice "Do not skip worktree for"
    163                                  (magit-with-toplevel
    164                                    (magit-skip-worktree-files)))))
    165   (magit-with-toplevel
    166     (magit-run-git "update-index" "--no-skip-worktree" "--" file)))
    167 
    168 ;;; Assume Unchanged Commands
    169 
    170 ;;;###autoload
    171 (defun magit-assume-unchanged (file)
    172   "Call \"git update-index --assume-unchanged -- FILE\"."
    173   (interactive
    174    (list (magit-read-file-choice "Assume file to be unchanged"
    175                                  (magit-with-toplevel
    176                                    (cl-set-difference
    177                                     (magit-list-files)
    178                                     (magit-assume-unchanged-files)
    179                                     :test #'equal)))))
    180   (magit-with-toplevel
    181     (magit-run-git "update-index" "--assume-unchanged" "--" file)))
    182 
    183 ;;;###autoload
    184 (defun magit-no-assume-unchanged (file)
    185   "Call \"git update-index --no-assume-unchanged -- FILE\"."
    186   (interactive
    187    (list (magit-read-file-choice "Do not assume file to be unchanged"
    188                                  (magit-with-toplevel
    189                                    (magit-assume-unchanged-files)))))
    190   (magit-with-toplevel
    191     (magit-run-git "update-index" "--no-assume-unchanged" "--" file)))
    192 
    193 ;;; _
    194 (provide 'magit-gitignore)
    195 ;;; magit-gitignore.el ends here