config

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

magit-sparse-checkout.el (6797B)


      1 ;;; magit-sparse-checkout.el --- Sparse checkout support for Magit  -*- lexical-binding:t -*-
      2 
      3 ;; Copyright (C) 2008-2024 The Magit Project Contributors
      4 
      5 ;; Author: Kyle Meyer <kyle@kyleam.com>
      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 provides an interface to the `git sparse-checkout'
     26 ;; command.  It's been possible to define sparse checkouts since Git
     27 ;; v1.7.0 by adding patterns to $GIT_DIR/info/sparse-checkout and
     28 ;; calling `git read-tree -mu HEAD' to update the index and working
     29 ;; tree.  However, Git v2.25 introduced the `git sparse-checkout'
     30 ;; command along with "cone mode", which restricts the possible
     31 ;; patterns to directories to provide better performance.
     32 ;;
     33 ;; The goal of this library is to support the `git sparse-checkout'
     34 ;; command operating in cone mode.
     35 
     36 ;;; Code:
     37 
     38 (require 'magit)
     39 
     40 ;;; Utilities
     41 
     42 (defun magit-sparse-checkout-enabled-p ()
     43   "Return non-nil if working tree is a sparse checkout."
     44   (magit-get-boolean "core.sparsecheckout"))
     45 
     46 (defun magit-sparse-checkout--assert-version ()
     47   ;; Older versions of Git have the ability to define sparse checkout
     48   ;; patterns in .git/info/sparse-checkout, but the sparse-checkout
     49   ;; command isn't available until 2.25.0.
     50   (when (magit-git-version< "2.25.0")
     51     (user-error "`git sparse-checkout' not available until Git v2.25")))
     52 
     53 (defun magit-sparse-checkout--auto-enable ()
     54   (if (magit-sparse-checkout-enabled-p)
     55       (unless (magit-get-boolean "core.sparsecheckoutcone")
     56         (user-error
     57          "Magit's sparse checkout functionality requires cone mode"))
     58     ;; Note: Don't use `magit-sparse-checkout-enable' because it's
     59     ;; asynchronous.
     60     (magit-run-git "sparse-checkout" "init" "--cone")))
     61 
     62 (defun magit-sparse-checkout-directories ()
     63   "Return directories that are recursively included in the sparse checkout.
     64 See the `git sparse-checkout' manpage for details about
     65 \"recursive\" versus \"parent\" directories in cone mode."
     66   (and (magit-get-boolean "core.sparsecheckoutcone")
     67        (mapcar #'file-name-as-directory
     68                (magit-git-lines "sparse-checkout" "list"))))
     69 
     70 ;;; Commands
     71 
     72 ;;;###autoload (autoload 'magit-sparse-checkout "magit-sparse-checkout" nil t)
     73 (transient-define-prefix magit-sparse-checkout ()
     74   "Create and manage sparse checkouts."
     75   :man-page "git-sparse-checkout"
     76   ["Arguments for enabling"
     77    :if-not magit-sparse-checkout-enabled-p
     78    ("-i" "Use sparse index" "--sparse-index")]
     79   ["Actions"
     80    [:if-not magit-sparse-checkout-enabled-p
     81     ("e" "Enable sparse checkout" magit-sparse-checkout-enable)]
     82    [:if magit-sparse-checkout-enabled-p
     83     ("d" "Disable sparse checkout" magit-sparse-checkout-disable)
     84     ("r" "Reapply rules" magit-sparse-checkout-reapply)]
     85    [("s" "Set directories" magit-sparse-checkout-set)
     86     ("a" "Add directories" magit-sparse-checkout-add)]])
     87 
     88 ;;;###autoload
     89 (defun magit-sparse-checkout-enable (&optional args)
     90   "Convert the working tree to a sparse checkout."
     91   (interactive (list (transient-args 'magit-sparse-checkout)))
     92   (magit-sparse-checkout--assert-version)
     93   (magit-run-git-async "sparse-checkout" "init" "--cone" args))
     94 
     95 ;;;###autoload
     96 (defun magit-sparse-checkout-set (directories)
     97   "Restrict working tree to DIRECTORIES.
     98 To extend rather than override the currently configured
     99 directories, call `magit-sparse-checkout-add' instead."
    100   (interactive
    101    (list (magit-completing-read-multiple
    102           "Include these directories: "
    103           ;; Note: Given that the appeal of sparse checkouts is
    104           ;; dealing with very large trees, listing all subdirectories
    105           ;; may need to be reconsidered.
    106           (magit-revision-directories "HEAD"))))
    107   (magit-sparse-checkout--assert-version)
    108   (magit-sparse-checkout--auto-enable)
    109   (magit-run-git-async "sparse-checkout" "set" directories))
    110 
    111 ;;;###autoload
    112 (defun magit-sparse-checkout-add (directories)
    113   "Add DIRECTORIES to the working tree.
    114 To override rather than extend the currently configured
    115 directories, call `magit-sparse-checkout-set' instead."
    116   (interactive
    117    (list (magit-completing-read-multiple
    118           "Add these directories: "
    119           ;; Same performance note as in `magit-sparse-checkout-set',
    120           ;; but even more so given the additional processing.
    121           (seq-remove
    122            (let ((re (concat
    123                       "\\`"
    124                       (regexp-opt (magit-sparse-checkout-directories)))))
    125              (lambda (d) (string-match-p re d)))
    126            (magit-revision-directories "HEAD")))))
    127   (magit-sparse-checkout--assert-version)
    128   (magit-sparse-checkout--auto-enable)
    129   (magit-run-git-async "sparse-checkout" "add" directories))
    130 
    131 ;;;###autoload
    132 (defun magit-sparse-checkout-reapply ()
    133   "Reapply the sparse checkout rules to the working tree.
    134 Some operations such as merging or rebasing may need to check out
    135 files that aren't included in the sparse checkout.  Call this
    136 command to reset to the sparse checkout state."
    137   (interactive)
    138   (magit-sparse-checkout--assert-version)
    139   (magit-run-git-async "sparse-checkout" "reapply"))
    140 
    141 ;;;###autoload
    142 (defun magit-sparse-checkout-disable ()
    143   "Convert sparse checkout to full checkout.
    144 Note that disabling the sparse checkout does not clear the
    145 configured directories.  Call `magit-sparse-checkout-enable' to
    146 restore the previous sparse checkout."
    147   (interactive)
    148   (magit-sparse-checkout--assert-version)
    149   (magit-run-git-async "sparse-checkout" "disable"))
    150 
    151 ;;; Miscellaneous
    152 
    153 (defun magit-sparse-checkout-insert-header ()
    154   "Insert header line with sparse checkout information.
    155 This header is not inserted by default.  To enable it, add it to
    156 `magit-status-headers-hook'."
    157   (when (magit-sparse-checkout-enabled-p)
    158     (insert (propertize (format "%-10s" "Sparse! ")
    159                         'font-lock-face 'magit-section-heading))
    160     (insert
    161      (let ((dirs (magit-sparse-checkout-directories)))
    162        (pcase (length dirs)
    163          (0 "top-level directory")
    164          (1 (car dirs))
    165          (n (format "%d directories" n)))))
    166     (insert ?\n)))
    167 
    168 ;;; _
    169 (provide 'magit-sparse-checkout)
    170 ;;; magit-sparse-checkout.el ends here