diff mbox series

[13/14] completion: add default options

Message ID 20190621223107.8022-14-felipe.contreras@gmail.com (mailing list archive)
State New, archived
Headers show
Series completion: a bunch of updates | expand

Commit Message

Felipe Contreras June 21, 2019, 10:31 p.m. UTC
Versions of Git older than v2.17 don't know about
--git-completion-helper, so provide some defaults for them.

Also, some commands fail if there's no Git repository available.

Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 contrib/completion/git-completion.bash | 97 +++++++++++++++++++++++++-
 t/t9902-completion.sh                  |  4 +-
 2 files changed, 98 insertions(+), 3 deletions(-)

Comments

Duy Nguyen June 22, 2019, 3:01 a.m. UTC | #1
On Sat, Jun 22, 2019 at 5:31 AM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> Versions of Git older than v2.17 don't know about
> --git-completion-helper, so provide some defaults for them.
>
> Also, some commands fail if there's no Git repository available.
>
> Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
> ---
>  contrib/completion/git-completion.bash | 97 +++++++++++++++++++++++++-
>  t/t9902-completion.sh                  |  4 +-
>  2 files changed, 98 insertions(+), 3 deletions(-)
>
> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> index d3ee6c7dc2..922ba5f925 100644
> --- a/contrib/completion/git-completion.bash
> +++ b/contrib/completion/git-completion.bash
> @@ -377,6 +377,100 @@ else
>         unset $(compgen -v __gitcomp_builtin_)
>  fi
>
> +__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-
removal --refresh --ignore-errors --ignore-missing --chmod=
--no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit
--no-force --no-update --no-renormalize --no-intent-to-add --no-all
--no-ignore-removal --no-refresh --no-ignore-errors
--no-ignore-missing --no-chmod"

And who's going to keep these uptodate? If you do this, might as well
delete --git-completion-helper

A more acceptable option might be regenerate git-completion.bash and
run --git-completion-helper to generate these, or make
git-completion.bash source a generated file. But that might need some
more build infrastructure, and people who just one to copy the file
might not like it.
Felipe Contreras June 22, 2019, 4:36 a.m. UTC | #2
On Fri, Jun 21, 2019 at 10:02 PM Duy Nguyen <pclouds@gmail.com> wrote:
>
> On Sat, Jun 22, 2019 at 5:31 AM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
> >
> > Versions of Git older than v2.17 don't know about
> > --git-completion-helper, so provide some defaults for them.
> >
> > Also, some commands fail if there's no Git repository available.
> >
> > Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
> > ---
> >  contrib/completion/git-completion.bash | 97 +++++++++++++++++++++++++-
> >  t/t9902-completion.sh                  |  4 +-
> >  2 files changed, 98 insertions(+), 3 deletions(-)
> >
> > diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
> > index d3ee6c7dc2..922ba5f925 100644
> > --- a/contrib/completion/git-completion.bash
> > +++ b/contrib/completion/git-completion.bash
> > @@ -377,6 +377,100 @@ else
> >         unset $(compgen -v __gitcomp_builtin_)
> >  fi
> >
> > +__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-
> removal --refresh --ignore-errors --ignore-missing --chmod=
> --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit
> --no-force --no-update --no-renormalize --no-intent-to-add --no-all
> --no-ignore-removal --no-refresh --no-ignore-errors
> --no-ignore-missing --no-chmod"
>
> And who's going to keep these uptodate?

The same people that kept them up-to-date before git-completion-helper.

> If you do this, might as well delete --git-completion-helper

They serve two different purposes. Say you install the completion of
Git v2.22, but a while later you have Git v2.25; you will get the
updated commands thanks to git-completion-helper, and all the
__gitcomp_builtin_*_default will be ignored.

Granted; that's not the typical situation, as many people get the Git
completion through their distribution in tandem with their Git
version. But remember that these completion scripts are part of
contrib; they are not part of official Git (`make install` doesn't
install them).

When a) most people have a version of git that has
git-completion-helper, and b) most of the issues running commands
outside of a Git repo are resolved, they could be removed. But right
now they do serve a purpose.

> A more acceptable option might be regenerate git-completion.bash and
> run --git-completion-helper to generate these, or make
> git-completion.bash source a generated file. But that might need some
> more build infrastructure, and people who just one to copy the file
> might not like it.

Indeed, I wrote a script to generate these, but I manually copied
them. I could write a script that automatically generates this file if
it's agreed that this is indeed the way we want to go.

But even if these were not up-to-date--as historically has been the
case for most options--and a) you are running a version of Git that
doesn't have git-completion-helper, or b) you run a command that
requires a Git repo; it's better to get outdated options than to get
*nothing*, which is what we get now.

Cheers.
Junio C Hamano June 24, 2019, 5:22 p.m. UTC | #3
Duy Nguyen <pclouds@gmail.com> writes:

> On Sat, Jun 22, 2019 at 5:31 AM Felipe Contreras
> <felipe.contreras@gmail.com> wrote:
>>
>> Versions of Git older than v2.17 don't know about
>> --git-completion-helper, so provide some defaults for them.
> ...
>> +__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-
> removal --refresh --ignore-errors --ignore-missing --chmod=
> --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit
> --no-force --no-update --no-renormalize --no-intent-to-add --no-all
> --no-ignore-removal --no-refresh --no-ignore-errors
> --no-ignore-missing --no-chmod"
>
> And who's going to keep these uptodate? If you do this, might as well
> delete --git-completion-helper
>
> A more acceptable option might be regenerate git-completion.bash and
> run --git-completion-helper to generate these, or make
> git-completion.bash source a generated file.

Nicely analysed and summarized.  What kind of target audience are we
talking about?  What's the payoff vs cost comparison trying to
catering to those who install more recent completion script that
requires the --git-completion-helper option without using antient
Git?

If the cutoff boundary is 2.17, that is more than year ago, and the
boundary gets further and further in the past as time goes by. Also,
depending on how old the version of Git the target user runs, these
hardcoded and manually listed options may not yet even exist in
their binary.
Felipe Contreras June 25, 2019, 1:38 a.m. UTC | #4
On Mon, Jun 24, 2019 at 12:22 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Duy Nguyen <pclouds@gmail.com> writes:
>
> > On Sat, Jun 22, 2019 at 5:31 AM Felipe Contreras
> > <felipe.contreras@gmail.com> wrote:
> >>
> >> Versions of Git older than v2.17 don't know about
> >> --git-completion-helper, so provide some defaults for them.
> > ...
> >> +__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-
> > removal --refresh --ignore-errors --ignore-missing --chmod=
> > --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit
> > --no-force --no-update --no-renormalize --no-intent-to-add --no-all
> > --no-ignore-removal --no-refresh --no-ignore-errors
> > --no-ignore-missing --no-chmod"
> >
> > And who's going to keep these uptodate? If you do this, might as well
> > delete --git-completion-helper
> >
> > A more acceptable option might be regenerate git-completion.bash and
> > run --git-completion-helper to generate these, or make
> > git-completion.bash source a generated file.
>
> Nicely analysed and summarized.  What kind of target audience are we
> talking about?

The people that install their completion independently of their
distribution. A quick search in Stack Overflow shows hundreds of
questions, many related to Homebrew and Cygwin.

> What's the payoff vs cost comparison trying to
> catering to those who install more recent completion script that
> requires the --git-completion-helper option without using antient
> Git?

You use the adjective "ancient", but is it really? The current Ubuntu
LTS release uses
2.17.1, the previous one (supported until 2021) uses 2.7.4, the
current Debian stable uses 2.11.0, and the previous RHEL uses 2.3.5.

Travis CI runs 2.15.1 by default.

If you are going to call these "ancient" what would you call the
current version in Debian oldstable? 2.1.4.

Not everyone is a privileged as us.

> If the cutoff boundary is 2.17, that is more than year ago, and the
> boundary gets further and further in the past as time goes by. Also,
> depending on how old the version of Git the target user runs, these
> hardcoded and manually listed options may not yet even exist in
> their binary.

Indeed, the need for these defaults will diminish over time, but
*right now* people are running versions of Git older than 2.17, for
sure.

And yes, it's possible that the completion will return an option that
doesn't exist yet in the user's version of Git, but historically that
has always been the case regarding Git completions (at least until
git-completion-helper).

So what would you rather have? a) return potentially non-existent
completions, or b) don't complete anything?

Another idea I had is to have a separate 'git completion-helper'
command that could act as a proxy for `git cmd
--git-completion-helper` and `git --list-cmds`. The completion would
throw a warning if such command is missing, then, the person that
installed the completion would have to find a suitable `git
completion-helper` command. We could provide an "example" script that
contains all these defaults. People could modify this to generate the
correct options for different Git versions. Realistically though, most
people will just use the defaults for the latest version, but at least
the responsibility is not on your side.

Cheers.
Duy Nguyen June 25, 2019, 3:32 a.m. UTC | #5
On Tue, Jun 25, 2019 at 8:38 AM Felipe Contreras
<felipe.contreras@gmail.com> wrote:
>
> On Mon, Jun 24, 2019 at 12:22 PM Junio C Hamano <gitster@pobox.com> wrote:
> >
> > Duy Nguyen <pclouds@gmail.com> writes:
> >
> > > On Sat, Jun 22, 2019 at 5:31 AM Felipe Contreras
> > > <felipe.contreras@gmail.com> wrote:
> > >>
> > >> Versions of Git older than v2.17 don't know about
> > >> --git-completion-helper, so provide some defaults for them.
> > > ...
> > >> +__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-
> > > removal --refresh --ignore-errors --ignore-missing --chmod=
> > > --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit
> > > --no-force --no-update --no-renormalize --no-intent-to-add --no-all
> > > --no-ignore-removal --no-refresh --no-ignore-errors
> > > --no-ignore-missing --no-chmod"
> > >
> > > And who's going to keep these uptodate? If you do this, might as well
> > > delete --git-completion-helper
> > >
> > > A more acceptable option might be regenerate git-completion.bash and
> > > run --git-completion-helper to generate these, or make
> > > git-completion.bash source a generated file.
> >
> > Nicely analysed and summarized.  What kind of target audience are we
> > talking about?
>
> The people that install their completion independently of their
> distribution. A quick search in Stack Overflow shows hundreds of
> questions, many related to Homebrew and Cygwin.

Which could be answered with installing the right completion version.
I don't think we make any promise of supporting "old" versions anyway
even if used to work.

I could see we add support to source/preload some generated shell
script, so that it works without --git-completion-helper [1]. But
that's about it, the generated scripts that contain all these
__gitcomp_ variables can be packaged and maintained separately. Then
you could even have multiple completion packages for different git
versions if you want. But I'd rather we (git.git devs) do not maintain
these generated variables by ourselves.

[1] which may even gain interest from Windows crowd because there are
fewer processes to run.
diff mbox series

Patch

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index d3ee6c7dc2..922ba5f925 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -377,6 +377,100 @@  else
 	unset $(compgen -v __gitcomp_builtin_)
 fi
 
+__gitcomp_builtin_add_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-removal --refresh --ignore-errors --ignore-missing --chmod= --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit --no-force --no-update --no-renormalize --no-intent-to-add --no-all --no-ignore-removal --no-refresh --no-ignore-errors --no-ignore-missing --no-chmod"
+__gitcomp_builtin_am_default=" --interactive --3way --quiet --signoff --utf8 --keep --keep-non-patch --message-id --keep-cr --no-keep-cr --scissors --whitespace= --ignore-space-change --ignore-whitespace --directory= --exclude= --include= --patch-format= --reject --resolvemsg= --continue --resolved --skip --abort --quit --show-current-patch --committer-date-is-author-date --ignore-date --rerere-autoupdate --gpg-sign -- --no-interactive --no-3way --no-quiet --no-signoff --no-utf8 --no-keep --no-keep-non-patch --no-message-id --no-scissors --no-whitespace --no-ignore-space-change --no-ignore-whitespace --no-directory --no-exclude --no-include --no-patch-format --no-reject --no-resolvemsg --no-committer-date-is-author-date --no-ignore-date --no-rerere-autoupdate --no-gpg-sign"
+__gitcomp_builtin_apply_default=" --exclude= --include= --no-add --stat --numstat --summary --check --index --intent-to-add --cached --apply --3way --build-fake-ancestor= --whitespace= --ignore-space-change --ignore-whitespace --reverse --unidiff-zero --reject --allow-overlap --verbose --inaccurate-eof --recount --directory= --add -- --no-stat --no-numstat --no-summary --no-check --no-index --no-intent-to-add --no-cached --no-apply --no-3way --no-build-fake-ancestor --no-whitespace --no-ignore-space-change --no-ignore-whitespace --no-reverse --no-unidiff-zero --no-reject --no-allow-overlap --no-verbose --no-inaccurate-eof --no-recount --no-directory"
+__gitcomp_builtin_archive_default=" --output= --remote= --exec= --no-output -- --no-remote --no-exec"
+__gitcomp_builtin_bisect__helper_default=" --next-all --write-terms --bisect-clean-state --check-expected-revs --bisect-reset --bisect-write --check-and-set-terms --bisect-next-check --bisect-terms --bisect-start --no-checkout --no-log --checkout --log"
+__gitcomp_builtin_blame_default=" --incremental --root --show-stats --progress --score-debug --show-name --show-number --porcelain --line-porcelain --show-email --color-lines --color-by-age --indent-heuristic --minimal --contents= --abbrev --no-incremental -- --no-root --no-show-stats --no-progress --no-score-debug --no-show-name --no-show-number --no-porcelain --no-line-porcelain --no-show-email --no-color-lines --no-color-by-age --no-minimal --no-contents --no-abbrev"
+__gitcomp_builtin_branch_default=" --verbose --quiet --track --set-upstream-to= --unset-upstream --color --remotes --contains --no-contains --abbrev --all --delete --move --copy --list --show-current --create-reflog --edit-description --merged --no-merged --column --sort= --points-at= --ignore-case --format= -- --no-verbose --no-quiet --no-track --no-set-upstream-to --no-unset-upstream --no-color --no-remotes --no-abbrev --no-all --no-delete --no-move --no-copy --no-list --no-show-current --no-create-reflog --no-edit-description --no-column --no-points-at --no-ignore-case --no-format"
+__gitcomp_builtin_cat_file_default=" --textconv --filters --path= --allow-unknown-type --buffer --batch --batch-check --follow-symlinks --batch-all-objects --unordered --no-path -- --no-allow-unknown-type --no-buffer --no-follow-symlinks --no-batch-all-objects --no-unordered"
+__gitcomp_builtin_check_attr_default=" --all --cached --stdin --no-all -- --no-cached --no-stdin"
+__gitcomp_builtin_check_ignore_default=" --quiet --verbose --stdin --non-matching --no-index --index -- --no-quiet --no-verbose --no-stdin --no-non-matching"
+__gitcomp_builtin_check_mailmap_default=" --stdin --no-stdin"
+__gitcomp_builtin_checkout_default=" --quiet --detach --track --orphan= --ours --theirs --merge --conflict= --patch --ignore-skip-worktree-bits --no-guess --ignore-other-worktrees --recurse-submodules --progress --overlay --guess -- --no-quiet --no-detach --no-track --no-orphan --no-merge --no-conflict --no-patch --no-ignore-skip-worktree-bits --no-ignore-other-worktrees --no-recurse-submodules --no-progress --no-overlay"
+__gitcomp_builtin_checkout_index_default=" --all --force --quiet --no-create --index --stdin --temp --prefix= --stage= --create -- --no-all --no-force --no-quiet --no-index --no-stdin --no-temp --no-prefix"
+__gitcomp_builtin_cherry_default=" --abbrev --verbose --no-abbrev -- --no-verbose"
+__gitcomp_builtin_cherry_pick_default=" --quit --continue --abort --cleanup= --no-commit --edit --signoff --mainline= --rerere-autoupdate --strategy= --strategy-option= --gpg-sign --ff --allow-empty --allow-empty-message --keep-redundant-commits --commit -- --no-cleanup --no-edit --no-signoff --no-mainline --no-rerere-autoupdate --no-strategy --no-strategy-option --no-gpg-sign --no-ff --no-allow-empty --no-allow-empty-message --no-keep-redundant-commits"
+__gitcomp_builtin_clean_default=" --quiet --dry-run --interactive --exclude= --no-quiet -- --no-dry-run --no-interactive"
+__gitcomp_builtin_clone_default=" --verbose --quiet --progress --no-checkout --bare --mirror --local --no-hardlinks --shared --recursive --recurse-submodules --jobs= --template= --reference= --reference-if-able= --dissociate --origin= --branch= --upload-pack= --depth= --shallow-since= --shallow-exclude= --single-branch --no-tags --shallow-submodules --separate-git-dir= --config= --server-option= --ipv4 --ipv6 --filter= --checkout --hardlinks --tags -- --no-verbose --no-quiet --no-progress --no-bare --no-mirror --no-local --no-shared --no-recursive --no-recurse-submodules --no-jobs --no-template --no-reference --no-reference-if-able --no-dissociate --no-origin --no-branch --no-upload-pack --no-depth --no-shallow-since --no-shallow-exclude --no-single-branch --no-shallow-submodules --no-separate-git-dir --no-config --no-server-option --no-ipv4 --no-ipv6 --no-filter"
+__gitcomp_builtin_column_default=" --command= --mode --raw-mode= --width= --indent= --nl= --padding= --no-command -- --no-mode --no-raw-mode --no-width --no-indent --no-nl --no-padding"
+__gitcomp_builtin_commit_default=" --quiet --verbose --file= --author= --date= --message= --reedit-message= --reuse-message= --fixup= --squash= --reset-author --signoff --template= --edit --cleanup= --status --gpg-sign --all --include --interactive --patch --only --no-verify --dry-run --short --branch --ahead-behind --porcelain --long --null --amend --no-post-rewrite --untracked-files --verify --post-rewrite -- --no-quiet --no-verbose --no-file --no-author --no-date --no-message --no-reedit-message --no-reuse-message --no-fixup --no-squash --no-reset-author --no-signoff --no-template --no-edit --no-cleanup --no-status --no-gpg-sign --no-all --no-include --no-interactive --no-patch --no-only --no-dry-run --no-short --no-branch --no-ahead-behind --no-porcelain --no-long --no-null --no-amend --no-untracked-files"
+__gitcomp_builtin_commit_graph_default=" --object-dir= --no-object-dir"
+__gitcomp_builtin_config_default=" --global --system --local --worktree --file= --blob= --get --get-all --get-regexp --get-urlmatch --replace-all --add --unset --unset-all --rename-section --remove-section --list --edit --get-color --get-colorbool --type= --bool --int --bool-or-int --path --expiry-date --null --name-only --includes --show-origin --default= --no-global -- --no-system --no-local --no-worktree --no-file --no-blob --no-get --no-get-all --no-get-regexp --no-get-urlmatch --no-replace-all --no-add --no-unset --no-unset-all --no-rename-section --no-remove-section --no-list --no-edit --no-get-color --no-get-colorbool --no-type --no-null --no-name-only --no-includes --no-show-origin --no-default"
+__gitcomp_builtin_count_objects_default=" --verbose --human-readable --no-verbose -- --no-human-readable"
+__gitcomp_builtin_describe_default=" --contains --debug --all --tags --long --first-parent --abbrev --exact-match --candidates= --match= --exclude= --always --dirty --broken --no-contains -- --no-debug --no-all --no-tags --no-long --no-first-parent --no-abbrev --no-exact-match --no-candidates --no-match --no-exclude --no-always --no-dirty --no-broken"
+__gitcomp_builtin_difftool_default=" --gui --dir-diff --no-prompt --symlinks --tool= --tool-help --trust-exit-code --extcmd= --no-index -- --no-gui --no-dir-diff --no-symlinks --no-tool --no-tool-help --no-trust-exit-code --no-extcmd"
+__gitcomp_builtin_fast_export_default=" --progress= --signed-tags= --tag-of-filtered-object= --export-marks= --import-marks= --fake-missing-tagger --full-tree --use-done-feature --no-data --refspec= --anonymize --reference-excluded-parents --show-original-ids --data -- --no-progress --no-signed-tags --no-tag-of-filtered-object --no-export-marks --no-import-marks --no-fake-missing-tagger --no-full-tree --no-use-done-feature --no-refspec --no-anonymize --no-reference-excluded-parents --no-show-original-ids"
+__gitcomp_builtin_fetch_default=" --verbose --quiet --all --append --upload-pack= --force --multiple --tags --jobs= --prune --prune-tags --recurse-submodules --dry-run --keep --update-head-ok --progress --depth= --shallow-since= --shallow-exclude= --deepen= --unshallow --update-shallow --refmap= --server-option= --ipv4 --ipv6 --negotiation-tip= --filter= --no-verbose -- --no-quiet --no-all --no-append --no-upload-pack --no-force --no-multiple --no-tags --no-jobs --no-prune --no-prune-tags --no-recurse-submodules --no-dry-run --no-keep --no-update-head-ok --no-progress --no-depth --no-shallow-since --no-shallow-exclude --no-deepen --no-update-shallow --no-server-option --no-ipv4 --no-ipv6 --no-negotiation-tip --no-filter"
+__gitcomp_builtin_fmt_merge_msg_default=" --log --message= --file= --no-log -- --no-message --no-file"
+__gitcomp_builtin_for_each_ref_default=" --shell --perl --python --tcl --count= --format= --color --sort= --points-at= --merged --no-merged --contains --no-contains --ignore-case -- --no-shell --no-perl --no-python --no-tcl --no-count --no-format --no-color --no-points-at --no-ignore-case"
+__gitcomp_builtin_format_patch_default=" --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --rfc --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --to= --cc= --from --in-reply-to= --attach --inline --thread --signature= --base= --signature-file= --quiet --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-numbered --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-to --no-cc --no-from --no-in-reply-to --no-attach --no-thread --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor"
+__gitcomp_builtin_fsck_default=" --verbose --unreachable --dangling --tags --root --cache --reflogs --full --connectivity-only --strict --lost-found --progress --name-objects --no-verbose -- --no-unreachable --no-dangling --no-tags --no-root --no-cache --no-reflogs --no-full --no-connectivity-only --no-strict --no-lost-found --no-progress --no-name-objects"
+__gitcomp_builtin_fsck_objects_default=" --verbose --unreachable --dangling --tags --root --cache --reflogs --full --connectivity-only --strict --lost-found --progress --name-objects --no-verbose -- --no-unreachable --no-dangling --no-tags --no-root --no-cache --no-reflogs --no-full --no-connectivity-only --no-strict --no-lost-found --no-progress --no-name-objects"
+__gitcomp_builtin_gc_default=" --quiet --prune --aggressive --keep-largest-pack --no-quiet -- --no-prune --no-aggressive --no-keep-largest-pack"
+__gitcomp_builtin_grep_default=" --cached --no-index --untracked --exclude-standard --recurse-submodules --invert-match --ignore-case --word-regexp --text --textconv --recursive --max-depth= --extended-regexp --basic-regexp --fixed-strings --perl-regexp --line-number --column --full-name --files-with-matches --name-only --files-without-match --only-matching --count --color --break --heading --context= --before-context= --after-context= --threads= --show-function --function-context --and --or --not --quiet --all-match --index -- --no-cached --no-untracked --no-exclude-standard --no-recurse-submodules --no-invert-match --no-ignore-case --no-word-regexp --no-text --no-textconv --no-recursive --no-extended-regexp --no-basic-regexp --no-fixed-strings --no-perl-regexp --no-line-number --no-column --no-full-name --no-files-with-matches --no-name-only --no-files-without-match --no-only-matching --no-count --no-color --no-break --no-heading --no-context --no-before-context --no-after-context --no-threads --no-show-function --no-function-context --no-or --no-quiet --no-all-match"
+__gitcomp_builtin_hash_object_default=" --stdin --stdin-paths --no-filters --literally --path= --filters -- --no-stdin --no-stdin-paths --no-literally --no-path"
+__gitcomp_builtin_help_default=" --all --guides --config --man --web --info --verbose --no-all -- --no-guides --no-config --no-man --no-web --no-info --no-verbose"
+__gitcomp_builtin_init_default=" --template= --bare --shared --quiet --separate-git-dir= --no-template -- --no-bare --no-quiet --no-separate-git-dir"
+__gitcomp_builtin_init_db_default=" --template= --bare --shared --quiet --separate-git-dir= --no-template -- --no-bare --no-quiet --no-separate-git-dir"
+__gitcomp_builtin_interpret_trailers_default=" --in-place --trim-empty --where= --if-exists= --if-missing= --only-trailers --only-input --unfold --parse --no-divider --trailer= --divider -- --no-in-place --no-trim-empty --no-where --no-if-exists --no-if-missing --no-only-trailers --no-only-input --no-unfold --no-trailer"
+__gitcomp_builtin_log_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate"
+__gitcomp_builtin_ls_files_default=" --cached --deleted --modified --others --ignored --stage --killed --directory --eol --empty-directory --unmerged --resolve-undo --exclude= --exclude-from= --exclude-per-directory= --exclude-standard --full-name --recurse-submodules --error-unmatch --with-tree= --abbrev --debug --no-cached -- --no-deleted --no-modified --no-others --no-ignored --no-stage --no-killed --no-directory --no-eol --no-empty-directory --no-unmerged --no-resolve-undo --no-exclude-per-directory --no-recurse-submodules --no-error-unmatch --no-with-tree --no-abbrev --no-debug"
+__gitcomp_builtin_ls_remote_default=" --quiet --upload-pack= --tags --heads --refs --get-url --sort= --symref --server-option= --no-quiet -- --no-upload-pack --no-tags --no-heads --no-refs --no-get-url --no-symref --no-server-option"
+__gitcomp_builtin_ls_tree_default=" --long --name-only --name-status --full-name --full-tree --abbrev --no-long -- --no-name-only --no-name-status --no-full-name --no-full-tree --no-abbrev"
+__gitcomp_builtin_merge_default=" --stat --summary --log --squash --commit --edit --cleanup= --ff --ff-only --rerere-autoupdate --verify-signatures --strategy= --strategy-option= --message= --file --verbose --quiet --abort --continue --allow-unrelated-histories --progress --gpg-sign --overwrite-ignore --signoff --verify --no-stat -- --no-summary --no-log --no-squash --no-commit --no-edit --no-cleanup --no-ff --no-rerere-autoupdate --no-verify-signatures --no-strategy --no-strategy-option --no-message --no-verbose --no-quiet --no-abort --no-continue --no-allow-unrelated-histories --no-progress --no-gpg-sign --no-overwrite-ignore --no-signoff --no-verify"
+__gitcomp_builtin_merge_base_default=" --all --octopus --independent --is-ancestor --fork-point --no-all"
+__gitcomp_builtin_merge_file_default=" --stdout --diff3 --ours --theirs --union --marker-size= --quiet --no-stdout -- --no-diff3 --no-ours --no-theirs --no-union --no-marker-size --no-quiet"
+__gitcomp_builtin_mktree_default=" --missing --batch --no-missing -- --no-batch"
+__gitcomp_builtin_multi_pack_index_default=" --object-dir= --no-object-dir"
+__gitcomp_builtin_mv_default=" --verbose --dry-run --no-verbose -- --no-dry-run"
+__gitcomp_builtin_name_rev_default=" --name-only --tags --refs= --exclude= --all --stdin --undefined --always --no-name-only -- --no-tags --no-refs --no-exclude --no-all --no-stdin --no-undefined --no-always"
+__gitcomp_builtin_notes_default=" --ref= --no-ref"
+__gitcomp_builtin_pack_objects_default=" --quiet --progress --all-progress --all-progress-implied --index-version= --max-pack-size= --local --incremental --window= --window-memory= --depth= --reuse-delta --reuse-object --delta-base-offset --threads= --non-empty --revs --unpacked --all --reflog --indexed-objects --stdout --include-tag --keep-unreachable --pack-loose-unreachable --unpack-unreachable --sparse --thin --shallow --honor-pack-keep --keep-pack= --compression= --keep-true-parents --use-bitmap-index --write-bitmap-index --filter= --missing= --exclude-promisor-objects --delta-islands --no-quiet -- --no-progress --no-all-progress --no-all-progress-implied --no-local --no-incremental --no-window --no-depth --no-reuse-delta --no-reuse-object --no-delta-base-offset --no-threads --no-non-empty --no-revs --no-stdout --no-include-tag --no-keep-unreachable --no-pack-loose-unreachable --no-unpack-unreachable --no-sparse --no-thin --no-shallow --no-honor-pack-keep --no-keep-pack --no-compression --no-keep-true-parents --no-use-bitmap-index --no-write-bitmap-index --no-filter --no-exclude-promisor-objects --no-delta-islands"
+__gitcomp_builtin_pack_refs_default=" --all --prune --no-all -- --no-prune"
+__gitcomp_builtin_pickaxe_default=" --incremental --root --show-stats --progress --score-debug --show-name --show-number --porcelain --line-porcelain --show-email --color-lines --color-by-age --indent-heuristic --minimal --contents= --abbrev --no-incremental -- --no-root --no-show-stats --no-progress --no-score-debug --no-show-name --no-show-number --no-porcelain --no-line-porcelain --no-show-email --no-color-lines --no-color-by-age --no-minimal --no-contents --no-abbrev"
+__gitcomp_builtin_prune_default=" --dry-run --verbose --progress --expire= --exclude-promisor-objects --no-dry-run -- --no-verbose --no-progress --no-expire --no-exclude-promisor-objects"
+__gitcomp_builtin_prune_packed_default=" --dry-run --quiet --no-dry-run -- --no-quiet"
+__gitcomp_builtin_pull_default=" --verbose --quiet --progress --recurse-submodules --rebase --stat --log --signoff --squash --commit --edit --cleanup= --ff --ff-only --verify-signatures --autostash --strategy= --strategy-option= --gpg-sign --allow-unrelated-histories --all --append --upload-pack= --force --tags --prune --jobs --dry-run --keep --depth= --unshallow --update-shallow --refmap= --ipv4 --ipv6 --no-verbose -- --no-quiet --no-progress --no-recurse-submodules --no-rebase --no-stat --no-log --no-signoff --no-squash --no-commit --no-edit --no-cleanup --no-ff --no-verify-signatures --no-autostash --no-strategy --no-strategy-option --no-gpg-sign --no-allow-unrelated-histories --no-all --no-append --no-upload-pack --no-force --no-tags --no-prune --no-jobs --no-dry-run --no-keep --no-depth --no-update-shallow --no-ipv4 --no-ipv6"
+__gitcomp_builtin_push_default=" --verbose --quiet --repo= --all --mirror --delete --tags --dry-run --porcelain --force --force-with-lease --recurse-submodules --receive-pack= --exec= --set-upstream --progress --prune --no-verify --follow-tags --signed --atomic --push-option= --ipv4 --ipv6 --verify -- --no-verbose --no-quiet --no-repo --no-all --no-mirror --no-delete --no-tags --no-dry-run --no-porcelain --no-force --no-force-with-lease --no-recurse-submodules --no-receive-pack --no-exec --no-set-upstream --no-progress --no-prune --no-follow-tags --no-signed --no-atomic --no-push-option --no-ipv4 --no-ipv6"
+__gitcomp_builtin_range_diff_default=" --creation-factor= --no-dual-color --patch --no-patch --unified --function-context --raw --patch-with-raw --patch-with-stat --numstat --shortstat --dirstat --cumulative --dirstat-by-file --check --summary --name-only --name-status --stat --stat-width= --stat-name-width= --stat-graph-width= --stat-count= --compact-summary --binary --full-index --color --ws-error-highlight= --abbrev --src-prefix= --dst-prefix= --line-prefix= --no-prefix --inter-hunk-context= --output-indicator-new= --output-indicator-old= --output-indicator-context= --break-rewrites --find-renames --irreversible-delete --find-copies --find-copies-harder --no-renames --rename-empty --follow --minimal --ignore-all-space --ignore-space-change --ignore-space-at-eol --ignore-cr-at-eol --ignore-blank-lines --indent-heuristic --patience --histogram --diff-algorithm= --anchored= --word-diff --word-diff-regex= --color-words --color-moved --color-moved-ws= --relative --text --exit-code --quiet --ext-diff --textconv --ignore-submodules --submodule --ita-invisible-in-index --ita-visible-in-index --pickaxe-all --pickaxe-regex --find-object= --diff-filter= --output= --dual-color -- --no-creation-factor --no-function-context --no-compact-summary --no-full-index --no-color --no-abbrev --no-find-copies-harder --no-rename-empty --no-follow --no-minimal --no-indent-heuristic --no-color-moved --no-color-moved-ws --no-text --no-exit-code --no-quiet --no-ext-diff --no-textconv"
+__gitcomp_builtin_read_tree_default=" --index-output= --empty --verbose --trivial --aggressive --reset --prefix= --exclude-per-directory= --dry-run --no-sparse-checkout --debug-unpack --recurse-submodules --quiet --sparse-checkout -- --no-empty --no-verbose --no-trivial --no-aggressive --no-reset --no-dry-run --no-debug-unpack --no-recurse-submodules --no-quiet"
+__gitcomp_builtin_rebase_default=" --onto= --no-verify --quiet --verbose --no-stat --signoff --ignore-whitespace --committer-date-is-author-date --ignore-date --whitespace= --force-rebase --no-ff --continue --skip --abort --quit --edit-todo --show-current-patch --merge --interactive --preserve-merges --rerere-autoupdate --keep-empty --autosquash --gpg-sign --autostash --exec= --allow-empty-message --rebase-merges --fork-point --strategy= --strategy-option= --root --reschedule-failed-exec --verify --stat --ff -- --no-onto --no-quiet --no-verbose --no-signoff --no-ignore-whitespace --no-committer-date-is-author-date --no-ignore-date --no-whitespace --no-force-rebase --no-preserve-merges --no-rerere-autoupdate --no-keep-empty --no-autosquash --no-gpg-sign --no-autostash --no-exec --no-allow-empty-message --no-rebase-merges --no-fork-point --no-strategy --no-strategy-option --no-root --no-reschedule-failed-exec"
+__gitcomp_builtin_rebase__interactive_default=" --ff --keep-empty --allow-empty-message --rebase-merges --rebase-cousins --autosquash --signoff --verbose --continue --skip --edit-todo --show-current-patch --shorten-ids --expand-ids --check-todo-list --rearrange-squash --add-exec-commands --onto= --restrict-revision= --squash-onto= --upstream= --head-name= --gpg-sign --strategy= --strategy-opts= --switch-to= --onto-name= --cmd= --rerere-autoupdate --reschedule-failed-exec --no-ff -- --no-keep-empty --no-allow-empty-message --no-rebase-merges --no-rebase-cousins --no-autosquash --no-signoff --no-verbose --no-head-name --no-gpg-sign --no-strategy --no-strategy-opts --no-switch-to --no-onto-name --no-cmd --no-rerere-autoupdate --no-reschedule-failed-exec"
+__gitcomp_builtin_receive_pack_default=" --quiet --no-quiet"
+__gitcomp_builtin_reflog_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate"
+__gitcomp_builtin_remote_default=" --verbose --no-verbose"
+__gitcomp_builtin_repack_default=" --quiet --local --write-bitmap-index --delta-islands --unpack-unreachable= --keep-unreachable --window= --window-memory= --depth= --threads= --max-pack-size= --pack-kept-objects --keep-pack= --no-quiet -- --no-local --no-write-bitmap-index --no-delta-islands --no-unpack-unreachable --no-keep-unreachable --no-window --no-window-memory --no-depth --no-threads --no-max-pack-size --no-pack-kept-objects --no-keep-pack"
+__gitcomp_builtin_replace_default=" --list --delete --edit --graft --convert-graft-file --raw --format= --no-raw -- --no-format"
+__gitcomp_builtin_rerere_default=" --rerere-autoupdate --no-rerere-autoupdate"
+__gitcomp_builtin_reset_default=" --quiet --mixed --soft --hard --merge --keep --recurse-submodules --patch --intent-to-add --no-quiet -- --no-mixed --no-soft --no-hard --no-merge --no-keep --no-recurse-submodules --no-patch --no-intent-to-add"
+__gitcomp_builtin_revert_default=" --quit --continue --abort --cleanup= --no-commit --edit --signoff --mainline= --rerere-autoupdate --strategy= --strategy-option= --gpg-sign --commit -- --no-cleanup --no-edit --no-signoff --no-mainline --no-rerere-autoupdate --no-strategy --no-strategy-option --no-gpg-sign"
+__gitcomp_builtin_rm_default=" --dry-run --quiet --cached --ignore-unmatch --no-dry-run -- --no-quiet --no-cached --no-ignore-unmatch"
+__gitcomp_builtin_send_pack_default=" --verbose --quiet --receive-pack= --exec= --remote= --all --dry-run --mirror --force --signed --push-option= --progress --thin --atomic --stateless-rpc --stdin --helper-status --force-with-lease --no-verbose -- --no-quiet --no-receive-pack --no-exec --no-remote --no-all --no-dry-run --no-mirror --no-force --no-signed --no-push-option --no-progress --no-thin --no-atomic --no-stateless-rpc --no-stdin --no-helper-status --no-force-with-lease"
+__gitcomp_builtin_shortlog_default=" --committer --numbered --summary --email --no-committer -- --no-numbered --no-summary --no-email"
+__gitcomp_builtin_show_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate"
+__gitcomp_builtin_show_branch_default=" --all --remotes --color --more --list --no-name --current --sha1-name --merge-base --independent --topo-order --topics --sparse --date-order --reflog --name -- --no-all --no-remotes --no-color --no-more --no-list --no-current --no-sha1-name --no-merge-base --no-independent --no-topo-order --no-topics --no-sparse --no-date-order"
+__gitcomp_builtin_show_index_default=""
+__gitcomp_builtin_show_ref_default=" --tags --heads --verify --head --dereference --hash --abbrev --quiet --exclude-existing --no-tags -- --no-heads --no-verify --no-head --no-dereference --no-hash --no-abbrev --no-quiet"
+__gitcomp_builtin_stage_default=" --dry-run --verbose --interactive --patch --edit --force --update --renormalize --intent-to-add --all --ignore-removal --refresh --ignore-errors --ignore-missing --chmod= --no-dry-run -- --no-verbose --no-interactive --no-patch --no-edit --no-force --no-update --no-renormalize --no-intent-to-add --no-all --no-ignore-removal --no-refresh --no-ignore-errors --no-ignore-missing --no-chmod"
+__gitcomp_builtin_stash_default=""
+__gitcomp_builtin_status_default=" --verbose --short --branch --show-stash --ahead-behind --porcelain --long --null --untracked-files --ignored --ignore-submodules --column --no-renames --find-renames --renames -- --no-verbose --no-short --no-branch --no-show-stash --no-ahead-behind --no-porcelain --no-long --no-null --no-untracked-files --no-ignored --no-ignore-submodules --no-column"
+__gitcomp_builtin_stripspace_default=" --strip-comments --comment-lines"
+__gitcomp_builtin_symbolic_ref_default=" --quiet --delete --short --no-quiet -- --no-delete --no-short"
+__gitcomp_builtin_tag_default=" --list --delete --verify --annotate --message= --file= --edit --sign --cleanup= --local-user= --force --create-reflog --column --contains --no-contains --merged --no-merged --sort= --points-at --format= --color --ignore-case -- --no-annotate --no-file --no-edit --no-sign --no-cleanup --no-local-user --no-force --no-create-reflog --no-column --no-points-at --no-format --no-color --no-ignore-case"
+__gitcomp_builtin_update_index_default=" --ignore-submodules --add --replace --remove --unmerged --refresh --really-refresh --cacheinfo --chmod= --assume-unchanged --no-assume-unchanged --skip-worktree --no-skip-worktree --info-only --force-remove --stdin --index-info --unresolve --again --ignore-missing --verbose --clear-resolve-undo --index-version= --split-index --untracked-cache --test-untracked-cache --force-untracked-cache --force-write-index --fsmonitor --fsmonitor-valid --no-fsmonitor-valid -- --no-ignore-submodules --no-add --no-replace --no-remove --no-unmerged --no-info-only --no-force-remove --no-ignore-missing --no-verbose --no-index-version --no-split-index --no-untracked-cache --no-test-untracked-cache --no-force-untracked-cache --no-force-write-index --no-fsmonitor"
+__gitcomp_builtin_update_ref_default=" --no-deref --stdin --create-reflog --deref -- --no-stdin --no-create-reflog"
+__gitcomp_builtin_update_server_info_default=" --force --no-force"
+__gitcomp_builtin_upload_pack_default=" --stateless-rpc --advertise-refs --strict --timeout= --no-stateless-rpc -- --no-advertise-refs --no-strict --no-timeout"
+__gitcomp_builtin_verify_commit_default=" --verbose --raw --no-verbose -- --no-raw"
+__gitcomp_builtin_verify_pack_default=" --verbose --stat-only --no-verbose -- --no-stat-only"
+__gitcomp_builtin_verify_tag_default=" --verbose --raw --format= --no-verbose -- --no-raw --no-format"
+__gitcomp_builtin_version_default=" --build-options --no-build-options"
+__gitcomp_builtin_whatchanged_default=" --quiet --source --use-mailmap --decorate-refs= --decorate-refs-exclude= --decorate --no-quiet -- --no-source --no-use-mailmap --no-decorate-refs --no-decorate-refs-exclude --no-decorate"
+__gitcomp_builtin_write_tree_default=" --missing-ok --prefix= --no-missing-ok -- --no-prefix"
+__gitcomp_builtin_send_email_default=" --numbered --no-numbered --signoff --stdout --cover-letter --numbered-files --suffix= --start-number= --reroll-count= --rfc --subject-prefix= --output-directory= --keep-subject --no-binary --zero-commit --ignore-if-in-upstream --no-stat --add-header= --to= --cc= --from --in-reply-to= --attach --inline --thread --signature= --base= --signature-file= --quiet --progress --interdiff= --range-diff= --creation-factor= --binary -- --no-numbered --no-signoff --no-stdout --no-cover-letter --no-numbered-files --no-suffix --no-start-number --no-reroll-count --no-zero-commit --no-ignore-if-in-upstream --no-add-header --no-to --no-cc --no-from --no-in-reply-to --no-attach --no-thread --no-signature --no-base --no-signature-file --no-quiet --no-progress --no-interdiff --no-range-diff --no-creation-factor"
+
 # This function is equivalent to
 #
 #    __gitcomp "$(git xxx --git-completion-helper) ..."
@@ -400,7 +494,8 @@  __gitcomp_builtin ()
 	if [ -z "$options" ]; then
 		# leading and trailing spaces are significant to make
 		# option removal work correctly.
-		options=" $incl $(__git ${cmd/_/ } --git-completion-helper) "
+		options=" $incl $(__git ${cmd/_/ } --git-completion-helper) " ||
+			eval "options=\" $incl \$${var}_default \""
 		for i in $excl; do
 			options="${options/ $i / }"
 		done
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 3dbfef6960..14598bfbec 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -1428,7 +1428,7 @@  test_expect_success 'double dash "git" itself' '
 	EOF
 '
 
-test_expect_failure 'double dash "git checkout"' '
+test_expect_success 'double dash "git checkout"' '
 	offgit &&
 	test_completion "git checkout --" <<-\EOF
 	--quiet Z
@@ -1561,7 +1561,7 @@  test_expect_success 'complete tree filename with metacharacters' '
 	EOF
 '
 
-test_expect_failure PERL 'send-email' '
+test_expect_success PERL 'send-email' '
 	test_completion "git send-email ma" "master " &&
 	offgit &&
 	test_completion "git send-email --cov" "--cover-letter "