emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[nongnu] elpa/git-commit 2d94a9b363 2/7: Add interface to 'git sparse-ch


From: ELPA Syncer
Subject: [nongnu] elpa/git-commit 2d94a9b363 2/7: Add interface to 'git sparse-checkout'
Date: Sun, 23 Jan 2022 16:58:07 -0500 (EST)

branch: elpa/git-commit
commit 2d94a9b363a7dc851e4c88dd16552bd6b2fd9238
Author: Kyle Meyer <kyle@kyleam.com>
Commit: Kyle Meyer <kyle@kyleam.com>

    Add interface to 'git sparse-checkout'
    
    Git has had limited and mostly hidden sparse checkout support for a
    long time, but Git 2.25 exposed the functionality via a porcelain
    command.  Alongside this, it added and promoted a restricted pattern
    set ("cone mode") that improves the performance of the sparse
    checkouts, particularly with large trees.
    
    Add a new library that provides an interface to 'git sparse-checkout',
    supporting only the new cone mode.
    
    Bind magit-sparse-checkout to ">" in magit-mode-map.  Aside from the
    lack of available letters, this key choice is based on the (perhaps
    silly) hope that ">" will be easy enough to associate with a command
    that converts the working tree from a bigger checkout to a smaller
    one.
    
    Hold off on adding a binding to magit-dispatch given that
    magit-dispatch is mostly limited to letters at the moment and
    magit-sparse-checkout is unlikely to be a heavily used command.
    
    Note that magit-sparse-checkout-{set,add} read directories with
    magit-completing-read-multiple*, which means that directory names
    can't include crm-separator characters.  However, this same limitation
    is already in place for magit-read-files/magit:--.
---
 default.mk                    |   1 +
 docs/RelNotes/3.4.0.org       |   3 +
 docs/magit.org                |  55 +++++++++++++++
 lisp/Makefile                 | 103 ++++++++++++++--------------
 lisp/magit-mode.el            |   1 +
 lisp/magit-sparse-checkout.el | 153 ++++++++++++++++++++++++++++++++++++++++++
 lisp/magit.el                 |   1 +
 7 files changed, 266 insertions(+), 51 deletions(-)

diff --git a/default.mk b/default.mk
index 31e140c8cd..70bbdd5cd4 100644
--- a/default.mk
+++ b/default.mk
@@ -90,6 +90,7 @@ ELS += magit-patch.el
 ELS += magit-bisect.el
 ELS += magit-stash.el
 ELS += magit-blame.el
+ELS += magit-sparse-checkout.el
 ELS += magit-submodule.el
 ELS += magit-subtree.el
 ELS += magit-ediff.el
diff --git a/docs/RelNotes/3.4.0.org b/docs/RelNotes/3.4.0.org
index e305918326..3572db3b33 100644
--- a/docs/RelNotes/3.4.0.org
+++ b/docs/RelNotes/3.4.0.org
@@ -13,6 +13,9 @@
 - Added new face ~git-rebase-action~ to allow customization of the face
   used for the action words in git-rebase-todo files.
 
+- New transient ~magit-sparse-checkout~ provides an interface to the
+  ~git sparse-checkout~ command, introduced in Git v2.25.  #4102
+
 ** Fixes since v3.3.0
 
 - Automatic saving of file-visiting buffers was broken inside remote
diff --git a/docs/magit.org b/docs/magit.org
index 1634c05915..da53f5c756 100644
--- a/docs/magit.org
+++ b/docs/magit.org
@@ -6990,6 +6990,61 @@ Also see [[man:git-worktree]]
   If the worktree at point is the one whose status is already being
   displayed in the current buffer, then show it in Dired instead.
 
+** Sparse checkouts
+
+Sparse checkouts provide a way to restrict the working tree to a
+subset of directories.  See [[man:git-sparse-checkout]]
+
+*Warning*: Git introduced the ~git sparse-checkout~ command in version
+2.25 and still advertises it as experimental and subject to change.
+Magit's interface should be considered the same.  In particular, if
+Git introduces a backward incompatible change, Magit's sparse checkout
+functionality may be updated in a way that requires a more recent Git
+version.
+
+- Key: > (magit-sparse-checkout) ::
+
+  This transient prefix command binds the following suffix commands
+  and displays them in a temporary buffer until a suffix is invoked.
+
+- Key: > e (magit-sparse-checkout-enable) ::
+
+  This command initializes a sparse checkout that includes only the
+  files in the top-level directory.
+
+  Note that ~magit-sparse-checkout-set~ and
+  ~magit-sparse-checkout-add~ automatically initialize a sparse
+  checkout if necessary.  However, you may want to call
+  ~magit-sparse-checkout-enable~ explicitly to re-initialize a sparse
+  checkout after calling ~magit-sparse-checkout-disable~, to pass
+  additional arguments to ~git sparse-checkout init~, or to execute
+  the initialization asynchronously.
+
+- Key: > s (magit-sparse-checkout-set) ::
+
+  This command takes a list of directories and configures the sparse
+  checkout to include only files in those subdirectories.  Any
+  previously included directories are excluded unless they are in the
+  provided list of directories.
+
+- Key: > a (magit-sparse-checkout-add) ::
+
+  This command is like ~magit-sparse-checkout-set~, but instead adds
+  the specified list of directories to the set of directories that is
+  already included in the sparse checkout.
+
+- Key: > r (magit-sparse-checkout-reapply) ::
+
+  This command applies the currently configured sparse checkout
+  patterns to the working tree.  This is useful to call if excluded
+  files have been checked out after operations such as merging or
+  rebasing.
+
+- Key: > d (magit-sparse-checkout-disable) ::
+
+  This command restores the full checkout.  To return to the previous
+  sparse checkout, call ~magit-sparse-checkout-enable~.
+
 ** Bundle
 
 Also see [[man:git-bundle]]
diff --git a/lisp/Makefile b/lisp/Makefile
index b0ef31fcc9..d56731ca9c 100644
--- a/lisp/Makefile
+++ b/lisp/Makefile
@@ -14,59 +14,60 @@ magit-utils.elc:
 magit-section.elc:
 ifeq "$(BUILD_MAGIT_LIBGIT)" "true"
 magit-libgit.elc:
-magit-git.elc:          magit-utils.elc magit-section.elc magit-libgit.elc
+magit-git.elc:             magit-utils.elc magit-section.elc magit-libgit.elc
 else
-magit-git.elc:          magit-utils.elc magit-section.elc
+magit-git.elc:             magit-utils.elc magit-section.elc
 endif
-magit-mode.elc:         magit-section.elc magit-git.elc
-magit-margin.elc:       magit-section.elc magit-mode.elc
-magit-process.elc:      magit-utils.elc magit-section.elc \
-                        magit-git.elc magit-mode.elc
-magit-transient.elc:    magit-git.elc magit-mode.elc magit-process.elc
-magit-autorevert.elc:   magit-git.elc magit-process.elc
-magit-core.elc:         magit-margin.elc magit-utils.elc \
-                        magit-section.elc magit-git.elc \
-                        magit-transient.elc magit-mode.elc \
-                        magit-process.elc magit-autorevert.elc
-magit-diff.elc:         git-commit.elc magit-core.elc
-magit-log.elc:          magit-core.elc magit-diff.elc
-magit-wip.elc:          magit-core.elc magit-log.elc
-magit-reflog.elc:       magit-core.elc magit-log.elc
-magit-apply.elc:        magit-core.elc magit-diff.elc magit-wip.elc
-magit-repos.elc:        magit-core.elc
-magit.elc:              git-commit.elc magit-core.elc magit-diff.elc \
-                        magit-log.elc magit-apply.elc magit-repos.elc
-magit-status.elc:       magit.elc
-magit-refs.elc:         magit.elc
-magit-files.elc:        magit.elc
-magit-reset.elc:        magit.elc
-magit-branch.elc:       magit.elc magit-reset.elc
-magit-merge.elc:        magit.elc magit-diff.elc
-magit-tag.elc:          magit.elc
-magit-worktree.elc:     magit.elc
-magit-notes.elc:        magit.elc
-magit-sequence.elc:     magit.elc
-magit-commit.elc:       magit.elc magit-sequence.elc
-magit-remote.elc:       magit.elc
-magit-clone.elc:        magit.elc
-magit-fetch.elc:        magit.elc
-magit-pull.elc:         magit.elc magit-remote.elc
-magit-push.elc:         magit.elc
-magit-bisect.elc:       magit.elc
-magit-stash.elc:        magit.elc magit-sequence.elc magit-reflog.elc
-magit-blame.elc:        magit.elc
-magit-obsolete.elc:     magit.elc
-magit-submodule.elc:    magit.elc
-magit-patch.elc:        magit.elc
-magit-subtree.elc:      magit.elc
-magit-ediff.elc:        magit.elc
-magit-gitignore.elc:    magit.elc
-magit-bundle.elc:       magit.elc
-magit-extras.elc:       magit.elc magit-merge.elc
-git-rebase.elc:         magit.elc
-magit-imenu.elc:        magit.elc git-rebase.elc
-magit-bookmark.elc:     magit.elc
-magit-obsolete.elc:     magit.elc
+magit-mode.elc:            magit-section.elc magit-git.elc
+magit-margin.elc:          magit-section.elc magit-mode.elc
+magit-process.elc:         magit-utils.elc magit-section.elc \
+                           magit-git.elc magit-mode.elc
+magit-transient.elc:       magit-git.elc magit-mode.elc magit-process.elc
+magit-autorevert.elc:      magit-git.elc magit-process.elc
+magit-core.elc:            magit-margin.elc magit-utils.elc \
+                           magit-section.elc magit-git.elc \
+                           magit-transient.elc magit-mode.elc \
+                           magit-process.elc magit-autorevert.elc
+magit-diff.elc:            git-commit.elc magit-core.elc
+magit-log.elc:             magit-core.elc magit-diff.elc
+magit-wip.elc:             magit-core.elc magit-log.elc
+magit-reflog.elc:          magit-core.elc magit-log.elc
+magit-apply.elc:           magit-core.elc magit-diff.elc magit-wip.elc
+magit-repos.elc:           magit-core.elc
+magit.elc:                 git-commit.elc magit-core.elc magit-diff.elc \
+                           magit-log.elc magit-apply.elc magit-repos.elc
+magit-status.elc:          magit.elc
+magit-refs.elc:            magit.elc
+magit-files.elc:           magit.elc
+magit-reset.elc:           magit.elc
+magit-branch.elc:          magit.elc magit-reset.elc
+magit-merge.elc:           magit.elc magit-diff.elc
+magit-tag.elc:             magit.elc
+magit-worktree.elc:        magit.elc
+magit-notes.elc:           magit.elc
+magit-sequence.elc:        magit.elc
+magit-commit.elc:          magit.elc magit-sequence.elc
+magit-remote.elc:          magit.elc
+magit-clone.elc:           magit.elc
+magit-fetch.elc:           magit.elc
+magit-pull.elc:            magit.elc magit-remote.elc
+magit-push.elc:            magit.elc
+magit-bisect.elc:          magit.elc
+magit-stash.elc:           magit.elc magit-sequence.elc magit-reflog.elc
+magit-blame.elc:           magit.elc
+magit-obsolete.elc:        magit.elc
+magit-submodule.elc:       magit.elc
+magit-patch.elc:           magit.elc
+magit-subtree.elc:         magit.elc
+magit-ediff.elc:           magit.elc
+magit-gitignore.elc:       magit.elc
+magit-sparse-checkout.elc: magit.elc
+magit-bundle.elc:          magit.elc
+magit-extras.elc:          magit.elc magit-merge.elc
+git-rebase.elc:            magit.elc
+magit-imenu.elc:           magit.elc git-rebase.elc
+magit-bookmark.elc:        magit.elc
+magit-obsolete.elc:        magit.elc
 
 ## Build #############################################################
 
diff --git a/lisp/magit-mode.el b/lisp/magit-mode.el
index f32bf0d706..95d4898a1e 100644
--- a/lisp/magit-mode.el
+++ b/lisp/magit-mode.el
@@ -403,6 +403,7 @@ recommended value."
     (define-key map "%" 'magit-worktree)
     (define-key map "$" 'magit-process-buffer)
     (define-key map "!" 'magit-run)
+    (define-key map ">" 'magit-sparse-checkout)
     (define-key map (kbd "C-c C-c") 'magit-dispatch)
     (define-key map (kbd "C-c C-e") 'magit-edit-thing)
     (define-key map (kbd "C-c C-o") 'magit-browse-thing)
diff --git a/lisp/magit-sparse-checkout.el b/lisp/magit-sparse-checkout.el
new file mode 100644
index 0000000000..fea2743d43
--- /dev/null
+++ b/lisp/magit-sparse-checkout.el
@@ -0,0 +1,153 @@
+;;; magit-sparse-checkout.el --- sparse checkout support for Magit  -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022  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: Kyle Meyer <kyle@kyleam.com>
+;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
+
+;; SPDX-License-Identifier: GPL-3.0-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 provides an interface to the `git sparse-checkout'
+;; command.  It's been possible to define sparse checkouts since Git
+;; v1.7.0 by adding patterns to $GIT_DIR/info/sparse-checkout and
+;; calling `git read-tree -mu HEAD' to update the index and working
+;; tree.  However, Git v2.25 introduced the `git sparse-checkout'
+;; command along with "cone mode", which restricts the possible
+;; patterns to directories to provide better performance.
+;;
+;; The goal of this library is to support the `git sparse-checkout'
+;; command operating in cone mode.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Utilities
+
+(defun magit-sparse-checkout-enabled-p ()
+  "Return non-nil if working tree is a sparse checkout."
+  (magit-get-boolean "core.sparsecheckout"))
+
+(defun magit-sparse-checkout--assert-version ()
+  ;; Older versions of Git have the ability to define sparse checkout
+  ;; patterns in .git/info/sparse-checkout, but the sparse-checkout
+  ;; command isn't available until 2.25.0.
+  (when (magit-git-version< "2.25.0")
+    (user-error "`git sparse-checkout' not available until Git v2.25")))
+
+(defun magit-sparse-checkout--auto-enable ()
+  (if (magit-sparse-checkout-enabled-p)
+      (unless (magit-get-boolean "core.sparsecheckoutcone")
+        (user-error
+         "Magit's sparse checkout functionality requires cone mode"))
+    ;; Note: Don't use `magit-sparse-checkout-enable' because it's
+    ;; asynchronous.
+    (magit-run-git "sparse-checkout" "init" "--cone")))
+
+(defun magit-sparse-checkout-directories ()
+  "Return directories that are recursively included in the sparse checkout.
+See the `git sparse-checkout' manpage for details about
+\"recursive\" versus \"parent\" directories in cone mode."
+  (and (magit-get-boolean "core.sparsecheckoutcone")
+       (mapcar #'file-name-as-directory
+               (magit-git-lines "sparse-checkout" "list"))))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-sparse-checkout "magit-sparse-checkout" nil t)
+(transient-define-prefix magit-sparse-checkout ()
+  "Create and manage sparse checkouts."
+  :man-page "git-sparse-checkout"
+  ["Actions"
+   [:if-not magit-sparse-checkout-enabled-p
+    ("e" "Enable sparse checkout" magit-sparse-checkout-enable)]
+   [:if magit-sparse-checkout-enabled-p
+    ("d" "Disable sparse checkout" magit-sparse-checkout-disable)
+    ("r" "Reapply rules" magit-sparse-checkout-reapply)]
+   [("s" "Set directories" magit-sparse-checkout-set)
+    ("a" "Add directories" magit-sparse-checkout-add)]])
+
+;;;###autoload
+(defun magit-sparse-checkout-enable ()
+  "Convert the working tree to a sparse checkout."
+  (interactive)
+  (magit-sparse-checkout--assert-version)
+  (magit-run-git-async "sparse-checkout" "init" "--cone"))
+
+;;;###autoload
+(defun magit-sparse-checkout-set (directories)
+  "Restrict working tree to DIRECTORIES.
+To extend rather than override the currently configured
+directories, call `magit-sparse-checkout-add' instead."
+  (interactive
+   (list (magit-completing-read-multiple*
+          "Include these directories: "
+          ;; Note: Given that the appeal of sparse checkouts is
+          ;; dealing with very large trees, listing all subdirectories
+          ;; may need to be reconsidered.
+          (magit-revision-directories "HEAD"))))
+  (magit-sparse-checkout--assert-version)
+  (magit-sparse-checkout--auto-enable)
+  (magit-run-git-async "sparse-checkout" "set" directories))
+
+;;;###autoload
+(defun magit-sparse-checkout-add (directories)
+  "Add DIRECTORIES to the working tree.
+To override rather than extend the currently configured
+directories, call `magit-sparse-checkout-set' instead."
+  (interactive
+   (list (magit-completing-read-multiple*
+          "Add these directories: "
+          ;; Same performance note as in `magit-sparse-checkout-set',
+          ;; but even more so given the additional processing.
+          (seq-remove
+           (let ((re (concat
+                      "\\`"
+                      (regexp-opt (magit-sparse-checkout-directories)))))
+             (lambda (d) (string-match-p re d)))
+           (magit-revision-directories "HEAD")))))
+  (magit-sparse-checkout--assert-version)
+  (magit-sparse-checkout--auto-enable)
+  (magit-run-git-async "sparse-checkout" "add" directories))
+
+;;;###autoload
+(defun magit-sparse-checkout-reapply ()
+  "Reapply the sparse checkout rules to the working tree.
+Some operations such as merging or rebasing may need to check out
+files that aren't included in the sparse checkout.  Call this
+command to reset to the sparse checkout state."
+  (interactive)
+  (magit-sparse-checkout--assert-version)
+  (magit-run-git-async "sparse-checkout" "reapply"))
+
+;;;###autoload
+(defun magit-sparse-checkout-disable ()
+  "Convert sparse checkout to full checkout.
+Note that disabling the sparse checkout does not clear the
+configured directories.  Call `magit-sparse-checkout-enable' to
+restore the previous sparse checkout."
+  (interactive)
+  (magit-sparse-checkout--assert-version)
+  (magit-run-git-async "sparse-checkout" "disable"))
+
+;;; _
+(provide 'magit-sparse-checkout)
+;;; magit-sparse-checkout.el ends here
diff --git a/lisp/magit.el b/lisp/magit.el
index 83cba08406..80a16463e7 100644
--- a/lisp/magit.el
+++ b/lisp/magit.el
@@ -712,6 +712,7 @@ For X11 something like ~/.xinitrc should work.\n"
     (require 'magit-subtree)
     (require 'magit-ediff)
     (require 'magit-gitignore)
+    (require 'magit-sparse-checkout)
     (require 'magit-extras)
     (require 'git-rebase)
     (require 'magit-imenu)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]