git_lfs/args.rs
1//! Clap CLI surface (struct `Cli` + subcommands).
2//!
3//! Extracted from `main.rs` so xtask (and any future tool) can
4//! reuse the command tree for man-page generation, completion
5//! scripts, etc. Keep this file focused on the clap derive — all
6//! dispatch / business logic stays in main.rs and the per-command
7//! modules.
8//!
9//! Each subcommand is a tuple variant on [`Command`] delegating to
10//! a `*Args` struct. The struct is the home for the rustdoc that
11//! drives clap's `about` / `long_about` (first paragraph → about,
12//! rest → long_about) and for `#[command(...)]` extras such as
13//! `after_help`, aliases, and arg-group headings. Keep the variants
14//! themselves bare — putting a doc comment on the variant would
15//! shadow the struct's docs.
16
17use std::path::PathBuf;
18
19use clap::{Args, Parser, Subcommand};
20
21/// Git LFS is a system for managing and versioning large files
22/// in association with a Git repository. Instead of storing the
23/// large files within the Git repository as blobs, Git LFS stores
24/// special "pointer files" in the repository, while storing the
25/// actual file contents on a Git LFS server. The contents of the
26/// large file are downloaded automatically when needed, for example
27/// when a Git branch containing the large file is checked out.
28///
29/// Git LFS works by using a "smudge" filter to look up the large
30/// file contents based on the pointer file, and a "clean" filter
31/// to create a new version of the pointer file when the large file's
32/// contents change. It also uses a pre-push hook to upload the large
33/// file contents to the Git LFS server whenever a commit containing
34/// a new large file version is about to be pushed to the
35/// corresponding Git server.
36#[derive(Parser)]
37#[command(
38 name = "git-lfs",
39 about = "Git LFS — large file storage for git",
40 // We want `git lfs --version` to print the same banner as
41 // `git lfs version`. clap's auto-derived `--version` would
42 // emit `git-lfs <version>` (one token, no `/` separator),
43 // which doesn't match the user-agent style upstream uses.
44 // Suppress clap's flag and handle --version ourselves.
45 disable_version_flag = true,
46 max_term_width = 100,
47)]
48pub struct Cli {
49 /// Print the version banner and exit.
50 #[arg(long, short = 'V', global = true)]
51 pub version: bool,
52
53 #[command(subcommand)]
54 pub command: Option<Command>,
55}
56
57// note: don't add rustdoc comments here, they will shadow the struct's docs
58// in the clap-generated help output
59#[derive(Subcommand)]
60pub enum Command {
61 Clean(CleanArgs),
62 Smudge(SmudgeArgs),
63 Install(InstallArgs),
64 Uninstall(UninstallArgs),
65 Track(TrackArgs),
66 Untrack(UntrackArgs),
67 FilterProcess(FilterProcessArgs),
68 Fetch(FetchArgs),
69 Pull(PullArgs),
70 Push(PushArgs),
71 Clone(CloneArgs),
72 PostCheckout(PostCheckoutArgs),
73 PostCommit(PostCommitArgs),
74 PostMerge(PostMergeArgs),
75 PrePush(PrePushArgs),
76 Version(VersionArgs),
77 Pointer(PointerArgs),
78 Env(EnvArgs),
79 Ext(ExtArgs),
80 Update(UpdateArgs),
81 Migrate(MigrateArgs),
82 Checkout(CheckoutArgs),
83 Prune(PruneArgs),
84 Fsck(FsckArgs),
85 Status(StatusArgs),
86 Lock(LockArgs),
87 Locks(LocksArgs),
88 Unlock(UnlockArgs),
89 LsFiles(LsFilesArgs),
90}
91
92/// Git clean filter that converts large files to pointers
93///
94/// Read the contents of a large file from standard input, and write a
95/// Git LFS pointer file for that file to standard output.
96///
97/// Clean is typically run by Git’s clean filter, configured by the
98/// repository’s Git attributes.
99///
100/// Clean is not part of the user-facing Git plumbing commands.
101/// To preview the pointer of a large file as it would be generated,
102/// see the git-lfs-pointer(1) command.
103#[derive(Args)]
104pub struct CleanArgs {
105 /// Working-tree path of the file being cleaned.
106 ///
107 /// Substituted for `%f` in any configured `lfs.extension.<name>.clean` command.
108 pub path: Option<PathBuf>,
109}
110
111/// Git smudge filter that converts pointer in blobs to the actual content
112///
113/// Read a Git LFS pointer file from standard input and write the contents of the
114/// corresponding large file to standard output. If needed, download the file’s
115/// contents from the Git LFS endpoint. The argument, if provided, is only used
116/// for a progress bar.
117///
118/// Smudge is typically run by Git’s smudge filter, configured by the repository’s
119/// Git attributes.
120///
121/// In your Git configuration or in a .lfsconfig file, you may set either or both
122/// of `lfs.fetchinclude` and `lfs.fetchexclude` to comma-separated lists of paths.
123/// If `lfs.fetchinclude` is defined, Git LFS pointer files will only be replaced
124/// with the contents of the corresponding Git LFS object file if their path
125/// matches one in that list, and if `lfs.fetchexclude` is defined, Git LFS pointer
126/// files will only be replaced with the contents of the corresponding Git LFS
127/// object file if their path does not match one in that list. Paths are matched
128/// using wildcard matching as per gitignore(5). Git LFS pointer files that are
129/// not replaced with the contents of their corresponding object files are simply
130/// copied to standard output without change.
131///
132/// Without any options, git lfs smudge outputs the raw Git LFS content to standard
133/// output.
134#[derive(Args)]
135pub struct SmudgeArgs {
136 /// Working-tree path of the file being smudged (currently unused).
137 pub path: Option<PathBuf>,
138 /// Skip automatic downloading of objects on clone or pull.
139 ///
140 /// Equivalent to `GIT_LFS_SKIP_SMUDGE=1`. Wired up by `git lfs install --skip-smudge`.
141 #[arg(long)]
142 pub skip: bool,
143}
144
145/// Install Git LFS configuration
146///
147/// Set up the `lfs` smudge and clean filters under the name `lfs` in
148/// the global Git config, and (when run from inside a repository)
149/// install a pre-push hook to run git-lfs-pre-push(1). If
150/// `core.hooksPath` is configured in any Git configuration (supported
151/// on Git v2.9.0 or later), the pre-push hook is installed to that
152/// directory instead.
153///
154/// Without any options, only sets up the `lfs` smudge and clean filters
155/// if they are not already set.
156#[derive(Args)]
157pub struct InstallArgs {
158 // TODO(post-1.0): replace the --local/--system/--worktree/--file mutex
159 // with a clap ArgGroup (multiple = false). Validation lives in
160 // resolve_install_scope (cli/src/main.rs); kept manual because
161 // tests/t-install.sh:329 (and the t-install-worktree / t-uninstall /
162 // t-uninstall-worktree variants) assert upstream's exact wording
163 // ("Only one of the --local, --system, --worktree, and --file
164 // options can be specified."). Worth taking once we're free to
165 // update those assertions.
166 /// Set the `lfs` smudge and clean filters, overwriting existing
167 /// values.
168 #[arg(short, long)]
169 pub force: bool,
170
171 /// Set the `lfs` smudge and clean filters in the local repository's
172 /// git config, instead of the global git config (`~/.gitconfig`).
173 #[arg(short, long)]
174 pub local: bool,
175
176 /// Set the `lfs` smudge and clean filters in the current working
177 /// tree's git config, instead of the global git config
178 /// (`~/.gitconfig`) or local repository's git config
179 /// (`$GIT_DIR/config`).
180 ///
181 /// If multiple working trees are in use, the Git config extension
182 /// `worktreeConfig` must be enabled to use this option. If only one
183 /// working tree is in use, `--worktree` has the same effect as
184 /// `--local`. Available only on Git v2.20.0 or later.
185 #[arg(short, long)]
186 pub worktree: bool,
187
188 /// Set the `lfs` smudge and clean filters in the system git config,
189 /// e.g. `/etc/gitconfig` instead of the global git config
190 /// (`~/.gitconfig`).
191 #[arg(long)]
192 pub system: bool,
193
194 /// Set the `lfs` smudge and clean filters in the Git configuration
195 /// file specified by `<PATH>`.
196 #[arg(long, value_name = "PATH")]
197 pub file: Option<PathBuf>,
198
199 /// Skip automatic downloading of objects on clone or pull.
200 ///
201 /// Requires a manual `git lfs pull` every time a new commit is
202 /// checked out on the repository.
203 #[arg(short, long)]
204 pub skip_smudge: bool,
205
206 /// Skip installation of hooks into the local repository.
207 ///
208 /// Use if you want to install the LFS filters but not make changes
209 /// to the hooks. Valid alongside `--local`, `--worktree`, `--system`,
210 /// or `--file`.
211 #[arg(long)]
212 pub skip_repo: bool,
213}
214
215/// Remove Git LFS configuration
216///
217/// Remove the `lfs` clean and smudge filters from the global Git config,
218/// and (when run from inside a Git repository) uninstall the Git LFS
219/// pre-push hook. Hooks that don't match what we would write are left
220/// untouched.
221#[derive(Args)]
222pub struct UninstallArgs {
223 // TODO(post-1.0): same --local/--system/--worktree/--file mutex as
224 // InstallArgs — share a clap ArgGroup. See InstallArgs's TODO for
225 // the rationale and test references.
226 /// Optional mode. With `hooks`, removes only the LFS git hooks and
227 /// leaves the filter config alone (the inverse of `--skip-repo`).
228 pub mode: Option<String>,
229
230 /// Remove the `lfs` smudge and clean filters from the local
231 /// repository's git config, instead of the global git config
232 /// (`~/.gitconfig`).
233 #[arg(short, long)]
234 pub local: bool,
235
236 /// Remove the `lfs` smudge and clean filters from the current
237 /// working tree's git config, instead of the global git config
238 /// (`~/.gitconfig`) or local repository's git config
239 /// (`$GIT_DIR/config`).
240 ///
241 /// If multiple working trees are in use, the Git config extension
242 /// `worktreeConfig` must be enabled to use this option. If only one
243 /// working tree is in use, `--worktree` has the same effect as
244 /// `--local`. Available only on Git v2.20.0 or later.
245 #[arg(short, long)]
246 pub worktree: bool,
247
248 /// Remove the `lfs` smudge and clean filters from the system git
249 /// config, instead of the global git config (`~/.gitconfig`).
250 #[arg(long)]
251 pub system: bool,
252
253 /// Remove the `lfs` smudge and clean filters from the Git
254 /// configuration file specified by `<PATH>`.
255 #[arg(long, value_name = "PATH")]
256 pub file: Option<PathBuf>,
257
258 /// Skip cleanup of the local repo.
259 ///
260 /// Use if you want to uninstall the global LFS filters but not
261 /// make changes to the current repo.
262 #[arg(long)]
263 pub skip_repo: bool,
264}
265
266/// View or add Git LFS paths to Git attributes
267///
268/// Start tracking the given pattern(s) through Git LFS. The argument is
269/// written to `.gitattributes`. If no paths are provided, list the
270/// currently-tracked paths.
271///
272/// Per gitattributes(5), patterns use the gitignore(5) pattern rules to
273/// match paths. This means that patterns containing asterisk (`*`),
274/// question mark (`?`), and the bracket characters (`[` and `]`) are
275/// treated specially; to disable this behavior and treat them literally
276/// instead, use `--filename` or escape the character with a backslash.
277#[derive(Args)]
278pub struct TrackArgs {
279 /// File patterns to track (e.g. `*.jpg`, `data/*.bin`).
280 pub patterns: Vec<String>,
281
282 /// Log files which `git lfs track` will touch. Disabled by default.
283 #[arg(short, long)]
284 pub verbose: bool,
285
286 /// Log all actions that would normally take place (adding entries
287 /// to `.gitattributes`, touching files on disk, etc.) without
288 /// performing any mutative operations.
289 ///
290 /// Implicitly mocks the behavior of `--verbose`, logging in greater
291 /// detail what it is doing. Disabled by default.
292 #[arg(short, long)]
293 pub dry_run: bool,
294
295 /// Write the currently tracked patterns as JSON to standard output.
296 ///
297 /// Intended for interoperation with external tools. Cannot be
298 /// combined with any pattern arguments. If `--no-excluded` is also
299 /// provided, that option will have no effect.
300 #[arg(short, long)]
301 pub json: bool,
302
303 /// Treat the arguments as literal filenames, not as patterns.
304 ///
305 /// Any special glob characters in the filename will be escaped
306 /// when writing the `.gitattributes` file.
307 #[arg(long)]
308 pub filename: bool,
309
310 /// Make the paths "lockable" — they should be locked to edit them,
311 /// and will be made read-only in the working copy when not locked.
312 #[arg(short, long)]
313 pub lockable: bool,
314
315 /// Remove the lockable flag from the paths so they are no longer
316 /// read-only unless locked.
317 #[arg(long)]
318 pub not_lockable: bool,
319
320 /// Don't list patterns that are excluded in the output; only list
321 /// patterns that are tracked.
322 #[arg(long)]
323 pub no_excluded: bool,
324
325 /// Make matched entries stat-dirty so that Git can re-index files
326 /// you wish to convert to LFS.
327 ///
328 /// Does not modify any `.gitattributes` file.
329 #[arg(long)]
330 pub no_modify_attrs: bool,
331}
332
333/// Remove Git LFS paths from Git attributes
334///
335/// Stop tracking the given path(s) through Git LFS. The argument can
336/// be a glob pattern or a file path. The matching pointer files in
337/// history (and the objects in the local store) are left in place.
338#[derive(Args)]
339pub struct UntrackArgs {
340 /// Paths or glob patterns to stop tracking.
341 pub patterns: Vec<String>,
342}
343
344/// Git filter process that converts between pointer and actual content
345///
346/// Implement the Git process filter API, exchanging handshake messages
347/// and then accepting and responding to requests to either clean or
348/// smudge a file.
349///
350/// `filter-process` is always run by Git's filter process, and is
351/// configured by the repository's Git attributes.
352///
353/// In your Git configuration or in a `.lfsconfig` file, you may set
354/// either or both of `lfs.fetchinclude` and `lfs.fetchexclude` to
355/// comma-separated lists of paths. If `lfs.fetchinclude` is defined,
356/// Git LFS pointer files will only be replaced with the contents of
357/// the corresponding object file if their path matches one in that
358/// list, and if `lfs.fetchexclude` is defined, pointer files will
359/// only be replaced if their path does not match one in that list.
360/// Paths are matched using wildcard matching as per gitignore(5).
361/// Pointer files that are not replaced are simply copied to standard
362/// output without change.
363///
364/// The filter process uses Git's pkt-line protocol to communicate, and
365/// is documented in detail in gitattributes(5).
366#[derive(Args)]
367pub struct FilterProcessArgs {
368 /// Skip automatic downloading of objects on clone or pull.
369 ///
370 /// Equivalent to `GIT_LFS_SKIP_SMUDGE=1`. Wired up by
371 /// `git lfs install --skip-smudge`.
372 #[arg(short, long)]
373 pub skip: bool,
374}
375
376/// Download all Git LFS files for a given ref
377///
378/// Download Git LFS objects at the given refs from the specified remote.
379/// See DEFAULT REMOTE and DEFAULT REFS for what happens if you don't
380/// specify.
381///
382/// This does not update the working copy; use git-lfs-pull(1) to
383/// download and replace pointer text with object content, or
384/// git-lfs-checkout(1) to materialize already-downloaded objects.
385#[derive(Args)]
386pub struct FetchArgs {
387 /// Optional remote name followed by refs. The first positional
388 /// argument is treated as a remote name when it resolves; any
389 /// following arguments are refs to fetch.
390 pub args: Vec<String>,
391
392 /// Specify `lfs.fetchinclude` just for this invocation; see
393 /// INCLUDE AND EXCLUDE.
394 #[arg(short = 'I', long, help_heading = FILTER)]
395 pub include: Vec<String>,
396
397 /// Specify `lfs.fetchexclude` just for this invocation; see
398 /// INCLUDE AND EXCLUDE.
399 #[arg(short = 'X', long, help_heading = FILTER)]
400 pub exclude: Vec<String>,
401
402 /// Download all objects that are referenced by any commit
403 /// reachable from the refs provided as arguments.
404 ///
405 /// If no refs are provided, then all refs are fetched. This is
406 /// primarily for backup and migration purposes. Cannot be
407 /// combined with `--include`/`--exclude`. Ignores any globally
408 /// configured include and exclude paths to ensure that all
409 /// objects are downloaded.
410 #[arg(short, long)]
411 pub all: bool,
412
413 /// Read a list of newline-delimited refs from standard input
414 /// instead of the command line.
415 #[arg(long)]
416 pub stdin: bool,
417
418 /// Prune old and unreferenced objects after fetching, equivalent
419 /// to running `git lfs prune` afterwards. See git-lfs-prune(1)
420 /// for more details.
421 #[arg(short, long)]
422 pub prune: bool,
423
424 /// Also fetch objects that are already present locally.
425 ///
426 /// Useful for recovery from a corrupt local store.
427 #[arg(long)]
428 pub refetch: bool,
429
430 /// Print what would be fetched, without actually fetching anything.
431 #[arg(short, long)]
432 pub dry_run: bool,
433
434 /// Also fetch recently-touched refs and the recent pre-images on
435 /// each.
436 ///
437 /// Walk every ref under `refs/heads/` (and, by default, every
438 /// remote-tracking ref) whose tip commit lies within
439 /// `lfs.fetchrecentrefsdays` of today, and on each of those refs
440 /// download the pre-image of every LFS file modified within
441 /// `lfs.fetchrecentcommitsdays`. Combine with the named refs'
442 /// HEAD-state fetch. The same behaviour fires automatically if
443 /// `lfs.fetchrecentalways` is set.
444 #[arg(short, long)]
445 pub recent: bool,
446
447 /// Write the details of all object transfer requests as JSON to
448 /// standard output.
449 ///
450 /// Intended for interoperation with external tools. When
451 /// `--dry-run` is also specified, writes the details of the
452 /// transfers that would occur if the objects were fetched.
453 #[arg(short, long)]
454 pub json: bool,
455}
456
457const FILTER: &str = "Filter options";
458
459/// Download all Git LFS files for current ref and checkout
460///
461/// Download Git LFS objects for the currently checked out ref, and
462/// update the working copy with the downloaded content if required.
463///
464/// This is generally equivalent to running `git lfs fetch [options]
465/// [<remote>]` followed by `git lfs checkout`. See git-lfs-checkout(1)
466/// for partial-clone, sparse-checkout, and bare-repository behavior
467/// (governed by the installed Git version and `GIT_ATTR_SOURCE`).
468///
469/// Requires `git lfs install` to have wired up the smudge filter. If
470/// the filter is missing, the fetch step still runs but the
471/// working-tree update is skipped with a hint to install.
472#[derive(Args)]
473pub struct PullArgs {
474 /// Optional remote name followed by refs.
475 ///
476 /// The first positional argument is treated as a remote name when
477 /// it resolves; any following arguments are refs to fetch. With
478 /// no arguments, the default remote is used.
479 pub args: Vec<String>,
480
481 /// Specify `lfs.fetchinclude` just for this invocation.
482 #[arg(short = 'I', long, help_heading = FILTER)]
483 pub include: Vec<String>,
484
485 /// Specify `lfs.fetchexclude` just for this invocation.
486 #[arg(short = 'X', long, help_heading = FILTER)]
487 pub exclude: Vec<String>,
488}
489
490/// Push queued large files to the Git LFS endpoint
491///
492/// Upload Git LFS files to the configured endpoint for the current Git
493/// remote. By default, filters out objects that are already referenced
494/// by the local clone of the remote (approximated via
495/// `refs/remotes/<remote>/*`); the server's batch API dedupes again,
496/// so a missing local tracking ref doesn't waste bandwidth.
497#[derive(Args)]
498pub struct PushArgs {
499 /// Remote to push to (e.g. `origin`). The remote's tracking refs
500 /// are excluded from the upload set so already-pushed objects
501 /// aren't sent again.
502 pub remote: String,
503
504 /// Refs (or, with `--object-id`, raw OIDs) to push. With `--all`,
505 /// restricts the all-refs walk to these; with `--stdin`, ignored
506 /// (a warning is emitted).
507 pub args: Vec<String>,
508
509 /// Print the files that would be pushed, without actually pushing
510 /// them.
511 #[arg(short, long)]
512 pub dry_run: bool,
513
514 /// Push all objects reachable from the refs given as arguments.
515 ///
516 /// If no refs are provided, all local refs are pushed. Note this
517 /// behavior differs from `git lfs fetch --all`, which fetches
518 /// every ref including refs outside `refs/heads` / `refs/tags`. If
519 /// you're migrating a repository, run `git lfs push` for any
520 /// additional remote refs that contain LFS objects not reachable
521 /// from your local refs.
522 #[arg(short, long)]
523 pub all: bool,
524
525 /// Push only the object OIDs listed on the command line (or read
526 /// from stdin with `--stdin`), separated by spaces.
527 #[arg(short, long)]
528 pub object_id: bool,
529
530 /// Read newline-delimited refs (or object IDs when using
531 /// `--object-id`) from standard input instead of the command
532 /// line.
533 #[arg(long)]
534 pub stdin: bool,
535}
536
537/// Efficiently clone a LFS-enabled repository
538///
539/// Clone an LFS-enabled Git repository by disabling LFS during the
540/// `git clone`, then running `git lfs pull` directly afterwards.
541/// Also installs the repo-level hooks (`.git/hooks`) that LFS requires
542/// to operate; if `--separate-git-dir` is given to `git clone`, the
543/// hooks are installed there.
544///
545/// Historically faster than a regular `git clone` because that would
546/// download LFS content via the smudge filter one file at a time.
547/// Modern `git clone` parallelizes the smudge filter, so this command
548/// no longer offers a meaningful speedup over plain `git clone`. You
549/// should prefer plain `git clone`.
550///
551/// In addition to the options accepted by `git clone`, the LFS-only
552/// flags `--include` / `-I <paths>`, `--exclude` / `-X <paths>`, and
553/// `--skip-repo` (skip installing the repo-level hooks) are accepted
554/// — see git-lfs-fetch(1) for the include/exclude semantics. They're
555/// parsed from the trailing argument list rather than declared as
556/// clap flags, so they don't appear in this command's `--help`.
557#[derive(Args)]
558pub struct CloneArgs {
559 /// `git clone` arguments plus the LFS pass-through flags
560 /// (`-I`/`--include`, `-X`/`--exclude`, `--skip-repo`). The
561 /// repository URL is required; an optional target directory
562 /// follows.
563 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
564 pub args: Vec<String>,
565}
566
567/// Git post-checkout hook implementation
568///
569/// Respond to Git post-checkout events. Git invokes this hook with
570/// `<rev-before> <ref-after> <is-branch-checkout>`. We make sure that
571/// any files which are marked as lockable by `git lfs track` are
572/// read-only in the working copy, if not currently locked by the
573/// local user.
574#[derive(Args)]
575pub struct PostCheckoutArgs {
576 /// Positional arguments passed by git. Not normally invoked by
577 /// hand.
578 pub args: Vec<String>,
579}
580
581/// Git post-commit hook implementation
582///
583/// Respond to Git post-commit events. Like `git lfs post-merge`, we
584/// make sure that any files which are marked as lockable by
585/// `git lfs track` are read-only in the working copy, if not
586/// currently locked by the local user.
587///
588/// Upstream optimizes by only checking files changed in HEAD; we
589/// currently scan the full work tree on every commit. The result is
590/// the same, but slower on large repositories.
591#[derive(Args)]
592pub struct PostCommitArgs {
593 /// Positional arguments passed by git. Not normally invoked by
594 /// hand.
595 pub args: Vec<String>,
596}
597
598/// Git post-merge hook implementation
599///
600/// Respond to Git post-merge events. Git invokes this hook with
601/// `<is-squash>`. We make sure that any files which are marked as
602/// lockable by `git lfs track` are read-only in the working copy, if
603/// not currently locked by the local user.
604#[derive(Args)]
605pub struct PostMergeArgs {
606 /// Positional arguments passed by git. Not normally invoked by
607 /// hand.
608 pub args: Vec<String>,
609}
610
611/// Git pre-push hook implementation
612///
613/// Respond to Git pre-push events. Reads the range of commits from
614/// stdin in the form `<local-ref> <local-sha1> <remote-ref>
615/// <remote-sha1>`, takes the remote name and URL as arguments, and
616/// uploads any Git LFS objects associated with those commits to the
617/// Git LFS API.
618///
619/// When pushing a new branch, the list of Git objects considered is
620/// every object reachable from the new branch. When deleting a
621/// branch, no LFS objects are pushed.
622#[derive(Args)]
623pub struct PrePushArgs {
624 /// Name of the remote being pushed to.
625 pub remote: String,
626
627 /// URL of the remote (informational; we use the `lfs.url`
628 /// config).
629 pub url: Option<String>,
630
631 /// Print the files that would be pushed, without actually
632 /// pushing them.
633 #[arg(short, long)]
634 pub dry_run: bool,
635}
636
637/// Print the git-lfs version banner and exit
638#[derive(Args)]
639pub struct VersionArgs;
640
641/// Build, compare, and check pointers
642///
643/// Build and optionally compare generated pointer files to ensure
644/// consistency between different Git LFS implementations.
645#[derive(Args)]
646pub struct PointerArgs {
647 // TODO(post-1.0): replace the --strict/--no-strict, --check/--pointer,
648 // and --check/--file/--stdin manual checks (cli/src/pointer_cmd.rs:108,
649 // 218, 223, 230, 241) with clap arg_group/conflicts_with/requires.
650 // No shell test asserts this wording, so the constraint here is
651 // softer than for the other commands — the deferral is purely about
652 // upstream parity. Worth taking whenever.
653 /// A local file to build the pointer from.
654 #[arg(short, long)]
655 pub file: Option<PathBuf>,
656
657 /// A local file containing a pointer generated from another
658 /// implementation.
659 ///
660 /// Compared to the pointer generated from `--file`.
661 #[arg(short, long)]
662 pub pointer: Option<PathBuf>,
663
664 /// Read the pointer from standard input to compare with the
665 /// pointer generated from `--file`.
666 #[arg(long)]
667 pub stdin: bool,
668
669 /// Read the pointer from standard input (with `--stdin`) or the
670 /// filepath (with `--file`).
671 ///
672 /// If neither or both of `--stdin` and `--file` are given, the
673 /// invocation is invalid. Exits 0 if the data read is a valid Git
674 /// LFS pointer, 1 otherwise. With `--strict`, exits 2 if the
675 /// pointer is not byte-canonical.
676 #[arg(long)]
677 pub check: bool,
678
679 /// With `--check`, verify that the pointer is canonical (the one
680 /// Git LFS would create).
681 ///
682 /// If it isn't, exits 2. The default — for backwards compatibility
683 /// — is `--no-strict`.
684 #[arg(long)]
685 pub strict: bool,
686
687 /// Disable strict mode (paired with `--strict`).
688 #[arg(long)]
689 pub no_strict: bool,
690
691 /// Build a plain pointer without running configured `lfs.extension.*`
692 /// clean commands. Default behavior is to chain through any
693 /// extensions (and emit a `warning:` line on stderr); pass this to
694 /// suppress both the chain and the warning.
695 #[arg(long)]
696 pub no_extensions: bool,
697}
698
699/// Display the Git LFS environment
700///
701/// Display the current Git LFS environment: version, endpoints,
702/// on-disk paths, and the three `filter.lfs.*` config values.
703#[derive(Args)]
704pub struct EnvArgs;
705
706/// List the configured LFS pointer extensions
707///
708/// Print each `lfs.extension.<name>.*` entry resolved to its final
709/// configuration in priority order. Extensions chain external
710/// clean / smudge programs around each LFS object — see
711/// git-lfs-config(5) for how to configure them.
712///
713/// With no arguments, prints every configured extension. With
714/// `list <name>...`, prints only the named extensions (one block
715/// per name, in argument order).
716#[derive(Args)]
717pub struct ExtArgs {
718 #[command(subcommand)]
719 pub cmd: Option<ExtCmd>,
720}
721
722#[derive(Subcommand)]
723pub enum ExtCmd {
724 List(ExtListArgs),
725}
726
727/// List configured LFS pointer extensions, optionally filtered by name.
728#[derive(Args)]
729pub struct ExtListArgs {
730 /// Extension names to print. With no names, prints all configured
731 /// extensions (same as bare `git lfs ext`).
732 pub names: Vec<String>,
733}
734
735/// Update Git hooks
736///
737/// Update the Git hooks used by Git LFS. Silently upgrades known hook
738/// contents. If you have your own custom hooks you may need to use
739/// one of the extended options below.
740#[derive(Args)]
741pub struct UpdateArgs {
742 /// Forcibly overwrite any existing hooks with git-lfs hooks.
743 ///
744 /// Use this option if `git lfs update` fails because of existing
745 /// hooks but you don't care about their current contents.
746 #[arg(short, long)]
747 pub force: bool,
748
749 /// Print instructions for manually updating your hooks to
750 /// include git-lfs functionality.
751 ///
752 /// Use this option if `git lfs update` fails because of existing
753 /// hooks and you want to retain their functionality.
754 #[arg(short, long)]
755 pub manual: bool,
756}
757
758/// Migrate history to or from Git LFS
759///
760/// Convert files in a Git repository to or from Git LFS pointers, or
761/// summarize Git file sizes by file type. The `import` mode converts
762/// Git files (i.e. blobs) to Git LFS, the `export` mode does the
763/// reverse, and the `info` mode provides an informational summary
764/// useful for deciding which files to import or export.
765///
766/// In all modes, by default `git lfs migrate` operates only on the
767/// currently checked-out branch, and only on files added in commits
768/// which do not exist on any remote. Multiple options are available
769/// to override these defaults — see INCLUDE AND EXCLUDE REFERENCES.
770///
771/// When converting files to or from Git LFS, this command only
772/// changes your local repository and working copy, never any remotes.
773/// `import` and `export` are generally DESTRUCTIVE — they rewrite Git
774/// history, changing commits and generating new commit SHAs. (The
775/// exception is the `--no-rewrite` `import` sub-mode.) Always commit
776/// or stash any uncommitted work first, validate the result before
777/// pushing, and force-push the new history once you're satisfied.
778///
779/// For `info` and `import`, all file types are considered by default.
780/// In `import` you'll usually want filename patterns or `--fixup`;
781/// `export` requires at least one `--include` pattern. See INCLUDE
782/// AND EXCLUDE.
783///
784/// `git lfs migrate` will examine, create, and modify `.gitattributes`
785/// files as necessary. They are always assigned the default
786/// read/write permissions mode; symbolic links with that name halt
787/// the migration.
788#[derive(Args)]
789pub struct MigrateArgs {
790 #[command(subcommand)]
791 pub cmd: MigrateCmd,
792}
793
794#[derive(Subcommand)]
795pub enum MigrateCmd {
796 Import(MigrateImportArgs),
797 Export(MigrateExportArgs),
798 Info(MigrateInfoArgs),
799}
800
801/// Convert Git objects to Git LFS pointers
802///
803/// Migrate objects present in the Git history to pointer files
804/// tracked and stored with Git LFS. Adds entries for the converted
805/// file types to `.gitattributes`, creating those files if they
806/// don't exist — as if `git lfs track` had been run at the points
807/// in history where each type first appears.
808///
809/// With `--fixup`, examine existing `.gitattributes` files and
810/// convert only Git objects that should be tracked by Git LFS
811/// according to those rules but aren't yet.
812///
813/// With `--no-rewrite`, migrate objects to pointers in a single new
814/// commit on top of HEAD without rewriting history. The base
815/// `migrate` options (`--include-ref`, `--everything`, etc.) are
816/// ignored in this sub-mode, and the positional argument list
817/// changes from branches to a list of files. Files must be tracked
818/// by patterns already in `.gitattributes`.
819#[derive(Args)]
820pub struct MigrateImportArgs {
821 // TODO(post-1.0): replace the manual --no-rewrite/--fixup/--above/
822 // --include/--exclude/--everything cross-flag validation
823 // (cli/src/migrate/import.rs:53-77, plus the shared
824 // --everything/positional check in migrate/mod.rs::resolve_refs)
825 // with clap arg_group/conflicts_with. Currently kept as-is because
826 // tests/t-migrate-fixup.sh:94,112,130 and t-migrate-import.sh:814,
827 // 825,836 assert upstream's exact wording (e.g. "--no-rewrite and
828 // --fixup cannot be combined", "Cannot use --everything with
829 // --include-ref or --exclude-ref"). Worth taking once we're free
830 // to update those assertions.
831 /// Branches to rewrite (default: the currently checked-out
832 /// branch). With `--no-rewrite`, instead a list of working-tree
833 /// files to convert. References prefixed with `^` are excluded.
834 pub args: Vec<String>,
835
836 /// Convert paths matching this glob (repeatable, comma-delimited).
837 /// Required unless `--above` is set or `--no-rewrite` is given.
838 #[arg(short = 'I', long = "include")]
839 pub include: Vec<String>,
840
841 /// Exclude paths matching this glob (repeatable, comma-delimited).
842 #[arg(short = 'X', long = "exclude")]
843 pub exclude: Vec<String>,
844
845 /// Restrict the rewrite to commits reachable from these refs.
846 /// Repeatable.
847 #[arg(long = "include-ref")]
848 pub include_ref: Vec<String>,
849
850 /// Exclude commits reachable from these refs. Repeatable.
851 #[arg(long = "exclude-ref")]
852 pub exclude_ref: Vec<String>,
853
854 /// Consider all commits reachable from any local or remote ref.
855 ///
856 /// Only local refs are updated even with `--everything`; remote
857 /// refs stay synchronized with their remote.
858 #[arg(long)]
859 pub everything: bool,
860
861 /// Only migrate files whose individual filesize is above the
862 /// given size (e.g. `1b`, `20 MB`, `3 TiB`).
863 ///
864 /// Cannot be used with `--include`, `--exclude`, or `--fixup`.
865 #[arg(long, default_value = "")]
866 pub above: String,
867
868 /// Migrate objects in a new commit on top of HEAD without
869 /// rewriting Git history.
870 ///
871 /// Switches to a different argument list (positional args become
872 /// files, not branches) and ignores the core `migrate` options
873 /// (`--include-ref`, `--everything`, etc.).
874 #[arg(long)]
875 pub no_rewrite: bool,
876
877 /// Commit message for the `--no-rewrite` commit.
878 ///
879 /// If omitted, a message is generated from the file arguments.
880 #[arg(short, long)]
881 pub message: Option<String>,
882
883 /// Infer `--include` and `--exclude` filters per-commit from the
884 /// repository's `.gitattributes` files.
885 ///
886 /// Imports filepaths that should be tracked by Git LFS but
887 /// aren't yet pointers. Incompatible with explicitly given
888 /// `--include` / `--exclude` filters.
889 #[arg(long)]
890 pub fixup: bool,
891
892 /// Write a CSV of `<OLD-SHA>,<NEW-SHA>` for every rewritten
893 /// commit to the named file.
894 #[arg(long = "object-map")]
895 pub object_map: Option<PathBuf>,
896
897 /// Print the commit OID and filename of migrated files to
898 /// standard output.
899 #[arg(long)]
900 pub verbose: bool,
901
902 /// Remote to consult when fetching missing LFS objects (default
903 /// `origin`).
904 #[arg(long)]
905 pub remote: Option<String>,
906
907 /// Don't refresh the known set of remote references before
908 /// determining the set of "un-pushed" commits to migrate.
909 ///
910 /// Has no effect when combined with `--include-ref` or
911 /// `--exclude-ref`.
912 #[arg(long)]
913 pub skip_fetch: bool,
914
915 /// Assume a yes answer to any prompts, permitting noninteractive
916 /// use.
917 ///
918 /// Currently we don't prompt for any reason, so this is accepted
919 /// as a no-op for upstream parity.
920 #[arg(long)]
921 pub yes: bool,
922}
923
924/// Convert Git LFS pointers to Git objects
925///
926/// Migrate Git LFS pointer files present in the Git history out of
927/// Git LFS, converting them back into their corresponding object
928/// files. Files matching the `--include` patterns are removed from
929/// Git LFS; files matching `--exclude` retain their LFS status.
930/// Modifies `.gitattributes` to set/unset the relevant filepath
931/// patterns.
932///
933/// At least one `--include` pattern is required. Objects not present
934/// in the local LFS store are downloaded from the `--remote`
935/// (defaults to `origin`). Pointers whose objects can't be fetched
936/// are left as-is.
937#[derive(Args)]
938pub struct MigrateExportArgs {
939 // TODO(post-1.0): make --include a required clap arg (it is required
940 // in practice — cli/src/migrate/export.rs:53). Currently kept as a
941 // runtime check because tests/t-migrate-export.sh:208 asserts
942 // upstream's exact wording ("One or more files must be specified
943 // with --include"); clap's "the following required arguments were
944 // not provided: --include <INCLUDE>" would be a strict UX win but
945 // a behavioral diff. Also see the shared --everything/positional
946 // check in migrate/mod.rs::resolve_refs.
947 /// Branches to rewrite (default: the currently checked-out
948 /// branch). References prefixed with `^` are excluded.
949 pub branches: Vec<String>,
950
951 /// Convert pointers at paths matching this glob (repeatable,
952 /// comma-delimited). Required — at least one must be given.
953 #[arg(short = 'I', long = "include")]
954 pub include: Vec<String>,
955
956 /// Don't convert pointers at paths matching this glob
957 /// (repeatable, comma-delimited).
958 #[arg(short = 'X', long = "exclude")]
959 pub exclude: Vec<String>,
960
961 /// Restrict the rewrite to commits reachable from these refs.
962 /// Repeatable.
963 #[arg(long = "include-ref")]
964 pub include_ref: Vec<String>,
965
966 /// Exclude commits reachable from these refs. Repeatable.
967 #[arg(long = "exclude-ref")]
968 pub exclude_ref: Vec<String>,
969
970 /// Consider all commits reachable from any local or remote ref.
971 ///
972 /// Only local refs are updated even with `--everything`; remote
973 /// refs stay synchronized with their remote.
974 #[arg(long)]
975 pub everything: bool,
976
977 /// Write a CSV of `<OLD-SHA>,<NEW-SHA>` for every rewritten
978 /// commit to the named file.
979 ///
980 /// Useful as input to `git filter-repo` or other downstream
981 /// tools.
982 #[arg(long = "object-map")]
983 pub object_map: Option<PathBuf>,
984
985 /// Print the commit OID and filename of migrated files to
986 /// standard output.
987 #[arg(long)]
988 pub verbose: bool,
989
990 /// Download LFS objects from this remote during the export.
991 /// Defaults to `origin`.
992 #[arg(long)]
993 pub remote: Option<String>,
994
995 /// Don't refresh the known set of remote references before the
996 /// rewrite.
997 #[arg(long)]
998 pub skip_fetch: bool,
999
1000 /// Assume a yes answer to any prompts, permitting noninteractive
1001 /// use.
1002 ///
1003 /// Currently we don't prompt for any reason, so this is accepted
1004 /// as a no-op for upstream parity.
1005 #[arg(long)]
1006 pub yes: bool,
1007}
1008
1009/// Show information about repository size
1010///
1011/// Summarize the sizes of file objects present in the Git history,
1012/// grouped by filename extension. Read-only — no objects or history
1013/// change.
1014///
1015/// Existing Git LFS pointers are followed by default (the size of
1016/// the referenced objects is totaled in a separate "LFS Objects"
1017/// line). Use `--pointers=ignore` to skip pointers entirely, or
1018/// `--pointers=no-follow` to count the pointer-text size as if the
1019/// pointers were regular files (the older Git LFS behavior).
1020#[derive(Args)]
1021pub struct MigrateInfoArgs {
1022 // TODO(post-1.0): replace the manual --everything/--include-ref/
1023 // --exclude-ref/--fixup/--pointers/--include/--exclude cross-flag
1024 // validation (cli/src/migrate/info.rs:59-83, plus the shared
1025 // --everything/positional check in migrate/mod.rs::resolve_refs)
1026 // with clap arg_group/conflicts_with. Currently kept as-is because
1027 // tests/t-migrate-info.sh:903,922,941,977,995,1013,1031 assert
1028 // upstream's exact wording (e.g. "Cannot use --fixup with
1029 // --pointers=follow"). The value-conditional --pointers checks
1030 // ("=follow" / "=no-follow") may not all collapse cleanly to
1031 // declarative clap rules.
1032 /// Branches to scan (default: the currently checked-out branch).
1033 /// References prefixed with `^` are excluded.
1034 pub branches: Vec<String>,
1035
1036 /// Only include paths matching this glob (repeatable,
1037 /// comma-delimited).
1038 #[arg(short = 'I', long = "include")]
1039 pub include: Vec<String>,
1040
1041 /// Exclude paths matching this glob (repeatable, comma-delimited).
1042 #[arg(short = 'X', long = "exclude")]
1043 pub exclude: Vec<String>,
1044
1045 /// Restrict the scan to commits reachable from these refs.
1046 /// Repeatable.
1047 #[arg(long = "include-ref")]
1048 pub include_ref: Vec<String>,
1049
1050 /// Exclude commits reachable from these refs. Repeatable.
1051 #[arg(long = "exclude-ref")]
1052 pub exclude_ref: Vec<String>,
1053
1054 /// Consider all commits reachable from any local or remote ref.
1055 #[arg(long)]
1056 pub everything: bool,
1057
1058 /// Only count files whose individual filesize is above the given
1059 /// size (e.g. `1b`, `20 MB`, `3 TiB`).
1060 ///
1061 /// File-extension groups whose largest file is below `--above`
1062 /// don't appear in the output.
1063 #[arg(long, default_value = "")]
1064 pub above: String,
1065
1066 /// Display the top N entries, ordered by total file count.
1067 ///
1068 /// Default 5. When existing Git LFS objects are found, an extra
1069 /// "LFS Objects" line is output in addition to the top N
1070 /// entries (unless `--pointers` changes this).
1071 #[arg(long, default_value_t = 5)]
1072 pub top: usize,
1073
1074 /// How to handle existing LFS pointer blobs.
1075 ///
1076 /// `follow` (default): summarize referenced objects in a separate
1077 /// "LFS Objects" line. `ignore`: skip pointers entirely.
1078 /// `no-follow`: count pointer-text size as if pointers were
1079 /// regular files (the older Git LFS behavior). When `--fixup` is
1080 /// given, defaults to `ignore`.
1081 #[arg(long)]
1082 pub pointers: Option<String>,
1083
1084 /// Format byte quantities in this unit.
1085 ///
1086 /// Valid units: `b, kib, mib, gib, tib, pib` (IEC) or
1087 /// `b, kb, mb, gb, tb, pb` (SI). Auto-scaled when omitted.
1088 #[arg(long)]
1089 pub unit: Option<String>,
1090
1091 /// Infer `--include` and `--exclude` filters per-commit from the
1092 /// repository's `.gitattributes` files.
1093 ///
1094 /// Counts filepaths that should be tracked by Git LFS but aren't
1095 /// yet pointers. Incompatible with explicit `--include` /
1096 /// `--exclude` filters and with `--pointers` settings other than
1097 /// `ignore`. Implies `--pointers=ignore` if not set.
1098 #[arg(long)]
1099 pub fixup: bool,
1100
1101 /// Don't refresh the known set of remote references before the
1102 /// scan.
1103 #[arg(long)]
1104 pub skip_fetch: bool,
1105
1106 /// Remote to consult (currently a no-op; reserved for the
1107 /// auto-fetch path).
1108 #[arg(long)]
1109 pub remote: Option<String>,
1110}
1111
1112/// Populate working copy with real content from Git LFS files.
1113///
1114/// Try to ensure that the working copy contains file content for Git LFS
1115/// objects for the current ref, if the object data is available. Does not
1116/// download any content; see git-lfs-fetch(1) for that.
1117///
1118/// Checkout scans the current ref for all LFS objects that would be
1119/// required, then where a file is either missing in the working copy, or
1120/// contains placeholder pointer content with the same SHA, the real file
1121/// content is written, provided we have it in the local store. Modified
1122/// files are never overwritten.
1123///
1124/// One or more may be provided as arguments to restrict the set of files
1125/// that are updated. Glob patterns are matched as per the format described
1126/// in gitignore(5).
1127///
1128/// When used with `--to` and the working tree is in a conflicted state due
1129/// to a merge, this option checks out one of the three stages a conflicting
1130/// Git LFS object into a separate file (which can be outside of the work
1131/// tree). This can make using diff tools to inspect and resolve merges
1132/// easier. A single Git LFS object's file path must be provided in
1133/// `PATHS`. If `FILE` already exists, whether as a regular
1134/// file, symbolic link, or directory, it will be removed and replaced, unless
1135/// it is a non-empty directory or otherwise cannot be deleted.
1136///
1137/// If the installed Git version is at least 2.42.0,
1138/// this command will by default check out Git LFS objects for files
1139/// only if they are present in the Git index and if they match a Git LFS
1140/// filter attribute from a `.gitattributes` file that is present in either
1141/// the index or the current working tree (or, as is always the case, if
1142/// they match a Git LFS filter attribute in a local gitattributes file
1143/// such as `$GIT_DIR/info/attributes`). These constraints do not apply
1144/// with prior versions of Git.
1145///
1146/// In a repository with a partial clone or sparse checkout, it is therefore
1147/// advisable to check out all `.gitattributes` files from HEAD before
1148/// using this command, if Git v2.42.0 or later is installed. Alternatively,
1149/// the `GIT_ATTR_SOURCE` environment variable may be set to HEAD, which
1150/// will cause Git to only read attributes from `.gitattributes` files in
1151/// HEAD and ignore those in the index or working tree.
1152///
1153/// In a bare repository, this command prints an informational message and
1154/// exits without modifying anything. In a future version, it may exit with
1155/// an error.
1156#[derive(Args)]
1157pub struct CheckoutArgs {
1158 // TODO(post-1.0): replace this manual stage/--to validation with
1159 // clap arg_group/requires/conflicts_with. Currently kept as-is
1160 // because tests/t-checkout.sh:897-909 assert upstream's exact error
1161 // wording; clap's wording would be a strict UX improvement but a
1162 // behavioral diff. Worth taking once we're free to update those
1163 // assertions.
1164 /// Check out the merge base of the specified file
1165 #[arg(long)]
1166 pub base: bool,
1167
1168 /// Check out our side (that of the current branch) of the
1169 /// conflict for the specified file
1170 #[arg(long)]
1171 pub ours: bool,
1172
1173 /// Check out their side (that of the other branch) of the
1174 /// conflict for the specified file
1175 #[arg(long)]
1176 pub theirs: bool,
1177
1178 /// If the working tree is in a conflicted state, check out the
1179 /// portion of the conflict specified by `--base`, `--ours`, or
1180 /// `--theirs` to the given path. Exactly one of these options
1181 /// is required.
1182 #[arg(long, value_name = "FILE")]
1183 pub to: Option<String>,
1184
1185 /// Paths to check out.
1186 ///
1187 /// When empty, everything in HEAD's tree is checked out. In
1188 /// conflict mode (`--to <path>` together with one of `--base`,
1189 /// `--ours`, or `--theirs`), exactly one path is required.
1190 pub paths: Vec<String>,
1191}
1192
1193/// Delete old LFS files from local storage
1194///
1195/// Delete locally stored LFS objects that aren't reachable from HEAD
1196/// or any unpushed commit, freeing up disk space.
1197#[derive(Args)]
1198pub struct PruneArgs {
1199 /// Don't actually delete anything; just report what would have
1200 /// been done.
1201 #[arg(short, long)]
1202 pub dry_run: bool,
1203
1204 /// Report the full detail of what is/would be deleted.
1205 #[arg(short, long)]
1206 pub verbose: bool,
1207
1208 /// Ignore the recent-refs / recent-commits retention windows
1209 /// when computing what is prunable. Equivalent to setting
1210 /// `lfs.fetchrecentrefsdays` and `lfs.fetchrecentcommitsdays` to
1211 /// 0 for this invocation.
1212 #[arg(long)]
1213 pub recent: bool,
1214
1215 /// Treat every pushed object as prunable regardless of the
1216 /// recent-refs / recent-commits / unpushed retention rules.
1217 /// Pointers reachable from HEAD's tree are still kept.
1218 #[arg(short, long)]
1219 pub force: bool,
1220
1221 /// Verify with the remote that prunable objects exist there
1222 /// before deleting them locally. With this on, an object that
1223 /// can't be served by the remote either halts the prune (default)
1224 /// or is dropped from the delete set (`--when-unverified=continue`).
1225 /// Reachable-but-unverified objects are reported as `missing on
1226 /// remote:`; unreachable objects (orphans not in any commit) are
1227 /// silently passed through unless `--verify-unreachable` is also
1228 /// set. Overrides `lfs.pruneverifyremotealways`.
1229 #[arg(short = 'c', long, conflicts_with = "no_verify_remote")]
1230 pub verify_remote: bool,
1231
1232 /// Override `lfs.pruneverifyremotealways=true` and skip the
1233 /// remote verify pass for this invocation.
1234 #[arg(long)]
1235 pub no_verify_remote: bool,
1236
1237 /// When `--verify-remote` is in effect, verify orphan objects
1238 /// (not reachable from any commit) too. Without this, orphans
1239 /// pass through verification silently and are still pruned.
1240 /// Overrides `lfs.pruneverifyunreachablealways`.
1241 #[arg(long, conflicts_with = "no_verify_unreachable")]
1242 pub verify_unreachable: bool,
1243
1244 /// Override `lfs.pruneverifyunreachablealways=true` and skip
1245 /// orphan verification for this invocation.
1246 #[arg(long)]
1247 pub no_verify_unreachable: bool,
1248
1249 /// What to do when `--verify-remote` finds objects missing on
1250 /// the remote. `halt` (the default) refuses the prune and lists
1251 /// the missing OIDs; `continue` drops them from the delete set
1252 /// and prunes the verified ones.
1253 #[arg(long, value_name = "MODE", default_value = "halt", value_parser = ["halt", "continue"])]
1254 pub when_unverified: String,
1255}
1256
1257/// Check Git LFS files for consistency
1258///
1259/// Check all Git LFS files in the current HEAD for consistency.
1260/// Corrupted files are moved to `.git/lfs/bad`.
1261///
1262/// A single committish may be given to inspect that commit instead of
1263/// HEAD. The `<a>..<b>` range form from upstream is not yet supported
1264/// — only a single ref is accepted. With no argument, HEAD is
1265/// examined.
1266///
1267/// The default is to perform all checks. `lfs.fetchexclude` is also
1268/// not yet honored on this command; objects whose paths match the
1269/// exclude list will still be checked.
1270#[derive(Args)]
1271pub struct FsckArgs {
1272 /// Ref to scan. Defaults to HEAD.
1273 pub refspec: Option<String>,
1274
1275 /// Check that each object in HEAD matches its expected hash and
1276 /// that each object exists on disk.
1277 #[arg(long)]
1278 pub objects: bool,
1279
1280 /// Check that each pointer is canonical and that each file which
1281 /// should be stored as a Git LFS file is so stored.
1282 #[arg(long)]
1283 pub pointers: bool,
1284
1285 /// Perform checks, but do not move any corrupted files to
1286 /// `.git/lfs/bad`.
1287 #[arg(short, long)]
1288 pub dry_run: bool,
1289}
1290
1291/// Show the status of Git LFS files in the working tree
1292///
1293/// Display paths of Git LFS objects that have not been pushed to the
1294/// Git LFS server (large files that would be uploaded by `git push`),
1295/// that have differences between the index file and the current HEAD
1296/// commit (large files that would be committed by `git commit`), or
1297/// that have differences between the working tree and the index file
1298/// (files that could be staged with `git add`).
1299///
1300/// Must be run in a non-bare repository.
1301#[derive(Args)]
1302pub struct StatusArgs {
1303 /// Give the output in an easy-to-parse format for scripts.
1304 #[arg(short, long)]
1305 pub porcelain: bool,
1306
1307 /// Write Git LFS file status information as JSON to standard
1308 /// output if the command exits successfully.
1309 ///
1310 /// Intended for interoperation with external tools. If
1311 /// `--porcelain` is also provided, that option takes precedence.
1312 #[arg(short, long)]
1313 pub json: bool,
1314}
1315
1316/// Set a file as "locked" on the Git LFS server
1317///
1318/// Sets the given file path as "locked" against the Git LFS server,
1319/// with the intention of blocking attempts by other users to update
1320/// the given path. Locking a file requires the file to exist in the
1321/// working copy.
1322///
1323/// Once locked, LFS will verify that Git pushes do not modify files
1324/// locked by other users. See the description of the
1325/// `lfs.<url>.locksverify` config key in git-lfs-config(5) for
1326/// details.
1327#[derive(Args)]
1328pub struct LockArgs {
1329 /// Paths to lock. Repo-relative or absolute; must resolve inside
1330 /// the working tree. Upstream's CLI accepts a single path; ours
1331 /// accepts multiple (additive extension).
1332 pub paths: Vec<String>,
1333
1334 /// Specify the Git LFS server to use. Ignored if the `lfs.url`
1335 /// config key is set.
1336 #[arg(short, long)]
1337 pub remote: Option<String>,
1338
1339 /// Write lock info as JSON to standard output if the command
1340 /// exits successfully.
1341 ///
1342 /// Intended for interoperation with external tools. If the command
1343 /// returns with a non-zero exit code, plain text messages are sent
1344 /// to standard error.
1345 #[arg(short, long)]
1346 pub json: bool,
1347
1348 /// Refspec to associate the lock with (extension over upstream).
1349 ///
1350 /// Defaults to the current branch's tracked upstream
1351 /// (`branch.<current>.merge`) or the current branch's full ref
1352 /// (`refs/heads/<branch>`).
1353 #[arg(long = "ref")]
1354 pub refspec: Option<String>,
1355}
1356
1357/// Lists currently locked files from the Git LFS server
1358///
1359/// Lists current locks from the Git LFS server. Without filters, all
1360/// locks visible to the configured remote are returned.
1361#[derive(Args)]
1362pub struct LocksArgs {
1363 /// Specify the Git LFS server to use. Ignored if the `lfs.url`
1364 /// config key is set.
1365 #[arg(short, long)]
1366 pub remote: Option<String>,
1367
1368 /// Specify a lock by its ID. Returns a single result.
1369 #[arg(short, long)]
1370 pub id: Option<String>,
1371
1372 /// Specify a lock by its path. Returns a single result.
1373 #[arg(short, long)]
1374 pub path: Option<String>,
1375
1376 /// List only our own locks which are cached locally. Skips a
1377 /// remote call.
1378 ///
1379 /// Useful when offline or to confirm what `git lfs lock` recorded
1380 /// locally. Combine with `--path` / `--id` / `--limit` to filter;
1381 /// `--verify` is rejected.
1382 #[arg(long)]
1383 pub local: bool,
1384
1385 /// Verify the lock owner on the server and mark our own locks
1386 /// with `O`.
1387 ///
1388 /// Own locks are held by us and the corresponding files can be
1389 /// updated for the next push. All other locks are held by someone
1390 /// else. Contrary to `--local`, this also detects locks held by us
1391 /// despite no local lock information being available (e.g. because
1392 /// the file had been locked from a different clone) and detects
1393 /// "broken" locks (e.g. someone else forcibly unlocked our files).
1394 #[arg(long)]
1395 pub verify: bool,
1396
1397 /// Maximum number of results to return.
1398 #[arg(short, long)]
1399 pub limit: Option<u32>,
1400
1401 /// Write lock info as JSON to standard output if the command
1402 /// exits successfully.
1403 ///
1404 /// Intended for interoperation with external tools. If the command
1405 /// returns with a non-zero exit code, plain text messages are sent
1406 /// to standard error.
1407 #[arg(short, long)]
1408 pub json: bool,
1409
1410 /// Refspec to filter locks by (extension over upstream).
1411 ///
1412 /// Defaults to the current branch's tracked upstream — same
1413 /// auto-resolution as `git lfs lock`.
1414 #[arg(long = "ref")]
1415 pub refspec: Option<String>,
1416}
1417
1418/// Remove "locked" setting for a file on the Git LFS server
1419///
1420/// Removes the given file path as "locked" on the Git LFS server.
1421/// Files must exist and have a clean git status before they can be
1422/// unlocked. The `--force` flag will skip these checks.
1423#[derive(Args)]
1424pub struct UnlockArgs {
1425 // TODO(post-1.0): replace the manual --id-xor-paths check
1426 // (cli/src/lock.rs:301-306) with a clap ArgGroup
1427 // (required = true, multiple = false) covering --id and the
1428 // positional paths arg. Currently kept as-is because
1429 // tests/t-unlock.sh:228,431,482 assert upstream's exact wording
1430 // ("Exactly one of --id or a set of paths must be provided").
1431 // Worth taking once we're free to update those assertions.
1432 /// Paths to unlock. Upstream's CLI accepts a single path; ours
1433 /// accepts multiple (additive extension). Mutually exclusive
1434 /// with `--id`.
1435 pub paths: Vec<String>,
1436
1437 /// Specify the Git LFS server to use. Ignored if the `lfs.url`
1438 /// config key is set.
1439 #[arg(short, long)]
1440 pub remote: Option<String>,
1441
1442 /// Tell the server to remove the lock, even if it's owned by
1443 /// another user.
1444 #[arg(short, long)]
1445 pub force: bool,
1446
1447 /// Specify a lock by its ID instead of path. Mutually exclusive
1448 /// with the positional paths.
1449 #[arg(short, long)]
1450 pub id: Option<String>,
1451
1452 /// Write lock info as JSON to standard output if the command
1453 /// exits successfully.
1454 ///
1455 /// Intended for interoperation with external tools. If the command
1456 /// returns with a non-zero exit code, plain text messages are sent
1457 /// to standard error.
1458 #[arg(short, long)]
1459 pub json: bool,
1460
1461 /// Refspec to send with the unlock request (extension over
1462 /// upstream).
1463 ///
1464 /// Defaults to the current branch's tracked upstream — same
1465 /// auto-resolution as `git lfs lock`.
1466 #[arg(long = "ref")]
1467 pub refspec: Option<String>,
1468}
1469
1470/// Show information about Git LFS files in the index and working tree
1471///
1472/// Display paths of Git LFS files that are found in the tree at the
1473/// given reference. If no reference is given, scan the currently
1474/// checked-out branch.
1475///
1476/// An asterisk (`*`) after the OID indicates a full object, a minus
1477/// (`-`) indicates an LFS pointer.
1478///
1479/// Note: upstream's `--include` / `--exclude` path filters and the
1480/// `--deleted` flag (which shows the full history of the given
1481/// reference, including objects that have been deleted) aren't yet
1482/// supported. The two-references form (`git lfs ls-files <a> <b>`,
1483/// to show files modified between two refs) is also not yet
1484/// supported.
1485#[derive(Args)]
1486pub struct LsFilesArgs {
1487 /// Ref to list. Defaults to HEAD.
1488 pub refspec: Option<String>,
1489
1490 /// Show the entire 64-character OID, instead of just the first
1491 /// 10.
1492 #[arg(short, long)]
1493 pub long: bool,
1494
1495 /// Show the size of the LFS object in parentheses at the end of
1496 /// each line.
1497 #[arg(short, long)]
1498 pub size: bool,
1499
1500 /// Show only the LFS-tracked file names.
1501 #[arg(short, long)]
1502 pub name_only: bool,
1503
1504 /// Inspect the full history of the repository, not the current
1505 /// HEAD (or other provided reference).
1506 ///
1507 /// Includes previous versions of LFS objects that are no longer
1508 /// found in the current tree.
1509 #[arg(short, long)]
1510 pub all: bool,
1511
1512 /// Show as much information as possible about an LFS file.
1513 ///
1514 /// Intended for manual inspection; the exact format may change
1515 /// at any time.
1516 #[arg(short, long)]
1517 pub debug: bool,
1518
1519 /// Write Git LFS file information as JSON to standard output if
1520 /// the command exits successfully.
1521 ///
1522 /// Intended for interoperation with external tools. If `--debug`
1523 /// is also provided, that option takes precedence. If any of
1524 /// `--long`, `--size`, or `--name-only` are provided, those
1525 /// options will have no effect.
1526 #[arg(short, long)]
1527 pub json: bool,
1528}