| 1 | ;;; magit-fetch.el --- Download objects and refs -*- lexical-binding:t -*- |
| 2 | |
| 3 | ;; Copyright (C) 2008-2026 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 fetch commands. |
| 26 | |
| 27 | ;;; Code: |
| 28 | |
| 29 | (require 'magit) |
| 30 | |
| 31 | ;;; Commands |
| 32 | |
| 33 | ;;;###autoload(autoload 'magit-fetch "magit-fetch" nil t) |
| 34 | (transient-define-prefix magit-fetch () |
| 35 | "Fetch from another repository." |
| 36 | :man-page "git-fetch" |
| 37 | ["Arguments" |
| 38 | ("-p" "Prune deleted branches" ("-p" "--prune")) |
| 39 | ("-t" "Fetch all tags" ("-t" "--tags")) |
| 40 | ("-u" "Fetch full history" "--unshallow" :level 7) |
| 41 | ("-F" "Force" ("-f" "--force"))] |
| 42 | ["Fetch from" |
| 43 | ("p" magit-fetch-from-pushremote) |
| 44 | ("u" magit-fetch-from-upstream) |
| 45 | ("e" "elsewhere" magit-fetch-other) |
| 46 | ("a" "all remotes" magit-fetch-all)] |
| 47 | ["Fetch" |
| 48 | ("o" "another branch" magit-fetch-branch) |
| 49 | ("r" "explicit refspec" magit-fetch-refspec) |
| 50 | ("m" "submodules" magit-fetch-modules)] |
| 51 | ["Configure" |
| 52 | ("C" "variables..." magit-branch-configure)]) |
| 53 | |
| 54 | (defun magit-fetch-arguments () |
| 55 | (transient-args 'magit-fetch)) |
| 56 | |
| 57 | (defun magit-git-fetch (remote args) |
| 58 | (run-hooks 'magit-credential-hook) |
| 59 | (magit-run-git-async "fetch" remote args)) |
| 60 | |
| 61 | ;;;###autoload(autoload 'magit-fetch-from-pushremote "magit-fetch" nil t) |
| 62 | (transient-define-suffix magit-fetch-from-pushremote (args) |
| 63 | "Fetch from the current push-remote. |
| 64 | |
| 65 | With a prefix argument or when the push-remote is either not |
| 66 | configured or unusable, then let the user first configure the |
| 67 | push-remote." |
| 68 | :description #'magit-fetch--pushremote-description |
| 69 | (interactive (list (magit-fetch-arguments))) |
| 70 | (let ((remote (magit-get-push-remote))) |
| 71 | (when (or current-prefix-arg |
| 72 | (not (member remote (magit-list-remotes)))) |
| 73 | (let ((var (magit--push-remote-variable))) |
| 74 | (setq remote |
| 75 | (magit-read-remote (format "Set %s and fetch from there" var))) |
| 76 | (magit-set remote var))) |
| 77 | (magit-git-fetch remote args))) |
| 78 | |
| 79 | (defun magit-fetch--pushremote-description () |
| 80 | (let* ((branch (magit-get-current-branch)) |
| 81 | (remote (magit-get-push-remote branch)) |
| 82 | (v (magit--push-remote-variable branch t))) |
| 83 | (cond |
| 84 | ((member remote (magit-list-remotes)) remote) |
| 85 | (remote |
| 86 | (format "%s, replacing invalid" v)) |
| 87 | ((format "%s, setting that" v))))) |
| 88 | |
| 89 | ;;;###autoload(autoload 'magit-fetch-from-upstream "magit-fetch" nil t) |
| 90 | (transient-define-suffix magit-fetch-from-upstream (remote args) |
| 91 | "Fetch from the \"current\" remote, usually the upstream. |
| 92 | |
| 93 | If the upstream is configured for the current branch and names |
| 94 | an existing remote, then use that. Otherwise try to use another |
| 95 | remote: If only a single remote is configured, then use that. |
| 96 | Otherwise if a remote named \"origin\" exists, then use that. |
| 97 | |
| 98 | If no remote can be determined, then this command is not available |
| 99 | from the `magit-fetch' transient prefix and invoking it directly |
| 100 | results in an error." |
| 101 | :if (##magit-get-current-remote t) |
| 102 | :description (##magit-get-current-remote t) |
| 103 | (interactive (list (magit-get-current-remote t) |
| 104 | (magit-fetch-arguments))) |
| 105 | (unless remote |
| 106 | (error "The \"current\" remote could not be determined")) |
| 107 | (magit-git-fetch remote args)) |
| 108 | |
| 109 | ;;;###autoload |
| 110 | (defun magit-fetch-other (remote args) |
| 111 | "Fetch from another repository." |
| 112 | (interactive (list (magit-read-remote "Fetch remote") |
| 113 | (magit-fetch-arguments))) |
| 114 | (magit-git-fetch remote args)) |
| 115 | |
| 116 | ;;;###autoload |
| 117 | (defun magit-fetch-branch (remote branch args) |
| 118 | "Fetch a BRANCH from a REMOTE." |
| 119 | (interactive |
| 120 | (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) |
| 121 | (list remote |
| 122 | (magit-read-remote-branch "Fetch branch" remote) |
| 123 | (magit-fetch-arguments)))) |
| 124 | (magit-git-fetch remote (cons branch args))) |
| 125 | |
| 126 | ;;;###autoload |
| 127 | (defun magit-fetch-refspec (remote refspec args) |
| 128 | "Fetch a REFSPEC from a REMOTE." |
| 129 | (interactive |
| 130 | (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) |
| 131 | (list remote |
| 132 | (magit-read-refspec "Fetch using refspec" remote) |
| 133 | (magit-fetch-arguments)))) |
| 134 | (magit-git-fetch remote (cons refspec args))) |
| 135 | |
| 136 | ;;;###autoload |
| 137 | (defun magit-fetch-all (args) |
| 138 | "Fetch from all remotes." |
| 139 | (interactive (list (magit-fetch-arguments))) |
| 140 | (magit-git-fetch nil (cons "--all" args))) |
| 141 | |
| 142 | ;;;###autoload |
| 143 | (defun magit-fetch-all-prune () |
| 144 | "Fetch from all remotes, and prune. |
| 145 | Prune remote tracking branches for branches that have been |
| 146 | removed on the respective remote." |
| 147 | (interactive) |
| 148 | (run-hooks 'magit-credential-hook) |
| 149 | (magit-run-git-async "remote" "update" "--prune")) |
| 150 | |
| 151 | ;;;###autoload |
| 152 | (defun magit-fetch-all-no-prune () |
| 153 | "Fetch from all remotes." |
| 154 | (interactive) |
| 155 | (run-hooks 'magit-credential-hook) |
| 156 | (magit-run-git-async "remote" "update")) |
| 157 | |
| 158 | ;;;###autoload(autoload 'magit-fetch-modules "magit-fetch" nil t) |
| 159 | (transient-define-prefix magit-fetch-modules (&optional transient args) |
| 160 | "Fetch all populated submodules. |
| 161 | |
| 162 | Fetching is done using \"git fetch --recurse-submodules\", which |
| 163 | means that the super-repository and recursively all submodules |
| 164 | are also fetched. |
| 165 | |
| 166 | To set and potentially save other arguments invoke this command |
| 167 | with a prefix argument." |
| 168 | :man-page "git-fetch" |
| 169 | :value (list "--verbose" "--jobs=4") |
| 170 | ["Arguments" |
| 171 | ("-v" "verbose" "--verbose") |
| 172 | ("-j" "number of jobs" "--jobs=" :reader transient-read-number-N+)] |
| 173 | ["Action" |
| 174 | ("m" "fetch modules" magit-fetch-modules)] |
| 175 | (interactive (if current-prefix-arg |
| 176 | (list t) |
| 177 | (list nil (transient-args 'magit-fetch-modules)))) |
| 178 | (if transient |
| 179 | (transient-setup 'magit-fetch-modules) |
| 180 | (magit-with-toplevel |
| 181 | (magit-run-git-async "fetch" "--recurse-submodules" args)) |
| 182 | ;; Tried anyway; a future Git release may fix this defect. |
| 183 | (unless (magit-list-remotes) |
| 184 | (message "Cannot fetch modules if super-repository has no remotes")))) |
| 185 | |
| 186 | ;;; _ |
| 187 | (provide 'magit-fetch) |
| 188 | ;; Local Variables: |
| 189 | ;; read-symbol-shorthands: ( |
| 190 | ;; ("and$" . "cond-let--and$") |
| 191 | ;; ("thread$" . "cond-let--thread$") |
| 192 | ;; ("when$" . "cond-let--when$") |
| 193 | ;; ("and-let*" . "cond-let--and-let*") |
| 194 | ;; ("and-let" . "cond-let--and-let") |
| 195 | ;; ("if-let*" . "cond-let--if-let*") |
| 196 | ;; ("if-let" . "cond-let--if-let") |
| 197 | ;; ("when-let*" . "cond-let--when-let*") |
| 198 | ;; ("when-let" . "cond-let--when-let") |
| 199 | ;; ("while-let*" . "cond-let--while-let*") |
| 200 | ;; ("while-let" . "cond-let--while-let") |
| 201 | ;; ("match-string" . "match-string") |
| 202 | ;; ("match-str" . "match-string-no-properties")) |
| 203 | ;; End: |
| 204 | ;;; magit-fetch.el ends here |