2011-04-27 05:23:35 +02:00
|
|
|
# bash/zsh completion support for core Git.
|
2006-09-28 11:31:25 +02:00
|
|
|
#
|
2007-05-24 07:36:46 +02:00
|
|
|
# Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org>
|
2006-09-28 11:31:25 +02:00
|
|
|
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/).
|
2007-05-24 07:36:46 +02:00
|
|
|
# Distributed under the GNU General Public License, version 2.0.
|
2006-09-28 11:31:25 +02:00
|
|
|
#
|
|
|
|
# The contained completion routines provide support for completing:
|
|
|
|
#
|
|
|
|
# *) local and remote branch names
|
|
|
|
# *) local and remote tag names
|
|
|
|
# *) .git/remotes file names
|
|
|
|
# *) git 'subcommands'
|
2015-11-19 23:52:12 +01:00
|
|
|
# *) git email aliases for git-send-email
|
2006-09-28 11:31:25 +02:00
|
|
|
# *) tree paths within 'ref:path/to/file' expressions
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
# *) file paths within current working directory and index
|
2007-05-24 07:36:46 +02:00
|
|
|
# *) common --long-options
|
2006-09-28 11:31:25 +02:00
|
|
|
#
|
|
|
|
# To use these routines:
|
|
|
|
#
|
2014-12-15 15:34:28 +01:00
|
|
|
# 1) Copy this file to somewhere (e.g. ~/.git-completion.bash).
|
2011-04-27 05:23:35 +02:00
|
|
|
# 2) Add the following line to your .bashrc/.zshrc:
|
2014-12-15 15:34:28 +01:00
|
|
|
# source ~/.git-completion.bash
|
2012-05-22 22:46:40 +02:00
|
|
|
# 3) Consider changing your PS1 to also show the current branch,
|
|
|
|
# see git-prompt.sh for details.
|
2014-06-12 20:49:29 +02:00
|
|
|
#
|
|
|
|
# If you use complex aliases of form '!f() { ... }; f', you can use the null
|
|
|
|
# command ':' as the first command in the function body to declare the desired
|
|
|
|
# completion style. For example '!f() { : git commit ; ... }; f' will
|
|
|
|
# tell the completion to use commit completion. This also works with aliases
|
|
|
|
# of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '".
|
completion: optionally disable checkout DWIM
When we complete branch names for "git checkout", we also
complete remote branch names that could trigger the DWIM
behavior. Depending on your workflow and project, this can
be either convenient or annoying.
For instance, my clone of gitster.git contains 74 local
"jk/*" branches, but origin contains another 147. When I
want to checkout a local branch but can't quite remember the
name, tab completion shows me 251 entries. And worse, for a
topic that has been picked up for pu, the upstream branch
name is likely to be similar to mine, leading to a high
probability that I pick the wrong one and accidentally
create a new branch.
This patch adds a way for the user to tell the completion
code not to include DWIM suggestions for checkout. This can
already be done by typing:
git checkout --no-guess jk/<TAB>
but that's rather cumbersome. The downside, of course, is
that you no longer get completion support when you _do_ want
to invoke the DWIM behavior. But depending on your workflow,
that may not be a big loss (for instance, in git.git I am
much more likely to want to detach, so I'd type "git
checkout origin/jk/<TAB>" anyway).
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-04-21 22:27:06 +02:00
|
|
|
#
|
2018-03-24 21:35:20 +01:00
|
|
|
# Compatible with bash 3.2.57.
|
|
|
|
#
|
completion: optionally disable checkout DWIM
When we complete branch names for "git checkout", we also
complete remote branch names that could trigger the DWIM
behavior. Depending on your workflow and project, this can
be either convenient or annoying.
For instance, my clone of gitster.git contains 74 local
"jk/*" branches, but origin contains another 147. When I
want to checkout a local branch but can't quite remember the
name, tab completion shows me 251 entries. And worse, for a
topic that has been picked up for pu, the upstream branch
name is likely to be similar to mine, leading to a high
probability that I pick the wrong one and accidentally
create a new branch.
This patch adds a way for the user to tell the completion
code not to include DWIM suggestions for checkout. This can
already be done by typing:
git checkout --no-guess jk/<TAB>
but that's rather cumbersome. The downside, of course, is
that you no longer get completion support when you _do_ want
to invoke the DWIM behavior. But depending on your workflow,
that may not be a big loss (for instance, in git.git I am
much more likely to want to detach, so I'd type "git
checkout origin/jk/<TAB>" anyway).
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-04-21 22:27:06 +02:00
|
|
|
# You can set the following environment variables to influence the behavior of
|
|
|
|
# the completion routines:
|
|
|
|
#
|
|
|
|
# GIT_COMPLETION_CHECKOUT_NO_GUESS
|
|
|
|
#
|
|
|
|
# When set to "1", do not include "DWIM" suggestions in git-checkout
|
2019-03-29 11:39:18 +01:00
|
|
|
# and git-switch completion (e.g., completing "foo" when "origin/foo"
|
|
|
|
# exists).
|
2006-09-28 11:31:25 +02:00
|
|
|
|
2008-07-15 07:52:04 +02:00
|
|
|
case "$COMP_WORDBREAKS" in
|
|
|
|
*:*) : great ;;
|
|
|
|
*) COMP_WORDBREAKS="$COMP_WORDBREAKS:"
|
|
|
|
esac
|
|
|
|
|
2017-02-03 03:48:28 +01:00
|
|
|
# Discovers the path to the git repository taking any '--git-dir=<path>' and
|
|
|
|
# '-C <path>' options into account and stores it in the $__git_repo_path
|
|
|
|
# variable.
|
|
|
|
__git_find_repo_path ()
|
|
|
|
{
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
if [ -n "$__git_repo_path" ]; then
|
|
|
|
# we already know where it is
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
2017-02-03 03:48:28 +01:00
|
|
|
if [ -n "${__git_C_args-}" ]; then
|
|
|
|
__git_repo_path="$(git "${__git_C_args[@]}" \
|
|
|
|
${__git_dir:+--git-dir="$__git_dir"} \
|
|
|
|
rev-parse --absolute-git-dir 2>/dev/null)"
|
|
|
|
elif [ -n "${__git_dir-}" ]; then
|
|
|
|
test -d "$__git_dir" &&
|
|
|
|
__git_repo_path="$__git_dir"
|
|
|
|
elif [ -n "${GIT_DIR-}" ]; then
|
|
|
|
test -d "${GIT_DIR-}" &&
|
|
|
|
__git_repo_path="$GIT_DIR"
|
|
|
|
elif [ -d .git ]; then
|
|
|
|
__git_repo_path=.git
|
|
|
|
else
|
|
|
|
__git_repo_path="$(git rev-parse --git-dir 2>/dev/null)"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
# Deprecated: use __git_find_repo_path() and $__git_repo_path instead
|
2009-01-15 17:02:23 +01:00
|
|
|
# __gitdir accepts 0 or 1 arguments (i.e., location)
|
|
|
|
# returns location of .git repo
|
2006-11-05 12:21:57 +01:00
|
|
|
__gitdir ()
|
|
|
|
{
|
2009-01-15 17:02:21 +01:00
|
|
|
if [ -z "${1-}" ]; then
|
2017-02-03 03:48:28 +01:00
|
|
|
__git_find_repo_path || return 1
|
|
|
|
echo "$__git_repo_path"
|
2006-11-28 18:12:26 +01:00
|
|
|
elif [ -d "$1/.git" ]; then
|
|
|
|
echo "$1/.git"
|
|
|
|
else
|
|
|
|
echo "$1"
|
|
|
|
fi
|
2006-11-05 12:21:57 +01:00
|
|
|
}
|
|
|
|
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
# Runs git with all the options given as argument, respecting any
|
|
|
|
# '--git-dir=<path>' and '-C <path>' options present on the command line
|
|
|
|
__git ()
|
|
|
|
{
|
|
|
|
git ${__git_C_args:+"${__git_C_args[@]}"} \
|
2017-02-03 03:48:26 +01:00
|
|
|
${__git_dir:+--git-dir="$__git_dir"} "$@" 2>/dev/null
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
}
|
|
|
|
|
completion: improve handling quoted paths on the command line
Our git-aware path completion doesn't work when it has to complete a
word already containing quoted and/or backslash-escaped characters on
the command line. The root cause of the issue is that completion
functions see all words on the command line verbatim, i.e. including
all backslash, single and double quote characters that the shell would
eventually remove when executing the finished command. These
quoting/escaping characters cause different issues depending on which
path component of the word to be completed contains them:
- The quoting/escaping is in the prefix path component(s).
Let's suppose we have a directory called 'New Dir', containing two
untracked files 'file.c' and 'file.o', and we have a gitignore
rule ignoring object files. In this case all of these:
git add New\ Dir/<TAB>
git add "New Dir/<TAB>
git add 'New Dir/<TAB>
should uniquely complete 'file.c' right away, but Bash offers both
'file.c' and 'file.o' instead. The reason for this behavior is
that our completion script uses the prefix directory name like
'git -C "New\ Dir/" ls-files ...", i.e. with the backslash inside
double quotes. Git then tries to enter a directory called
'New\ Dir', which (most likely) fails because such a directory
doesn't exists. As a result our completion script doesn't list
any files, leaves the COMPREPLY array empty, which in turn causes
Bash to fall back to its simple filename completion and lists all
files in that directory, i.e. both 'file.c' and 'file.o'.
- The quoting/escaping is in the path component to be completed.
Let's suppose we have two untracked files 'New File.c' and
'New File.o', and we have a gitignore rule ignoring object files.
In this case all of these:
git add New\ Fi<TAB>
git add "New Fi<TAB>
git add 'New Fi<TAB>
should uniquely complete 'New File.c' right away, but Bash offers
both 'New File.c' and 'New File.o' instead. The reason for this
behavior is that our completion script uses this 'New\ Fi' or
'"New Fi' etc. word to filter matching paths, and of course none
of the potential filenames will match because of the included
backslash or double quote. The end result is the same as above:
the completion script doesn't list any files, Bash falls back to
its filename completion, which then lists the matching object file
as well.
Add the new helper function __git_dequote() [1], which removes (most
of[2]) the quoting and escaping from the word it gets as argument. To
minimize the overhead of calling this function, store its result in
the variable $dequoted_word, supposed to be declared local in the
caller; simply printing the result would require a command
substitution imposing the overhead of fork()ing a subshell. Use this
function in __git_complete_index_file() to dequote the current word,
i.e. the path, to be completed, to avoid the above described
quoting-related issues, thereby fixing two of the failing quoted path
completion tests.
[1] The bash-completion project already has a dequote() function,
which I hoped I could borrow to deal with this, but unfortunately
it doesn't work quite well for this purpose (perhaps that's why
even the bash-completion project only rarely uses it). The main
issue is that their dequote() is implemented as:
eval printf %s "$1" 2> /dev/null
where $1 would contain the word to be completed. While it's a
short and sweet one-liner, the use of 'eval' requires that $1 is a
syntactically valid string, which is not the case when quoting the
path like 'git add "New Dir/<TAB>'. This causes 'eval' to fail,
because it can't find the matching closing double quote, and the
function returns nothing. The result is totally broken behavior,
as if the current word were empty, and the completion script would
then list all files from the current directory. This is why one
of the quoted path completion tests specifically checks the
completion of a path with an opening but without a corresponding
closing double quote character. Furthermore, the 'eval' performs
all kinds of expansions, which may or may not be desired; I think
it's the latter. Finally, using this function would require a
command substitution.
[2] Bash understands the $'string' quoting as well, which "expands to
'string', with backslash-escaped characters replaced as specified
by the ANSI C standard" (quoted from Bash manpage). Since shell
metacharacters, field separators, globbing, etc. can all be easily
entered using standard shell escaping or quoting, this type of
quoting comes in handly when dealing with control characters that
are otherwise difficult both to "type" and to see on the command
line. Because of this difficulty I would assume that people do
avoid pathnames with such control characters anyway, so I didn't
bother implementing it. This function is already way too long as
it is.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:09 +02:00
|
|
|
# Removes backslash escaping, single quotes and double quotes from a word,
|
|
|
|
# stores the result in the variable $dequoted_word.
|
|
|
|
# 1: The word to dequote.
|
|
|
|
__git_dequote ()
|
|
|
|
{
|
|
|
|
local rest="$1" len ch
|
|
|
|
|
|
|
|
dequoted_word=""
|
|
|
|
|
|
|
|
while test -n "$rest"; do
|
|
|
|
len=${#dequoted_word}
|
|
|
|
dequoted_word="$dequoted_word${rest%%[\\\'\"]*}"
|
|
|
|
rest="${rest:$((${#dequoted_word}-$len))}"
|
|
|
|
|
|
|
|
case "${rest:0:1}" in
|
|
|
|
\\)
|
|
|
|
ch="${rest:1:1}"
|
|
|
|
case "$ch" in
|
|
|
|
$'\n')
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
dequoted_word="$dequoted_word$ch"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
rest="${rest:2}"
|
|
|
|
;;
|
|
|
|
\')
|
|
|
|
rest="${rest:1}"
|
|
|
|
len=${#dequoted_word}
|
|
|
|
dequoted_word="$dequoted_word${rest%%\'*}"
|
|
|
|
rest="${rest:$((${#dequoted_word}-$len+1))}"
|
|
|
|
;;
|
|
|
|
\")
|
|
|
|
rest="${rest:1}"
|
|
|
|
while test -n "$rest" ; do
|
|
|
|
len=${#dequoted_word}
|
|
|
|
dequoted_word="$dequoted_word${rest%%[\\\"]*}"
|
|
|
|
rest="${rest:$((${#dequoted_word}-$len))}"
|
|
|
|
case "${rest:0:1}" in
|
|
|
|
\\)
|
|
|
|
ch="${rest:1:1}"
|
|
|
|
case "$ch" in
|
|
|
|
\"|\\|\$|\`)
|
|
|
|
dequoted_word="$dequoted_word$ch"
|
|
|
|
;;
|
|
|
|
$'\n')
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
dequoted_word="$dequoted_word\\$ch"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
rest="${rest:2}"
|
|
|
|
;;
|
|
|
|
\")
|
|
|
|
rest="${rest:1}"
|
|
|
|
break
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2010-12-15 05:57:58 +01:00
|
|
|
# The following function is based on code from:
|
|
|
|
#
|
|
|
|
# bash_completion - programmable completion functions for bash 3.2+
|
|
|
|
#
|
|
|
|
# Copyright © 2006-2008, Ian Macdonald <ian@caliban.org>
|
|
|
|
# © 2009-2010, Bash Completion Maintainers
|
|
|
|
# <bash-completion-devel@lists.alioth.debian.org>
|
|
|
|
#
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
|
# the Free Software Foundation; either version 2, or (at your option)
|
|
|
|
# any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License
|
2017-11-07 06:39:33 +01:00
|
|
|
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
2010-12-15 05:57:58 +01:00
|
|
|
#
|
|
|
|
# The latest version of this software can be obtained here:
|
|
|
|
#
|
|
|
|
# http://bash-completion.alioth.debian.org/
|
|
|
|
#
|
|
|
|
# RELEASE: 2.x
|
|
|
|
|
|
|
|
# This function can be used to access a tokenized list of words
|
|
|
|
# on the command line:
|
|
|
|
#
|
|
|
|
# __git_reassemble_comp_words_by_ref '=:'
|
|
|
|
# if test "${words_[cword_-1]}" = -w
|
|
|
|
# then
|
|
|
|
# ...
|
|
|
|
# fi
|
|
|
|
#
|
|
|
|
# The argument should be a collection of characters from the list of
|
|
|
|
# word completion separators (COMP_WORDBREAKS) to treat as ordinary
|
|
|
|
# characters.
|
|
|
|
#
|
|
|
|
# This is roughly equivalent to going back in time and setting
|
|
|
|
# COMP_WORDBREAKS to exclude those characters. The intent is to
|
|
|
|
# make option types like --date=<type> and <rev>:<path> easy to
|
|
|
|
# recognize by treating each shell word as a single token.
|
|
|
|
#
|
|
|
|
# It is best not to set COMP_WORDBREAKS directly because the value is
|
|
|
|
# shared with other completion scripts. By the time the completion
|
|
|
|
# function gets called, COMP_WORDS has already been populated so local
|
|
|
|
# changes to COMP_WORDBREAKS have no effect.
|
|
|
|
#
|
|
|
|
# Output: words_, cword_, cur_.
|
|
|
|
|
|
|
|
__git_reassemble_comp_words_by_ref()
|
|
|
|
{
|
|
|
|
local exclude i j first
|
|
|
|
# Which word separators to exclude?
|
|
|
|
exclude="${1//[^$COMP_WORDBREAKS]}"
|
|
|
|
cword_=$COMP_CWORD
|
|
|
|
if [ -z "$exclude" ]; then
|
|
|
|
words_=("${COMP_WORDS[@]}")
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
# List of word completion separators has shrunk;
|
|
|
|
# re-assemble words to complete.
|
|
|
|
for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do
|
|
|
|
# Append each nonempty word consisting of just
|
|
|
|
# word separator characters to the current word.
|
|
|
|
first=t
|
|
|
|
while
|
|
|
|
[ $i -gt 0 ] &&
|
|
|
|
[ -n "${COMP_WORDS[$i]}" ] &&
|
|
|
|
# word consists of excluded word separators
|
|
|
|
[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ]
|
|
|
|
do
|
|
|
|
# Attach to the previous token,
|
|
|
|
# unless the previous token is the command name.
|
|
|
|
if [ $j -ge 2 ] && [ -n "$first" ]; then
|
|
|
|
((j--))
|
|
|
|
fi
|
|
|
|
first=
|
|
|
|
words_[$j]=${words_[j]}${COMP_WORDS[i]}
|
|
|
|
if [ $i = $COMP_CWORD ]; then
|
|
|
|
cword_=$j
|
|
|
|
fi
|
|
|
|
if (($i < ${#COMP_WORDS[@]} - 1)); then
|
|
|
|
((i++))
|
|
|
|
else
|
|
|
|
# Done.
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
words_[$j]=${words_[j]}${COMP_WORDS[i]}
|
|
|
|
if [ $i = $COMP_CWORD ]; then
|
|
|
|
cword_=$j
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
if ! type _get_comp_words_by_ref >/dev/null 2>&1; then
|
|
|
|
_get_comp_words_by_ref ()
|
|
|
|
{
|
2010-12-15 05:57:58 +01:00
|
|
|
local exclude cur_ words_ cword_
|
|
|
|
if [ "$1" = "-n" ]; then
|
|
|
|
exclude=$2
|
|
|
|
shift 2
|
|
|
|
fi
|
|
|
|
__git_reassemble_comp_words_by_ref "$exclude"
|
|
|
|
cur_=${words_[cword_]}
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
case "$1" in
|
|
|
|
cur)
|
2010-12-15 05:57:58 +01:00
|
|
|
cur=$cur_
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
;;
|
|
|
|
prev)
|
2010-12-15 05:57:58 +01:00
|
|
|
prev=${words_[$cword_-1]}
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
;;
|
|
|
|
words)
|
2010-12-15 05:57:58 +01:00
|
|
|
words=("${words_[@]}")
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
;;
|
|
|
|
cword)
|
2010-12-15 05:57:58 +01:00
|
|
|
cword=$cword_
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
}
|
|
|
|
fi
|
|
|
|
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
# Fills the COMPREPLY array with prefiltered words without any additional
|
|
|
|
# processing.
|
|
|
|
# Callers must take care of providing only words that match the current word
|
|
|
|
# to be completed and adding any prefix and/or suffix (trailing space!), if
|
|
|
|
# necessary.
|
|
|
|
# 1: List of newline-separated matching completion words, complete with
|
|
|
|
# prefix and suffix.
|
|
|
|
__gitcomp_direct ()
|
|
|
|
{
|
|
|
|
local IFS=$'\n'
|
|
|
|
|
|
|
|
COMPREPLY=($1)
|
|
|
|
}
|
|
|
|
|
2014-01-05 11:18:03 +01:00
|
|
|
__gitcompappend ()
|
2013-04-10 08:57:53 +02:00
|
|
|
{
|
2015-04-08 07:45:58 +02:00
|
|
|
local x i=${#COMPREPLY[@]}
|
2013-04-10 08:57:55 +02:00
|
|
|
for x in $1; do
|
|
|
|
if [[ "$x" == "$3"* ]]; then
|
|
|
|
COMPREPLY[i++]="$2$x$4"
|
|
|
|
fi
|
|
|
|
done
|
2013-04-10 08:57:53 +02:00
|
|
|
}
|
|
|
|
|
2014-01-05 11:18:03 +01:00
|
|
|
__gitcompadd ()
|
|
|
|
{
|
|
|
|
COMPREPLY=()
|
|
|
|
__gitcompappend "$@"
|
|
|
|
}
|
|
|
|
|
2013-04-10 08:57:55 +02:00
|
|
|
# Generates completion reply, appending a space to possible completion words,
|
|
|
|
# if necessary.
|
2011-10-08 16:54:35 +02:00
|
|
|
# It accepts 1 to 4 arguments:
|
|
|
|
# 1: List of possible completion words.
|
|
|
|
# 2: A prefix to be added to each possible completion word (optional).
|
|
|
|
# 3: Generate possible completion matches for this word (optional).
|
|
|
|
# 4: A suffix to be appended to each possible completion word (optional).
|
2007-02-04 08:38:27 +01:00
|
|
|
__gitcomp ()
|
|
|
|
{
|
2012-02-02 20:48:08 +01:00
|
|
|
local cur_="${3-$cur}"
|
2011-04-28 18:01:51 +02:00
|
|
|
|
|
|
|
case "$cur_" in
|
2008-03-05 20:07:49 +01:00
|
|
|
--*=)
|
|
|
|
;;
|
2018-06-06 11:41:39 +02:00
|
|
|
--no-*)
|
|
|
|
local c i=0 IFS=$' \t\n'
|
|
|
|
for c in $1; do
|
|
|
|
if [[ $c == "--" ]]; then
|
|
|
|
continue
|
|
|
|
fi
|
|
|
|
c="$c${4-}"
|
|
|
|
if [[ $c == "$cur_"* ]]; then
|
|
|
|
case $c in
|
|
|
|
--*=*|*.) ;;
|
|
|
|
*) c="$c " ;;
|
|
|
|
esac
|
|
|
|
COMPREPLY[i++]="${2-}$c"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
;;
|
2008-03-05 20:07:49 +01:00
|
|
|
*)
|
2013-04-10 08:57:56 +02:00
|
|
|
local c i=0 IFS=$' \t\n'
|
|
|
|
for c in $1; do
|
2018-06-06 11:41:39 +02:00
|
|
|
if [[ $c == "--" ]]; then
|
|
|
|
c="--no-...${4-}"
|
|
|
|
if [[ $c == "$cur_"* ]]; then
|
|
|
|
COMPREPLY[i++]="${2-}$c "
|
|
|
|
fi
|
|
|
|
break
|
|
|
|
fi
|
2013-04-10 08:57:56 +02:00
|
|
|
c="$c${4-}"
|
|
|
|
if [[ $c == "$cur_"* ]]; then
|
2013-04-10 08:57:57 +02:00
|
|
|
case $c in
|
|
|
|
--*=*|*.) ;;
|
|
|
|
*) c="$c " ;;
|
|
|
|
esac
|
2013-04-10 08:57:56 +02:00
|
|
|
COMPREPLY[i++]="${2-}$c"
|
|
|
|
fi
|
|
|
|
done
|
2008-03-05 20:07:49 +01:00
|
|
|
;;
|
|
|
|
esac
|
2007-02-04 08:38:27 +01:00
|
|
|
}
|
|
|
|
|
completion: clear cached --options when sourcing the completion script
The established way to update the completion script in an already
running shell is to simply source it again: this brings in any new
--options and features, and clears caching variables. E.g. it clears
the variables caching the list of (all|porcelain) git commands, so
when they are later lazy-initialized again, then they will list and
cache any newly installed commmands as well.
Unfortunately, since d401f3debc (git-completion.bash: introduce
__gitcomp_builtin, 2018-02-09) and subsequent patches this doesn't
work for a lot of git commands' options. To eliminate a lot of
hard-to-maintain hard-coded lists of options, those commits changed
the completion script to use a bunch of programmatically created and
lazy-initialized variables to cache the options of those builtin
porcelain commands that use parse-options. These variables are not
cleared upon sourcing the completion script, therefore they continue
caching the old lists of options, even when some commands recently
learned new options or when deprecated options were removed.
Always 'unset' these variables caching the options of builtin commands
when sourcing the completion script.
Redirect 'unset's stderr to /dev/null, because ZSH's 'unset' complains
if it's invoked without any arguments, i.e. no variables caching
builtin's options are set. This can happen, if someone were to source
the completion script twice without completing any --options in
between. Bash stays silent in this case.
Add tests to ensure that these variables are indeed cleared when the
completion script is sourced; not just the variables caching options,
but all other caching variables, i.e. the variables caching commands,
porcelain commands and merge strategies as well.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-22 15:16:04 +01:00
|
|
|
# Clear the variables caching builtins' options when (re-)sourcing
|
|
|
|
# the completion script.
|
completion: reduce overhead of clearing cached --options
To get the names of all '$__git_builtin_*' variables caching --options
of builtin commands in order to unset them, 8b0eaa41f2 (completion:
clear cached --options when sourcing the completion script,
2018-03-22) runs a 'set |sed s///' pipeline. This works both in Bash
and in ZSH, but has a higher than necessary overhead with the extra
processes.
In Bash we can do better: run the 'compgen -v __gitcomp_builtin_'
builtin command, which lists the same variables, but without a
pipeline and 'sed' it can do so with lower overhead.
ZSH will still continue to run that pipeline.
This change also happens to work around an issue in the default Bash
version shipped in macOS (3.2.57), reported by users of the Powerline
shell prompt, which was triggered by the same commit 8b0eaa41f2 as
well. Powerline uses several Unicode Private Use Area code points to
represent some of its pretty text UI elements (arrows and what not),
and these are stored in the $PS1 variable. Apparently the 'set'
builtin of said Bash version on macOS has issues with these code
points, and produces garbled output where Powerline's special symbols
should be in the $PS1 variable. This, in turn, triggers the following
error message in the downstream 'sed' process:
sed: RE error: illegal byte sequence
Other Bash versions, notably 4.4.19 on macOS via homebrew (i.e. a
newer version on the same platform) and 3.2.25 on CentOS (i.e. a
slightly earlier version, though on a different platform) are not
affected. ZSH in macOS (the versions shipped by default or installed
via homebrew) or on other platforms isn't affected either.
With this patch neither the 'set' builtin is invoked to print garbage,
nor 'sed' to choke on it.
Issue-on-macOS-reported-by: Stephon Harris <theonestep4@gmail.com>
Issue-on-macOS-explained-by: Matthew Coleman <matt@1eanda.com>
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-18 00:02:19 +02:00
|
|
|
if [[ -n ${ZSH_VERSION-} ]]; then
|
|
|
|
unset $(set |sed -ne 's/^\(__gitcomp_builtin_[a-zA-Z0-9_][a-zA-Z0-9_]*\)=.*/\1/p') 2>/dev/null
|
|
|
|
else
|
|
|
|
unset $(compgen -v __gitcomp_builtin_)
|
|
|
|
fi
|
completion: clear cached --options when sourcing the completion script
The established way to update the completion script in an already
running shell is to simply source it again: this brings in any new
--options and features, and clears caching variables. E.g. it clears
the variables caching the list of (all|porcelain) git commands, so
when they are later lazy-initialized again, then they will list and
cache any newly installed commmands as well.
Unfortunately, since d401f3debc (git-completion.bash: introduce
__gitcomp_builtin, 2018-02-09) and subsequent patches this doesn't
work for a lot of git commands' options. To eliminate a lot of
hard-to-maintain hard-coded lists of options, those commits changed
the completion script to use a bunch of programmatically created and
lazy-initialized variables to cache the options of those builtin
porcelain commands that use parse-options. These variables are not
cleared upon sourcing the completion script, therefore they continue
caching the old lists of options, even when some commands recently
learned new options or when deprecated options were removed.
Always 'unset' these variables caching the options of builtin commands
when sourcing the completion script.
Redirect 'unset's stderr to /dev/null, because ZSH's 'unset' complains
if it's invoked without any arguments, i.e. no variables caching
builtin's options are set. This can happen, if someone were to source
the completion script twice without completing any --options in
between. Bash stays silent in this case.
Add tests to ensure that these variables are indeed cleared when the
completion script is sourced; not just the variables caching options,
but all other caching variables, i.e. the variables caching commands,
porcelain commands and merge strategies as well.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-03-22 15:16:04 +01:00
|
|
|
|
2018-02-09 12:01:43 +01:00
|
|
|
# This function is equivalent to
|
|
|
|
#
|
|
|
|
# __gitcomp "$(git xxx --git-completion-helper) ..."
|
|
|
|
#
|
|
|
|
# except that the output is cached. Accept 1-3 arguments:
|
|
|
|
# 1: the git command to execute, this is also the cache key
|
|
|
|
# 2: extra options to be added on top (e.g. negative forms)
|
|
|
|
# 3: options to be excluded
|
|
|
|
__gitcomp_builtin ()
|
|
|
|
{
|
|
|
|
# spaces must be replaced with underscore for multi-word
|
|
|
|
# commands, e.g. "git remote add" becomes remote_add.
|
|
|
|
local cmd="$1"
|
|
|
|
local incl="$2"
|
|
|
|
local excl="$3"
|
|
|
|
|
|
|
|
local var=__gitcomp_builtin_"${cmd/-/_}"
|
|
|
|
local options
|
|
|
|
eval "options=\$$var"
|
|
|
|
|
|
|
|
if [ -z "$options" ]; then
|
|
|
|
# leading and trailing spaces are significant to make
|
|
|
|
# option removal work correctly.
|
2019-06-12 10:56:06 +02:00
|
|
|
options=" $incl $(__git ${cmd/_/ } --git-completion-helper) " || return
|
|
|
|
|
2018-02-09 12:01:43 +01:00
|
|
|
for i in $excl; do
|
|
|
|
options="${options/ $i / }"
|
|
|
|
done
|
|
|
|
eval "$var=\"$options\""
|
|
|
|
fi
|
|
|
|
|
|
|
|
__gitcomp "$options"
|
|
|
|
}
|
|
|
|
|
2014-01-05 11:18:03 +01:00
|
|
|
# Variation of __gitcomp_nl () that appends to the existing list of
|
|
|
|
# completion candidates, COMPREPLY.
|
|
|
|
__gitcomp_nl_append ()
|
|
|
|
{
|
|
|
|
local IFS=$'\n'
|
|
|
|
__gitcompappend "$1" "${2-}" "${3-$cur}" "${4- }"
|
|
|
|
}
|
|
|
|
|
2013-04-10 08:57:55 +02:00
|
|
|
# Generates completion reply from newline-separated possible completion words
|
|
|
|
# by appending a space to all of them.
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
# It accepts 1 to 4 arguments:
|
|
|
|
# 1: List of possible completion words, separated by a single newline.
|
|
|
|
# 2: A prefix to be added to each possible completion word (optional).
|
|
|
|
# 3: Generate possible completion matches for this word (optional).
|
|
|
|
# 4: A suffix to be appended to each possible completion word instead of
|
|
|
|
# the default space (optional). If specified but empty, nothing is
|
|
|
|
# appended.
|
|
|
|
__gitcomp_nl ()
|
|
|
|
{
|
2014-01-05 11:18:03 +01:00
|
|
|
COMPREPLY=()
|
|
|
|
__gitcomp_nl_append "$@"
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
}
|
|
|
|
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
# Fills the COMPREPLY array with prefiltered paths without any additional
|
|
|
|
# processing.
|
|
|
|
# Callers must take care of providing only paths that match the current path
|
|
|
|
# to be completed and adding any prefix path components, if necessary.
|
|
|
|
# 1: List of newline-separated matching paths, complete with all prefix
|
2018-12-26 17:22:16 +01:00
|
|
|
# path components.
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
__gitcomp_file_direct ()
|
|
|
|
{
|
|
|
|
local IFS=$'\n'
|
|
|
|
|
|
|
|
COMPREPLY=($1)
|
|
|
|
|
|
|
|
# use a hack to enable file mode in bash < 4
|
|
|
|
compopt -o filenames +o nospace 2>/dev/null ||
|
completion: don't return with error from __gitcomp_file_direct()
In __gitcomp_file_direct() we tell Bash that it should handle our
possible completion words as filenames with the following piece of
cleverness:
# use a hack to enable file mode in bash < 4
compopt -o filenames +o nospace 2>/dev/null ||
compgen -f /non-existing-dir/ > /dev/null
Unfortunately, this makes this function always return with error
when it is not invoked in real completion, but e.g. in tests of
't9902-completion.sh':
- First the 'compopt' line errors out
- either because in Bash v3.x there is no such command,
- or because in Bash v4.x it complains about "not currently
executing completion function",
- then 'compgen' just silently returns with error because of the
non-existing directory.
Since __gitcomp_file_direct() is now the last command executed in
__git_complete_index_file(), that function returns with error as well,
which prevents it from being invoked in tests directly as is, and
would require extra steps in test to hide its error code.
So let's make sure that __gitcomp_file_direct() doesn't return with
error, because in the tests coming in the following patch we do want
to exercise __git_complete_index_file() directly,
__gitcomp_file() contains the same construct, and thus it, too, always
returns with error. Update that function accordingly as well.
While at it, also remove the space from between the redirection
operator and the filename in both functions.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-18 16:17:50 +02:00
|
|
|
compgen -f /non-existing-dir/ >/dev/null ||
|
|
|
|
true
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
}
|
|
|
|
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
# Generates completion reply with compgen from newline-separated possible
|
|
|
|
# completion filenames.
|
|
|
|
# It accepts 1 to 3 arguments:
|
|
|
|
# 1: List of possible completion filenames, separated by a single newline.
|
|
|
|
# 2: A directory prefix to be added to each possible completion filename
|
|
|
|
# (optional).
|
|
|
|
# 3: Generate possible completion matches for this word (optional).
|
|
|
|
__gitcomp_file ()
|
|
|
|
{
|
|
|
|
local IFS=$'\n'
|
|
|
|
|
|
|
|
# XXX does not work when the directory prefix contains a tilde,
|
|
|
|
# since tilde expansion is not applied.
|
|
|
|
# This means that COMPREPLY will be empty and Bash default
|
|
|
|
# completion will be used.
|
2013-04-27 22:10:02 +02:00
|
|
|
__gitcompadd "$1" "${2-}" "${3-$cur}" ""
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
2013-04-27 22:10:05 +02:00
|
|
|
# use a hack to enable file mode in bash < 4
|
2013-04-27 22:10:06 +02:00
|
|
|
compopt -o filenames +o nospace 2>/dev/null ||
|
completion: don't return with error from __gitcomp_file_direct()
In __gitcomp_file_direct() we tell Bash that it should handle our
possible completion words as filenames with the following piece of
cleverness:
# use a hack to enable file mode in bash < 4
compopt -o filenames +o nospace 2>/dev/null ||
compgen -f /non-existing-dir/ > /dev/null
Unfortunately, this makes this function always return with error
when it is not invoked in real completion, but e.g. in tests of
't9902-completion.sh':
- First the 'compopt' line errors out
- either because in Bash v3.x there is no such command,
- or because in Bash v4.x it complains about "not currently
executing completion function",
- then 'compgen' just silently returns with error because of the
non-existing directory.
Since __gitcomp_file_direct() is now the last command executed in
__git_complete_index_file(), that function returns with error as well,
which prevents it from being invoked in tests directly as is, and
would require extra steps in test to hide its error code.
So let's make sure that __gitcomp_file_direct() doesn't return with
error, because in the tests coming in the following patch we do want
to exercise __git_complete_index_file() directly,
__gitcomp_file() contains the same construct, and thus it, too, always
returns with error. Update that function accordingly as well.
While at it, also remove the space from between the redirection
operator and the filename in both functions.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-05-18 16:17:50 +02:00
|
|
|
compgen -f /non-existing-dir/ >/dev/null ||
|
|
|
|
true
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
}
|
|
|
|
|
2013-04-27 22:10:03 +02:00
|
|
|
# Execute 'git ls-files', unless the --committable option is specified, in
|
|
|
|
# which case it runs 'git diff-index' to find out the files that can be
|
|
|
|
# committed. It return paths relative to the directory specified in the first
|
|
|
|
# argument, and using the options specified in the second argument.
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
__git_ls_files_helper ()
|
|
|
|
{
|
2014-10-09 22:45:21 +02:00
|
|
|
if [ "$2" == "--committable" ]; then
|
2018-04-17 00:41:08 +02:00
|
|
|
__git -C "$1" -c core.quotePath=false diff-index \
|
completion: let 'ls-files' and 'diff-index' filter matching paths
During git-aware path completion, e.g. 'git rm dir/fil<TAB>', both
'git ls-files' and 'git diff-index' list all paths in the given 'dir/'
matching certain criteria (cached, modified, untracked, etc.)
appropriate for the given git command, even paths whose names don't
begin with 'fil'. This comes with a considerable performance
penalty when the directory in question contains a lot of paths, but
the current word can be uniquely completed or when only a handful of
those paths match the current word.
Reduce the number of iterations in this codepath from the number of
paths to the number of matching paths by specifying an appropriate
globbing pattern to 'git ls-files' and 'git diff-index' to list only
paths that match the current word to be completed.
Note that both commands treat backslashes as escape characters in
their file arguments, e.g. to preserve the literal meaning of globbing
characters, so we have to double every backslash in the globbing
pattern. This is why one of the path completion tests specifically
checks the completion of a path containing a literal backslash
character (that test still fails, though, because both commands output
such paths enclosed in double quotes and the special characters
escaped; a later patch in this series will deal with those).
This speeds up path completion considerably when there are a lot of
non-matching paths to be filtered out. Uniquely completing a tracked
filename at the top of the worktree in linux.git (over 62k files),
i.e. what's doing all the hard work behind 'git rm Mak<TAB>' to
complete 'Makefile':
Before this patch, best of five, on Linux:
$ time cur=Mak __git_complete_index_file
real 0m2.159s
user 0m1.299s
sys 0m1.089s
After:
real 0m0.033s
user 0m0.023s
sys 0m0.015s
Difference: -98.5%
Speedup: 65.4x
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:10 +02:00
|
|
|
--name-only --relative HEAD -- "${3//\\/\\\\}*"
|
2014-10-09 22:45:21 +02:00
|
|
|
else
|
|
|
|
# NOTE: $2 is not quoted in order to support multiple options
|
2018-04-17 00:41:08 +02:00
|
|
|
__git -C "$1" -c core.quotePath=false ls-files \
|
completion: let 'ls-files' and 'diff-index' filter matching paths
During git-aware path completion, e.g. 'git rm dir/fil<TAB>', both
'git ls-files' and 'git diff-index' list all paths in the given 'dir/'
matching certain criteria (cached, modified, untracked, etc.)
appropriate for the given git command, even paths whose names don't
begin with 'fil'. This comes with a considerable performance
penalty when the directory in question contains a lot of paths, but
the current word can be uniquely completed or when only a handful of
those paths match the current word.
Reduce the number of iterations in this codepath from the number of
paths to the number of matching paths by specifying an appropriate
globbing pattern to 'git ls-files' and 'git diff-index' to list only
paths that match the current word to be completed.
Note that both commands treat backslashes as escape characters in
their file arguments, e.g. to preserve the literal meaning of globbing
characters, so we have to double every backslash in the globbing
pattern. This is why one of the path completion tests specifically
checks the completion of a path containing a literal backslash
character (that test still fails, though, because both commands output
such paths enclosed in double quotes and the special characters
escaped; a later patch in this series will deal with those).
This speeds up path completion considerably when there are a lot of
non-matching paths to be filtered out. Uniquely completing a tracked
filename at the top of the worktree in linux.git (over 62k files),
i.e. what's doing all the hard work behind 'git rm Mak<TAB>' to
complete 'Makefile':
Before this patch, best of five, on Linux:
$ time cur=Mak __git_complete_index_file
real 0m2.159s
user 0m1.299s
sys 0m1.089s
After:
real 0m0.033s
user 0m0.023s
sys 0m0.015s
Difference: -98.5%
Speedup: 65.4x
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:10 +02:00
|
|
|
--exclude-standard $2 -- "${3//\\/\\\\}*"
|
2017-02-03 03:48:26 +01:00
|
|
|
fi
|
2013-03-11 13:21:27 +01:00
|
|
|
}
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
|
|
|
|
|
|
|
# __git_index_files accepts 1 or 2 arguments:
|
|
|
|
# 1: Options to pass to ls-files (required).
|
|
|
|
# 2: A directory path (optional).
|
|
|
|
# If provided, only files within the specified directory are listed.
|
|
|
|
# Sub directories are never recursed. Path must have a trailing
|
|
|
|
# slash.
|
completion: let 'ls-files' and 'diff-index' filter matching paths
During git-aware path completion, e.g. 'git rm dir/fil<TAB>', both
'git ls-files' and 'git diff-index' list all paths in the given 'dir/'
matching certain criteria (cached, modified, untracked, etc.)
appropriate for the given git command, even paths whose names don't
begin with 'fil'. This comes with a considerable performance
penalty when the directory in question contains a lot of paths, but
the current word can be uniquely completed or when only a handful of
those paths match the current word.
Reduce the number of iterations in this codepath from the number of
paths to the number of matching paths by specifying an appropriate
globbing pattern to 'git ls-files' and 'git diff-index' to list only
paths that match the current word to be completed.
Note that both commands treat backslashes as escape characters in
their file arguments, e.g. to preserve the literal meaning of globbing
characters, so we have to double every backslash in the globbing
pattern. This is why one of the path completion tests specifically
checks the completion of a path containing a literal backslash
character (that test still fails, though, because both commands output
such paths enclosed in double quotes and the special characters
escaped; a later patch in this series will deal with those).
This speeds up path completion considerably when there are a lot of
non-matching paths to be filtered out. Uniquely completing a tracked
filename at the top of the worktree in linux.git (over 62k files),
i.e. what's doing all the hard work behind 'git rm Mak<TAB>' to
complete 'Makefile':
Before this patch, best of five, on Linux:
$ time cur=Mak __git_complete_index_file
real 0m2.159s
user 0m1.299s
sys 0m1.089s
After:
real 0m0.033s
user 0m0.023s
sys 0m0.015s
Difference: -98.5%
Speedup: 65.4x
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:10 +02:00
|
|
|
# 3: List only paths matching this path component (optional).
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
__git_index_files ()
|
|
|
|
{
|
completion: use 'awk' to strip trailing path components
During git-aware path completion we complete one path component at a
time, i.e. 'git add <TAB>' offers only 'dir/' at first, not
'dir/subdir/file' right away, just like Bash's own filename
completion. However, since both 'git ls-files' and 'git diff-index'
dive deep into subdirectories, we have to strip all trailing path
components from the listed paths, keeping only the leading path
component. This stripping is currently done in a shell loop in
__git_index_files(), which can take a significant amount of time when
it has to iterate through a large number of paths.
Replace this shell loop with a little 'awk' script using '/' as input
field separator and printing the first field, which produces the same
output much faster.
Listing all tracked files (12) and directories (23) at the top of the
worktree in linux.git (over 62k files), i.e. what's doing all the hard
work behind 'git rm <TAB>':
Before this patch, best of five, using GNU awk on Linux:
$ time cur= __git_complete_index_file
real 0m2.149s
user 0m1.307s
sys 0m1.086s
After:
real 0m0.067s
user 0m0.089s
sys 0m0.023s
Difference: -96.9%
Speedup: 32.1x
Note that this could be done with 'sed', or even with 'cut', just as
well, but the upcoming patches require 'awk's scriptability.
Note also that this change means one more fork()+exec()ed process
during path completion, adding more overhead especially on Windows,
but a later patch will more than make up for it by eliminating two
other processes in the same function.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:11 +02:00
|
|
|
local root="$2" match="$3"
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
completion: let 'ls-files' and 'diff-index' filter matching paths
During git-aware path completion, e.g. 'git rm dir/fil<TAB>', both
'git ls-files' and 'git diff-index' list all paths in the given 'dir/'
matching certain criteria (cached, modified, untracked, etc.)
appropriate for the given git command, even paths whose names don't
begin with 'fil'. This comes with a considerable performance
penalty when the directory in question contains a lot of paths, but
the current word can be uniquely completed or when only a handful of
those paths match the current word.
Reduce the number of iterations in this codepath from the number of
paths to the number of matching paths by specifying an appropriate
globbing pattern to 'git ls-files' and 'git diff-index' to list only
paths that match the current word to be completed.
Note that both commands treat backslashes as escape characters in
their file arguments, e.g. to preserve the literal meaning of globbing
characters, so we have to double every backslash in the globbing
pattern. This is why one of the path completion tests specifically
checks the completion of a path containing a literal backslash
character (that test still fails, though, because both commands output
such paths enclosed in double quotes and the special characters
escaped; a later patch in this series will deal with those).
This speeds up path completion considerably when there are a lot of
non-matching paths to be filtered out. Uniquely completing a tracked
filename at the top of the worktree in linux.git (over 62k files),
i.e. what's doing all the hard work behind 'git rm Mak<TAB>' to
complete 'Makefile':
Before this patch, best of five, on Linux:
$ time cur=Mak __git_complete_index_file
real 0m2.159s
user 0m1.299s
sys 0m1.089s
After:
real 0m0.033s
user 0m0.023s
sys 0m0.015s
Difference: -98.5%
Speedup: 65.4x
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:10 +02:00
|
|
|
__git_ls_files_helper "$root" "$1" "$match" |
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
awk -F / -v pfx="${2//\\/\\\\}" '{
|
completion: remove repeated dirnames with 'awk' during path completion
During git-aware path completion, after all the trailing path
components have been removed from the output of 'git ls-files' and
'git diff-index' (see previous patch), each directory name is repeated
as many times as the number of listed paths it contains. This can be
a lot of repetitions, especially when invoking path completion close
to the root of a big worktree, which would cause a considerable
overhead downstream of __git_index_files(), in particular in the shell
loop that fills the COMPREPLY array. To reduce this overhead,
__git_index_files() runs the classic '... |sort |uniq' pattern to
remove those repetitions from the function's output.
While removing repeated directory names is effective in reducing the
number of iterations in that shell loop, it still imposes the overhead
of fork()+exec()ing two external processes, and two additional stages
in the pipeline, where potentially relatively large amount of data can
be passed between two subsequent pipeline stages.
Extend __git_index_files()'s 'awk' script to remove repeated path
components by first creating and filling an associative array indexed
by all encountered path components (after the trailing path components
have been removed), and then iterating over this array and printing
the indices, i.e. unique path components. This way we can remove the
'|sort |uniq' pipeline stages, and their eliminated overhead results
in faster path completion.
Listing all tracked files (12) and directories (23) at the top of the
worktree in linux.git (over 62k files), i.e. what's doing all the hard
work behind 'git rm <TAB>':
Before this patch, best of five, using GNU awk on Linux:
real 0m0.069s
user 0m0.089s
sys 0m0.026s
After:
real 0m0.052s
user 0m0.072s
sys 0m0.014s
Difference: -24.6%
Note that this changes order of elements in __git_index_files()'s
output. This is not an issue, because this function was only ever
intended to feed paths into the COMPREPLY array, and Bash will sort
its elements (according to the users locale) anyway.
Note also that using 'awk' to remove repeated path components is also
beneficial for the performance of the next two patches:
- The first will extend this 'awk' script to dequote quoted paths in
the output of 'git ls-files' and 'git diff-index'. With this
patch it will only have to dequote unique path components, not
all.
- The second will, among other things, extend this 'awk' script to
prepend prefix path components from the command line to the
currently completed path component. Consequently, each line in
'awk's output will grow longer. Without this patch that '|sort
|uniq' would have to exchange and process that much more data.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:13 +02:00
|
|
|
paths[$1] = 1
|
|
|
|
}
|
|
|
|
END {
|
completion: improve handling quoted paths in 'git ls-files's output
If any pathname contains backslash, double quote, tab, newline, or any
control characters, 'git ls-files' and 'git diff-index' will enclose
that pathname in double quotes and escape those special characters
using C-style one-character escape sequences or \nnn octal values.
This prevents those files from being listed during git-aware path
completion, because due to the quoting they will never match the
current word to be completed.
Extend __git_index_files()'s 'awk' script to remove all that quoting
and escaping from unique path components, so even paths containing
(almost all) such special characters can be completed.
Paths containing newline characters are still an issue, though. We
use newlines as separator character when filling the COMPREPLY array,
so a path with one or more newline will end up split to two or more
elements in COMPREPLY, basically breaking completion. There is
nothing we can do about it without a significant performance hit, so
let's just ignore such paths for now. As far as paths with newlines
are concerned, this isn't any different from the previous behavior,
because those paths were always omitted, though in the past they were
omitted because due to the quoting they didn't match the current word
to be completed. Anyway, Bash's own filename completion (Meta-/) can
complete even those paths, if need be.
Note:
- We don't dequote path components right away as they are coming in,
because then we would have to dequote each directory name
repeatedly, as many times as it appears in the input, i.e. as many
times as the number of listed paths it contains. Instead, we
dequote them at the end, as we print unique path components.
- Even when a directory name itself does not contain any special
characters, it will still be quoted if any of its trailing path
components do. If a directory contains paths both with and
without special characters, then the name of that directory will
appear both quoted and unquoted in the output of 'git ls-files'
and 'git diff-index'. Consequently, we will add such a directory
name to the deduplicating associative array twice: once quoted and
once unquoted.
This means that we have to be careful after dequoting a directory
name, and only print it if we haven't seen the same directory name
unquoted.
- It would be wonderful if we could just pass '-z' to those git
commands to output \0-separated unquoted paths, and use \0 as
record separator in the 'awk' script processing their output...
this patch would be so much simpler, almost trivial even.
Unfortunately, however, POSIX and most 'awk' implementations don't
support \0 as record separator (GNU awk does support it).
- This patch makes the earlier change to list paths with
'core.quotePath=false' basically redundant, because this could
decode any \nnn-escaped non-ASCII character just fine, as well.
However, I suspect that 'git ls-files' can deal with those
non-ASCII characters faster than this updated 'awk' script; just
in case someone is burdened with tons of pathnames containing
non-ASCII characters.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:35 +02:00
|
|
|
for (p in paths) {
|
|
|
|
if (substr(p, 1, 1) != "\"") {
|
|
|
|
# No special characters, easy!
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
print pfx p
|
completion: improve handling quoted paths in 'git ls-files's output
If any pathname contains backslash, double quote, tab, newline, or any
control characters, 'git ls-files' and 'git diff-index' will enclose
that pathname in double quotes and escape those special characters
using C-style one-character escape sequences or \nnn octal values.
This prevents those files from being listed during git-aware path
completion, because due to the quoting they will never match the
current word to be completed.
Extend __git_index_files()'s 'awk' script to remove all that quoting
and escaping from unique path components, so even paths containing
(almost all) such special characters can be completed.
Paths containing newline characters are still an issue, though. We
use newlines as separator character when filling the COMPREPLY array,
so a path with one or more newline will end up split to two or more
elements in COMPREPLY, basically breaking completion. There is
nothing we can do about it without a significant performance hit, so
let's just ignore such paths for now. As far as paths with newlines
are concerned, this isn't any different from the previous behavior,
because those paths were always omitted, though in the past they were
omitted because due to the quoting they didn't match the current word
to be completed. Anyway, Bash's own filename completion (Meta-/) can
complete even those paths, if need be.
Note:
- We don't dequote path components right away as they are coming in,
because then we would have to dequote each directory name
repeatedly, as many times as it appears in the input, i.e. as many
times as the number of listed paths it contains. Instead, we
dequote them at the end, as we print unique path components.
- Even when a directory name itself does not contain any special
characters, it will still be quoted if any of its trailing path
components do. If a directory contains paths both with and
without special characters, then the name of that directory will
appear both quoted and unquoted in the output of 'git ls-files'
and 'git diff-index'. Consequently, we will add such a directory
name to the deduplicating associative array twice: once quoted and
once unquoted.
This means that we have to be careful after dequoting a directory
name, and only print it if we haven't seen the same directory name
unquoted.
- It would be wonderful if we could just pass '-z' to those git
commands to output \0-separated unquoted paths, and use \0 as
record separator in the 'awk' script processing their output...
this patch would be so much simpler, almost trivial even.
Unfortunately, however, POSIX and most 'awk' implementations don't
support \0 as record separator (GNU awk does support it).
- This patch makes the earlier change to list paths with
'core.quotePath=false' basically redundant, because this could
decode any \nnn-escaped non-ASCII character just fine, as well.
However, I suspect that 'git ls-files' can deal with those
non-ASCII characters faster than this updated 'awk' script; just
in case someone is burdened with tons of pathnames containing
non-ASCII characters.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:35 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
# The path is quoted.
|
|
|
|
p = dequote(p)
|
|
|
|
if (p == "")
|
|
|
|
continue
|
|
|
|
|
|
|
|
# Even when a directory name itself does not contain
|
|
|
|
# any special characters, it will still be quoted if
|
|
|
|
# any of its (stripped) trailing path components do.
|
|
|
|
# Because of this we may have seen the same direcory
|
|
|
|
# both quoted and unquoted.
|
|
|
|
if (p in paths)
|
|
|
|
# We have seen the same directory unquoted,
|
|
|
|
# skip it.
|
|
|
|
continue
|
|
|
|
else
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
print pfx p
|
completion: improve handling quoted paths in 'git ls-files's output
If any pathname contains backslash, double quote, tab, newline, or any
control characters, 'git ls-files' and 'git diff-index' will enclose
that pathname in double quotes and escape those special characters
using C-style one-character escape sequences or \nnn octal values.
This prevents those files from being listed during git-aware path
completion, because due to the quoting they will never match the
current word to be completed.
Extend __git_index_files()'s 'awk' script to remove all that quoting
and escaping from unique path components, so even paths containing
(almost all) such special characters can be completed.
Paths containing newline characters are still an issue, though. We
use newlines as separator character when filling the COMPREPLY array,
so a path with one or more newline will end up split to two or more
elements in COMPREPLY, basically breaking completion. There is
nothing we can do about it without a significant performance hit, so
let's just ignore such paths for now. As far as paths with newlines
are concerned, this isn't any different from the previous behavior,
because those paths were always omitted, though in the past they were
omitted because due to the quoting they didn't match the current word
to be completed. Anyway, Bash's own filename completion (Meta-/) can
complete even those paths, if need be.
Note:
- We don't dequote path components right away as they are coming in,
because then we would have to dequote each directory name
repeatedly, as many times as it appears in the input, i.e. as many
times as the number of listed paths it contains. Instead, we
dequote them at the end, as we print unique path components.
- Even when a directory name itself does not contain any special
characters, it will still be quoted if any of its trailing path
components do. If a directory contains paths both with and
without special characters, then the name of that directory will
appear both quoted and unquoted in the output of 'git ls-files'
and 'git diff-index'. Consequently, we will add such a directory
name to the deduplicating associative array twice: once quoted and
once unquoted.
This means that we have to be careful after dequoting a directory
name, and only print it if we haven't seen the same directory name
unquoted.
- It would be wonderful if we could just pass '-z' to those git
commands to output \0-separated unquoted paths, and use \0 as
record separator in the 'awk' script processing their output...
this patch would be so much simpler, almost trivial even.
Unfortunately, however, POSIX and most 'awk' implementations don't
support \0 as record separator (GNU awk does support it).
- This patch makes the earlier change to list paths with
'core.quotePath=false' basically redundant, because this could
decode any \nnn-escaped non-ASCII character just fine, as well.
However, I suspect that 'git ls-files' can deal with those
non-ASCII characters faster than this updated 'awk' script; just
in case someone is burdened with tons of pathnames containing
non-ASCII characters.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
function dequote(p, bs_idx, out, esc, esc_idx, dec) {
|
|
|
|
# Skip opening double quote.
|
|
|
|
p = substr(p, 2)
|
|
|
|
|
|
|
|
# Interpret backslash escape sequences.
|
|
|
|
while ((bs_idx = index(p, "\\")) != 0) {
|
|
|
|
out = out substr(p, 1, bs_idx - 1)
|
|
|
|
esc = substr(p, bs_idx + 1, 1)
|
|
|
|
p = substr(p, bs_idx + 2)
|
|
|
|
|
|
|
|
if ((esc_idx = index("abtvfr\"\\", esc)) != 0) {
|
|
|
|
# C-style one-character escape sequence.
|
|
|
|
out = out substr("\a\b\t\v\f\r\"\\",
|
|
|
|
esc_idx, 1)
|
|
|
|
} else if (esc == "n") {
|
|
|
|
# Uh-oh, a newline character.
|
|
|
|
# We cant reliably put a pathname
|
|
|
|
# containing a newline into COMPREPLY,
|
|
|
|
# and the newline would create a mess.
|
|
|
|
# Skip this path.
|
|
|
|
return ""
|
|
|
|
} else {
|
|
|
|
# Must be a \nnn octal value, then.
|
|
|
|
dec = esc * 64 + \
|
|
|
|
substr(p, 1, 1) * 8 + \
|
|
|
|
substr(p, 2, 1)
|
|
|
|
out = out sprintf("%c", dec)
|
|
|
|
p = substr(p, 3)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# Drop closing double quote, if there is one.
|
|
|
|
# (There isnt any if this is a directory, as it was
|
|
|
|
# already stripped with the trailing path components.)
|
|
|
|
if (substr(p, length(p), 1) == "\"")
|
|
|
|
out = out substr(p, 1, length(p) - 1)
|
|
|
|
else
|
|
|
|
out = out p
|
|
|
|
|
|
|
|
return out
|
completion: remove repeated dirnames with 'awk' during path completion
During git-aware path completion, after all the trailing path
components have been removed from the output of 'git ls-files' and
'git diff-index' (see previous patch), each directory name is repeated
as many times as the number of listed paths it contains. This can be
a lot of repetitions, especially when invoking path completion close
to the root of a big worktree, which would cause a considerable
overhead downstream of __git_index_files(), in particular in the shell
loop that fills the COMPREPLY array. To reduce this overhead,
__git_index_files() runs the classic '... |sort |uniq' pattern to
remove those repetitions from the function's output.
While removing repeated directory names is effective in reducing the
number of iterations in that shell loop, it still imposes the overhead
of fork()+exec()ing two external processes, and two additional stages
in the pipeline, where potentially relatively large amount of data can
be passed between two subsequent pipeline stages.
Extend __git_index_files()'s 'awk' script to remove repeated path
components by first creating and filling an associative array indexed
by all encountered path components (after the trailing path components
have been removed), and then iterating over this array and printing
the indices, i.e. unique path components. This way we can remove the
'|sort |uniq' pipeline stages, and their eliminated overhead results
in faster path completion.
Listing all tracked files (12) and directories (23) at the top of the
worktree in linux.git (over 62k files), i.e. what's doing all the hard
work behind 'git rm <TAB>':
Before this patch, best of five, using GNU awk on Linux:
real 0m0.069s
user 0m0.089s
sys 0m0.026s
After:
real 0m0.052s
user 0m0.072s
sys 0m0.014s
Difference: -24.6%
Note that this changes order of elements in __git_index_files()'s
output. This is not an issue, because this function was only ever
intended to feed paths into the COMPREPLY array, and Bash will sort
its elements (according to the users locale) anyway.
Note also that using 'awk' to remove repeated path components is also
beneficial for the performance of the next two patches:
- The first will extend this 'awk' script to dequote quoted paths in
the output of 'git ls-files' and 'git diff-index'. With this
patch it will only have to dequote unique path components, not
all.
- The second will, among other things, extend this 'awk' script to
prepend prefix path components from the command line to the
currently completed path component. Consequently, each line in
'awk's output will grow longer. Without this patch that '|sort
|uniq' would have to exchange and process that much more data.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:13 +02:00
|
|
|
}'
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
}
|
|
|
|
|
2018-04-17 00:41:06 +02:00
|
|
|
# __git_complete_index_file requires 1 argument:
|
|
|
|
# 1: the options to pass to ls-file
|
|
|
|
#
|
|
|
|
# The exception is --committable, which finds the files appropriate commit.
|
|
|
|
__git_complete_index_file ()
|
|
|
|
{
|
completion: improve handling quoted paths on the command line
Our git-aware path completion doesn't work when it has to complete a
word already containing quoted and/or backslash-escaped characters on
the command line. The root cause of the issue is that completion
functions see all words on the command line verbatim, i.e. including
all backslash, single and double quote characters that the shell would
eventually remove when executing the finished command. These
quoting/escaping characters cause different issues depending on which
path component of the word to be completed contains them:
- The quoting/escaping is in the prefix path component(s).
Let's suppose we have a directory called 'New Dir', containing two
untracked files 'file.c' and 'file.o', and we have a gitignore
rule ignoring object files. In this case all of these:
git add New\ Dir/<TAB>
git add "New Dir/<TAB>
git add 'New Dir/<TAB>
should uniquely complete 'file.c' right away, but Bash offers both
'file.c' and 'file.o' instead. The reason for this behavior is
that our completion script uses the prefix directory name like
'git -C "New\ Dir/" ls-files ...", i.e. with the backslash inside
double quotes. Git then tries to enter a directory called
'New\ Dir', which (most likely) fails because such a directory
doesn't exists. As a result our completion script doesn't list
any files, leaves the COMPREPLY array empty, which in turn causes
Bash to fall back to its simple filename completion and lists all
files in that directory, i.e. both 'file.c' and 'file.o'.
- The quoting/escaping is in the path component to be completed.
Let's suppose we have two untracked files 'New File.c' and
'New File.o', and we have a gitignore rule ignoring object files.
In this case all of these:
git add New\ Fi<TAB>
git add "New Fi<TAB>
git add 'New Fi<TAB>
should uniquely complete 'New File.c' right away, but Bash offers
both 'New File.c' and 'New File.o' instead. The reason for this
behavior is that our completion script uses this 'New\ Fi' or
'"New Fi' etc. word to filter matching paths, and of course none
of the potential filenames will match because of the included
backslash or double quote. The end result is the same as above:
the completion script doesn't list any files, Bash falls back to
its filename completion, which then lists the matching object file
as well.
Add the new helper function __git_dequote() [1], which removes (most
of[2]) the quoting and escaping from the word it gets as argument. To
minimize the overhead of calling this function, store its result in
the variable $dequoted_word, supposed to be declared local in the
caller; simply printing the result would require a command
substitution imposing the overhead of fork()ing a subshell. Use this
function in __git_complete_index_file() to dequote the current word,
i.e. the path, to be completed, to avoid the above described
quoting-related issues, thereby fixing two of the failing quoted path
completion tests.
[1] The bash-completion project already has a dequote() function,
which I hoped I could borrow to deal with this, but unfortunately
it doesn't work quite well for this purpose (perhaps that's why
even the bash-completion project only rarely uses it). The main
issue is that their dequote() is implemented as:
eval printf %s "$1" 2> /dev/null
where $1 would contain the word to be completed. While it's a
short and sweet one-liner, the use of 'eval' requires that $1 is a
syntactically valid string, which is not the case when quoting the
path like 'git add "New Dir/<TAB>'. This causes 'eval' to fail,
because it can't find the matching closing double quote, and the
function returns nothing. The result is totally broken behavior,
as if the current word were empty, and the completion script would
then list all files from the current directory. This is why one
of the quoted path completion tests specifically checks the
completion of a path with an opening but without a corresponding
closing double quote character. Furthermore, the 'eval' performs
all kinds of expansions, which may or may not be desired; I think
it's the latter. Finally, using this function would require a
command substitution.
[2] Bash understands the $'string' quoting as well, which "expands to
'string', with backslash-escaped characters replaced as specified
by the ANSI C standard" (quoted from Bash manpage). Since shell
metacharacters, field separators, globbing, etc. can all be easily
entered using standard shell escaping or quoting, this type of
quoting comes in handly when dealing with control characters that
are otherwise difficult both to "type" and to see on the command
line. Because of this difficulty I would assume that people do
avoid pathnames with such control characters anyway, so I didn't
bother implementing it. This function is already way too long as
it is.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:09 +02:00
|
|
|
local dequoted_word pfx="" cur_
|
2018-04-17 00:41:06 +02:00
|
|
|
|
completion: improve handling quoted paths on the command line
Our git-aware path completion doesn't work when it has to complete a
word already containing quoted and/or backslash-escaped characters on
the command line. The root cause of the issue is that completion
functions see all words on the command line verbatim, i.e. including
all backslash, single and double quote characters that the shell would
eventually remove when executing the finished command. These
quoting/escaping characters cause different issues depending on which
path component of the word to be completed contains them:
- The quoting/escaping is in the prefix path component(s).
Let's suppose we have a directory called 'New Dir', containing two
untracked files 'file.c' and 'file.o', and we have a gitignore
rule ignoring object files. In this case all of these:
git add New\ Dir/<TAB>
git add "New Dir/<TAB>
git add 'New Dir/<TAB>
should uniquely complete 'file.c' right away, but Bash offers both
'file.c' and 'file.o' instead. The reason for this behavior is
that our completion script uses the prefix directory name like
'git -C "New\ Dir/" ls-files ...", i.e. with the backslash inside
double quotes. Git then tries to enter a directory called
'New\ Dir', which (most likely) fails because such a directory
doesn't exists. As a result our completion script doesn't list
any files, leaves the COMPREPLY array empty, which in turn causes
Bash to fall back to its simple filename completion and lists all
files in that directory, i.e. both 'file.c' and 'file.o'.
- The quoting/escaping is in the path component to be completed.
Let's suppose we have two untracked files 'New File.c' and
'New File.o', and we have a gitignore rule ignoring object files.
In this case all of these:
git add New\ Fi<TAB>
git add "New Fi<TAB>
git add 'New Fi<TAB>
should uniquely complete 'New File.c' right away, but Bash offers
both 'New File.c' and 'New File.o' instead. The reason for this
behavior is that our completion script uses this 'New\ Fi' or
'"New Fi' etc. word to filter matching paths, and of course none
of the potential filenames will match because of the included
backslash or double quote. The end result is the same as above:
the completion script doesn't list any files, Bash falls back to
its filename completion, which then lists the matching object file
as well.
Add the new helper function __git_dequote() [1], which removes (most
of[2]) the quoting and escaping from the word it gets as argument. To
minimize the overhead of calling this function, store its result in
the variable $dequoted_word, supposed to be declared local in the
caller; simply printing the result would require a command
substitution imposing the overhead of fork()ing a subshell. Use this
function in __git_complete_index_file() to dequote the current word,
i.e. the path, to be completed, to avoid the above described
quoting-related issues, thereby fixing two of the failing quoted path
completion tests.
[1] The bash-completion project already has a dequote() function,
which I hoped I could borrow to deal with this, but unfortunately
it doesn't work quite well for this purpose (perhaps that's why
even the bash-completion project only rarely uses it). The main
issue is that their dequote() is implemented as:
eval printf %s "$1" 2> /dev/null
where $1 would contain the word to be completed. While it's a
short and sweet one-liner, the use of 'eval' requires that $1 is a
syntactically valid string, which is not the case when quoting the
path like 'git add "New Dir/<TAB>'. This causes 'eval' to fail,
because it can't find the matching closing double quote, and the
function returns nothing. The result is totally broken behavior,
as if the current word were empty, and the completion script would
then list all files from the current directory. This is why one
of the quoted path completion tests specifically checks the
completion of a path with an opening but without a corresponding
closing double quote character. Furthermore, the 'eval' performs
all kinds of expansions, which may or may not be desired; I think
it's the latter. Finally, using this function would require a
command substitution.
[2] Bash understands the $'string' quoting as well, which "expands to
'string', with backslash-escaped characters replaced as specified
by the ANSI C standard" (quoted from Bash manpage). Since shell
metacharacters, field separators, globbing, etc. can all be easily
entered using standard shell escaping or quoting, this type of
quoting comes in handly when dealing with control characters that
are otherwise difficult both to "type" and to see on the command
line. Because of this difficulty I would assume that people do
avoid pathnames with such control characters anyway, so I didn't
bother implementing it. This function is already way too long as
it is.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:09 +02:00
|
|
|
__git_dequote "$cur"
|
|
|
|
|
|
|
|
case "$dequoted_word" in
|
2018-04-17 00:41:06 +02:00
|
|
|
?*/*)
|
completion: improve handling quoted paths on the command line
Our git-aware path completion doesn't work when it has to complete a
word already containing quoted and/or backslash-escaped characters on
the command line. The root cause of the issue is that completion
functions see all words on the command line verbatim, i.e. including
all backslash, single and double quote characters that the shell would
eventually remove when executing the finished command. These
quoting/escaping characters cause different issues depending on which
path component of the word to be completed contains them:
- The quoting/escaping is in the prefix path component(s).
Let's suppose we have a directory called 'New Dir', containing two
untracked files 'file.c' and 'file.o', and we have a gitignore
rule ignoring object files. In this case all of these:
git add New\ Dir/<TAB>
git add "New Dir/<TAB>
git add 'New Dir/<TAB>
should uniquely complete 'file.c' right away, but Bash offers both
'file.c' and 'file.o' instead. The reason for this behavior is
that our completion script uses the prefix directory name like
'git -C "New\ Dir/" ls-files ...", i.e. with the backslash inside
double quotes. Git then tries to enter a directory called
'New\ Dir', which (most likely) fails because such a directory
doesn't exists. As a result our completion script doesn't list
any files, leaves the COMPREPLY array empty, which in turn causes
Bash to fall back to its simple filename completion and lists all
files in that directory, i.e. both 'file.c' and 'file.o'.
- The quoting/escaping is in the path component to be completed.
Let's suppose we have two untracked files 'New File.c' and
'New File.o', and we have a gitignore rule ignoring object files.
In this case all of these:
git add New\ Fi<TAB>
git add "New Fi<TAB>
git add 'New Fi<TAB>
should uniquely complete 'New File.c' right away, but Bash offers
both 'New File.c' and 'New File.o' instead. The reason for this
behavior is that our completion script uses this 'New\ Fi' or
'"New Fi' etc. word to filter matching paths, and of course none
of the potential filenames will match because of the included
backslash or double quote. The end result is the same as above:
the completion script doesn't list any files, Bash falls back to
its filename completion, which then lists the matching object file
as well.
Add the new helper function __git_dequote() [1], which removes (most
of[2]) the quoting and escaping from the word it gets as argument. To
minimize the overhead of calling this function, store its result in
the variable $dequoted_word, supposed to be declared local in the
caller; simply printing the result would require a command
substitution imposing the overhead of fork()ing a subshell. Use this
function in __git_complete_index_file() to dequote the current word,
i.e. the path, to be completed, to avoid the above described
quoting-related issues, thereby fixing two of the failing quoted path
completion tests.
[1] The bash-completion project already has a dequote() function,
which I hoped I could borrow to deal with this, but unfortunately
it doesn't work quite well for this purpose (perhaps that's why
even the bash-completion project only rarely uses it). The main
issue is that their dequote() is implemented as:
eval printf %s "$1" 2> /dev/null
where $1 would contain the word to be completed. While it's a
short and sweet one-liner, the use of 'eval' requires that $1 is a
syntactically valid string, which is not the case when quoting the
path like 'git add "New Dir/<TAB>'. This causes 'eval' to fail,
because it can't find the matching closing double quote, and the
function returns nothing. The result is totally broken behavior,
as if the current word were empty, and the completion script would
then list all files from the current directory. This is why one
of the quoted path completion tests specifically checks the
completion of a path with an opening but without a corresponding
closing double quote character. Furthermore, the 'eval' performs
all kinds of expansions, which may or may not be desired; I think
it's the latter. Finally, using this function would require a
command substitution.
[2] Bash understands the $'string' quoting as well, which "expands to
'string', with backslash-escaped characters replaced as specified
by the ANSI C standard" (quoted from Bash manpage). Since shell
metacharacters, field separators, globbing, etc. can all be easily
entered using standard shell escaping or quoting, this type of
quoting comes in handly when dealing with control characters that
are otherwise difficult both to "type" and to see on the command
line. Because of this difficulty I would assume that people do
avoid pathnames with such control characters anyway, so I didn't
bother implementing it. This function is already way too long as
it is.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:09 +02:00
|
|
|
pfx="${dequoted_word%/*}/"
|
|
|
|
cur_="${dequoted_word##*/}"
|
2018-04-17 00:41:06 +02:00
|
|
|
;;
|
completion: improve handling quoted paths on the command line
Our git-aware path completion doesn't work when it has to complete a
word already containing quoted and/or backslash-escaped characters on
the command line. The root cause of the issue is that completion
functions see all words on the command line verbatim, i.e. including
all backslash, single and double quote characters that the shell would
eventually remove when executing the finished command. These
quoting/escaping characters cause different issues depending on which
path component of the word to be completed contains them:
- The quoting/escaping is in the prefix path component(s).
Let's suppose we have a directory called 'New Dir', containing two
untracked files 'file.c' and 'file.o', and we have a gitignore
rule ignoring object files. In this case all of these:
git add New\ Dir/<TAB>
git add "New Dir/<TAB>
git add 'New Dir/<TAB>
should uniquely complete 'file.c' right away, but Bash offers both
'file.c' and 'file.o' instead. The reason for this behavior is
that our completion script uses the prefix directory name like
'git -C "New\ Dir/" ls-files ...", i.e. with the backslash inside
double quotes. Git then tries to enter a directory called
'New\ Dir', which (most likely) fails because such a directory
doesn't exists. As a result our completion script doesn't list
any files, leaves the COMPREPLY array empty, which in turn causes
Bash to fall back to its simple filename completion and lists all
files in that directory, i.e. both 'file.c' and 'file.o'.
- The quoting/escaping is in the path component to be completed.
Let's suppose we have two untracked files 'New File.c' and
'New File.o', and we have a gitignore rule ignoring object files.
In this case all of these:
git add New\ Fi<TAB>
git add "New Fi<TAB>
git add 'New Fi<TAB>
should uniquely complete 'New File.c' right away, but Bash offers
both 'New File.c' and 'New File.o' instead. The reason for this
behavior is that our completion script uses this 'New\ Fi' or
'"New Fi' etc. word to filter matching paths, and of course none
of the potential filenames will match because of the included
backslash or double quote. The end result is the same as above:
the completion script doesn't list any files, Bash falls back to
its filename completion, which then lists the matching object file
as well.
Add the new helper function __git_dequote() [1], which removes (most
of[2]) the quoting and escaping from the word it gets as argument. To
minimize the overhead of calling this function, store its result in
the variable $dequoted_word, supposed to be declared local in the
caller; simply printing the result would require a command
substitution imposing the overhead of fork()ing a subshell. Use this
function in __git_complete_index_file() to dequote the current word,
i.e. the path, to be completed, to avoid the above described
quoting-related issues, thereby fixing two of the failing quoted path
completion tests.
[1] The bash-completion project already has a dequote() function,
which I hoped I could borrow to deal with this, but unfortunately
it doesn't work quite well for this purpose (perhaps that's why
even the bash-completion project only rarely uses it). The main
issue is that their dequote() is implemented as:
eval printf %s "$1" 2> /dev/null
where $1 would contain the word to be completed. While it's a
short and sweet one-liner, the use of 'eval' requires that $1 is a
syntactically valid string, which is not the case when quoting the
path like 'git add "New Dir/<TAB>'. This causes 'eval' to fail,
because it can't find the matching closing double quote, and the
function returns nothing. The result is totally broken behavior,
as if the current word were empty, and the completion script would
then list all files from the current directory. This is why one
of the quoted path completion tests specifically checks the
completion of a path with an opening but without a corresponding
closing double quote character. Furthermore, the 'eval' performs
all kinds of expansions, which may or may not be desired; I think
it's the latter. Finally, using this function would require a
command substitution.
[2] Bash understands the $'string' quoting as well, which "expands to
'string', with backslash-escaped characters replaced as specified
by the ANSI C standard" (quoted from Bash manpage). Since shell
metacharacters, field separators, globbing, etc. can all be easily
entered using standard shell escaping or quoting, this type of
quoting comes in handly when dealing with control characters that
are otherwise difficult both to "type" and to see on the command
line. Because of this difficulty I would assume that people do
avoid pathnames with such control characters anyway, so I didn't
bother implementing it. This function is already way too long as
it is.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:09 +02:00
|
|
|
*)
|
|
|
|
cur_="$dequoted_word"
|
2018-04-17 00:41:06 +02:00
|
|
|
esac
|
|
|
|
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
}
|
|
|
|
|
2017-03-23 16:29:24 +01:00
|
|
|
# Lists branches from the local repository.
|
|
|
|
# 1: A prefix to be added to each listed branch (optional).
|
|
|
|
# 2: List only branches matching this word (optional; list all branches if
|
|
|
|
# unset or empty).
|
|
|
|
# 3: A suffix to be appended to each listed branch (optional).
|
2006-11-27 10:44:47 +01:00
|
|
|
__git_heads ()
|
|
|
|
{
|
2017-03-23 16:29:24 +01:00
|
|
|
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
|
|
|
|
|
|
|
|
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
|
|
|
|
"refs/heads/$cur_*" "refs/heads/$cur_*/**"
|
2006-11-27 10:44:47 +01:00
|
|
|
}
|
|
|
|
|
2017-03-23 16:29:24 +01:00
|
|
|
# Lists tags from the local repository.
|
|
|
|
# Accepts the same positional parameters as __git_heads() above.
|
2007-09-01 05:47:01 +02:00
|
|
|
__git_tags ()
|
|
|
|
{
|
2017-03-23 16:29:24 +01:00
|
|
|
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
|
|
|
|
|
|
|
|
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
|
|
|
|
"refs/tags/$cur_*" "refs/tags/$cur_*/**"
|
2007-09-01 05:47:01 +02:00
|
|
|
}
|
|
|
|
|
2017-02-03 03:48:09 +01:00
|
|
|
# Lists refs from the local (by default) or from a remote repository.
|
|
|
|
# It accepts 0, 1 or 2 arguments:
|
|
|
|
# 1: The remote to list refs from (optional; ignored, if set but empty).
|
completion: list short refs from a remote given as a URL
e832f5c09680 (completion: avoid ls-remote in certain scenarios,
2013-05-28) turned a 'git ls-remote <remote>' query into a 'git
for-each-ref refs/remotes/<remote>/' to improve responsiveness of
remote refs completion by avoiding potential network communication.
However, it inadvertently made impossible to complete short refs from
a remote given as a URL, e.g. 'git fetch git://server.com/repo.git
<TAB>', because there is, of course, no such thing as
'refs/remotes/git://server.com/repo.git'.
Since the previous commit we tell apart configured remotes, i.e. those
that can have a hierarchy under 'refs/remotes/', from others that
don't, including remotes given as URL, so we know when we can't use
the faster 'git for-each-ref'-based approach.
Resurrect the old, pre-e832f5c09680 'git ls-remote'-based code for the
latter case to support listing short refs from remotes given as a URL.
The code is slightly updated from the original to
- take into account the path to the repository given on the command
line (if any), and
- omit 'ORIG_HEAD' from the query, as 'git ls-remote' will never
list it anyway.
When the remote given to __git_refs() doesn't exist, then it will be
handled by this resurrected 'git ls-remote' query. This code path
doesn't list 'HEAD' unconditionally, which has the nice side effect of
fixing two more expected test failures.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:20 +01:00
|
|
|
# Can be the name of a configured remote, a path, or a URL.
|
2017-02-03 03:48:09 +01:00
|
|
|
# 2: In addition to local refs, list unique branches from refs/remotes/ for
|
|
|
|
# 'git checkout's tracking DWIMery (optional; ignored, if set but empty).
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
# 3: A prefix to be added to each listed ref (optional).
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
# 4: List only refs matching this word (optional; list all refs if unset or
|
|
|
|
# empty).
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
# 5: A suffix to be appended to each listed ref (optional; ignored, if set
|
|
|
|
# but empty).
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
#
|
|
|
|
# Use __git_complete_refs() instead.
|
2006-09-28 11:31:25 +02:00
|
|
|
__git_refs ()
|
|
|
|
{
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
local i hash dir track="${2-}"
|
2017-02-03 03:48:17 +01:00
|
|
|
local list_refs_from=path remote="${1-}"
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
local format refs
|
|
|
|
local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
local match="${4-}"
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
|
2017-02-03 03:48:17 +01:00
|
|
|
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
dir="$__git_repo_path"
|
|
|
|
|
2017-02-03 03:48:19 +01:00
|
|
|
if [ -z "$remote" ]; then
|
|
|
|
if [ -z "$dir" ]; then
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
else
|
2017-02-03 03:48:18 +01:00
|
|
|
if __git_is_configured_remote "$remote"; then
|
|
|
|
# configured remote takes precedence over a
|
|
|
|
# local directory with the same name
|
|
|
|
list_refs_from=remote
|
|
|
|
elif [ -d "$remote/.git" ]; then
|
2017-02-03 03:48:17 +01:00
|
|
|
dir="$remote/.git"
|
|
|
|
elif [ -d "$remote" ]; then
|
|
|
|
dir="$remote"
|
|
|
|
else
|
2017-02-03 03:48:18 +01:00
|
|
|
list_refs_from=url
|
2017-02-03 03:48:17 +01:00
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2017-02-03 03:48:19 +01:00
|
|
|
if [ "$list_refs_from" = path ]; then
|
2017-03-23 16:29:15 +01:00
|
|
|
if [[ "$cur_" == ^* ]]; then
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
pfx="$pfx^"
|
|
|
|
fer_pfx="$fer_pfx^"
|
2017-03-23 16:29:15 +01:00
|
|
|
cur_=${cur_#^}
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
match=${match#^}
|
2017-03-23 16:29:15 +01:00
|
|
|
fi
|
2017-03-23 16:29:13 +01:00
|
|
|
case "$cur_" in
|
2008-11-28 01:46:38 +01:00
|
|
|
refs|refs/*)
|
|
|
|
format="refname"
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
refs=("$match*" "$match*/**")
|
2010-10-12 23:38:12 +02:00
|
|
|
track=""
|
2008-11-28 01:46:38 +01:00
|
|
|
;;
|
|
|
|
*)
|
2018-02-11 10:43:28 +01:00
|
|
|
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
case "$i" in
|
|
|
|
$match*)
|
|
|
|
if [ -e "$dir/$i" ]; then
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
echo "$pfx$i$sfx"
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
fi
|
|
|
|
;;
|
|
|
|
esac
|
2010-03-17 10:20:35 +01:00
|
|
|
done
|
completion: don't disambiguate short refs
When the completion script lists short refs it does so using the 'git
for-each-ref' format 'refname:short', which makes sure that all listed
refs are unambiguous. While disambiguating refs is technically
correct in this case, as opposed to the cases discussed in the
previous patch, this disambiguation involves several stat() syscalls
for each ref, thus, unfortunately, comes at a steep cost especially on
Windows and/or when there are a lot of refs to be listed. A user of
Git for Windows reported[1] 'git checkout <TAB>' taking ~11 seconds in
a repository with just about 4000 refs.
However, it's questionable whether ambiguous refs are really that bad
to justify that much extra cost:
- Ambiguous refs are not that common,
- even if a repository contains ambiguous refs, they only hurt when
the user actually happens to want to do something with one of the
ambiguous refs, and
- the issue can be easily circumvented by renaming those ambiguous
refs.
- On the other hand, apparently not that many refs are needed to
make refs completion unacceptably slow on Windows,
- and this slowness bites each and every time the user attempts refs
completion, even when the repository doesn't contain any ambiguous
refs.
- Furthermore, circumventing the issue might not be possible or
might be considerably more difficult and requires various
trade-offs (e.g. working in a repository with only a few selected
important refs while keeping a separate repository with all refs
for reference).
Arguably, in this case the benefits of technical correctness are
rather minor compared to the price we pay for it, and we are better
off opting for performance over correctness.
Use the 'git for-each-ref' format 'refname:strip=2' to list short refs
to spare the substantial cost of disambiguating.
This speeds up refs completion considerably. Uniquely completing a
branch in a repository with 100k local branches, all packed, best of
five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m1.662s
user 0m1.368s
sys 0m0.296s
After:
real 0m0.831s
user 0m0.808s
sys 0m0.028s
On Windows, before:
real 0m12.457s
user 0m1.016s
sys 0m0.092s
After:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
[1] - https://github.com/git-for-windows/git/issues/524
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:17 +01:00
|
|
|
format="refname:strip=2"
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
refs=("refs/tags/$match*" "refs/tags/$match*/**"
|
|
|
|
"refs/heads/$match*" "refs/heads/$match*/**"
|
|
|
|
"refs/remotes/$match*" "refs/remotes/$match*/**")
|
2008-11-28 01:46:38 +01:00
|
|
|
;;
|
|
|
|
esac
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
"${refs[@]}"
|
2010-10-12 23:38:12 +02:00
|
|
|
if [ -n "$track" ]; then
|
|
|
|
# employ the heuristic used by git checkout
|
|
|
|
# Try to find a remote branch that matches the completion word
|
|
|
|
# but only output if the branch name is unique
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
|
2017-03-23 16:29:21 +01:00
|
|
|
--sort="refname:strip=3" \
|
2017-03-23 16:29:20 +01:00
|
|
|
"refs/remotes/*/$match*" "refs/remotes/*/$match*/**" | \
|
2017-03-23 16:29:21 +01:00
|
|
|
uniq -u
|
2010-10-12 23:38:12 +02:00
|
|
|
fi
|
2006-11-27 09:42:32 +01:00
|
|
|
return
|
2006-09-28 11:31:25 +02:00
|
|
|
fi
|
2017-03-23 16:29:13 +01:00
|
|
|
case "$cur_" in
|
2011-10-08 16:54:39 +02:00
|
|
|
refs|refs/*)
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
__git ls-remote "$remote" "$match*" | \
|
2011-12-21 16:54:14 +01:00
|
|
|
while read -r hash i; do
|
2011-10-08 16:54:39 +02:00
|
|
|
case "$i" in
|
|
|
|
*^{}) ;;
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
*) echo "$pfx$i$sfx" ;;
|
2011-10-08 16:54:39 +02:00
|
|
|
esac
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
*)
|
completion: list short refs from a remote given as a URL
e832f5c09680 (completion: avoid ls-remote in certain scenarios,
2013-05-28) turned a 'git ls-remote <remote>' query into a 'git
for-each-ref refs/remotes/<remote>/' to improve responsiveness of
remote refs completion by avoiding potential network communication.
However, it inadvertently made impossible to complete short refs from
a remote given as a URL, e.g. 'git fetch git://server.com/repo.git
<TAB>', because there is, of course, no such thing as
'refs/remotes/git://server.com/repo.git'.
Since the previous commit we tell apart configured remotes, i.e. those
that can have a hierarchy under 'refs/remotes/', from others that
don't, including remotes given as URL, so we know when we can't use
the faster 'git for-each-ref'-based approach.
Resurrect the old, pre-e832f5c09680 'git ls-remote'-based code for the
latter case to support listing short refs from remotes given as a URL.
The code is slightly updated from the original to
- take into account the path to the repository given on the command
line (if any), and
- omit 'ORIG_HEAD' from the query, as 'git ls-remote' will never
list it anyway.
When the remote given to __git_refs() doesn't exist, then it will be
handled by this resurrected 'git ls-remote' query. This code path
doesn't list 'HEAD' unconditionally, which has the nice side effect of
fixing two more expected test failures.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:20 +01:00
|
|
|
if [ "$list_refs_from" = remote ]; then
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
case "HEAD" in
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
$match*) echo "${pfx}HEAD$sfx" ;;
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
esac
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
"refs/remotes/$remote/$match*" \
|
2017-03-23 16:29:19 +01:00
|
|
|
"refs/remotes/$remote/$match*/**"
|
completion: list short refs from a remote given as a URL
e832f5c09680 (completion: avoid ls-remote in certain scenarios,
2013-05-28) turned a 'git ls-remote <remote>' query into a 'git
for-each-ref refs/remotes/<remote>/' to improve responsiveness of
remote refs completion by avoiding potential network communication.
However, it inadvertently made impossible to complete short refs from
a remote given as a URL, e.g. 'git fetch git://server.com/repo.git
<TAB>', because there is, of course, no such thing as
'refs/remotes/git://server.com/repo.git'.
Since the previous commit we tell apart configured remotes, i.e. those
that can have a hierarchy under 'refs/remotes/', from others that
don't, including remotes given as URL, so we know when we can't use
the faster 'git for-each-ref'-based approach.
Resurrect the old, pre-e832f5c09680 'git ls-remote'-based code for the
latter case to support listing short refs from remotes given as a URL.
The code is slightly updated from the original to
- take into account the path to the repository given on the command
line (if any), and
- omit 'ORIG_HEAD' from the query, as 'git ls-remote' will never
list it anyway.
When the remote given to __git_refs() doesn't exist, then it will be
handled by this resurrected 'git ls-remote' query. This code path
doesn't list 'HEAD' unconditionally, which has the nice side effect of
fixing two more expected test failures.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:20 +01:00
|
|
|
else
|
completion: let 'for-each-ref' and 'ls-remote' filter matching refs
When completing refs, several __git_refs() code paths list all the
refs from the refs/{heads,tags,remotes}/ hierarchy and then
__gitcomp_nl() iterates over those refs in a shell loop to filter out
refs not matching the current ref to be completed. This comes with a
considerable performance penalty when a repository contains a lot of
refs but the current ref can be uniquely completed or when only a
handful of refs match the current ref.
Reduce the number of iterations in __gitcomp_nl() from the number of
refs to the number of matching refs by specifying appropriate globbing
patterns to 'git for-each-ref' and 'git ls-remote' to list only those
refs that match the current ref to be completed. However, do so only
when the ref to match is explicitly given as parameter, because the
current word on the command line might contain a prefix like
'--option=' or 'branch..'. The __git_complete_refs() and
__git_complete_fetch_refspecs() helpers introduced previously in this
patch series already call __git_refs() specifying this current ref
parameter, so all their callsites, i.e. all places in the completion
script doing refs completion, can benefit from this optimization.
Furthermore, list only those symbolic and pseudo refs that match the
current ref to be completed. Though it doesn't matter at all in
itself performance-wise, it will allow us further significant
optimizations later in this series.
This speeds up refs completion considerably when there are a lot of
non-matching refs to be filtered out. Uniquely completing a branch in
a repository with 100k local branches, all packed, best of five:
On Linux, before:
$ time __git_complete_refs --cur=maste
real 0m0.831s
user 0m0.808s
sys 0m0.028s
After:
real 0m0.119s
user 0m0.104s
sys 0m0.008s
On Windows, before:
real 0m1.480s
user 0m1.031s
sys 0m0.060s
After:
real 0m0.377s
user 0m0.015s
sys 0m0.030s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:18 +01:00
|
|
|
local query_symref
|
|
|
|
case "HEAD" in
|
|
|
|
$match*) query_symref="HEAD" ;;
|
|
|
|
esac
|
|
|
|
__git ls-remote "$remote" $query_symref \
|
|
|
|
"refs/tags/$match*" "refs/heads/$match*" \
|
|
|
|
"refs/remotes/$match*" |
|
completion: list short refs from a remote given as a URL
e832f5c09680 (completion: avoid ls-remote in certain scenarios,
2013-05-28) turned a 'git ls-remote <remote>' query into a 'git
for-each-ref refs/remotes/<remote>/' to improve responsiveness of
remote refs completion by avoiding potential network communication.
However, it inadvertently made impossible to complete short refs from
a remote given as a URL, e.g. 'git fetch git://server.com/repo.git
<TAB>', because there is, of course, no such thing as
'refs/remotes/git://server.com/repo.git'.
Since the previous commit we tell apart configured remotes, i.e. those
that can have a hierarchy under 'refs/remotes/', from others that
don't, including remotes given as URL, so we know when we can't use
the faster 'git for-each-ref'-based approach.
Resurrect the old, pre-e832f5c09680 'git ls-remote'-based code for the
latter case to support listing short refs from remotes given as a URL.
The code is slightly updated from the original to
- take into account the path to the repository given on the command
line (if any), and
- omit 'ORIG_HEAD' from the query, as 'git ls-remote' will never
list it anyway.
When the remote given to __git_refs() doesn't exist, then it will be
handled by this resurrected 'git ls-remote' query. This code path
doesn't list 'HEAD' unconditionally, which has the nice side effect of
fixing two more expected test failures.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:20 +01:00
|
|
|
while read -r hash i; do
|
|
|
|
case "$i" in
|
|
|
|
*^{}) ;;
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
refs/*) echo "$pfx${i#refs/*/}$sfx" ;;
|
|
|
|
*) echo "$pfx$i$sfx" ;; # symbolic refs
|
completion: list short refs from a remote given as a URL
e832f5c09680 (completion: avoid ls-remote in certain scenarios,
2013-05-28) turned a 'git ls-remote <remote>' query into a 'git
for-each-ref refs/remotes/<remote>/' to improve responsiveness of
remote refs completion by avoiding potential network communication.
However, it inadvertently made impossible to complete short refs from
a remote given as a URL, e.g. 'git fetch git://server.com/repo.git
<TAB>', because there is, of course, no such thing as
'refs/remotes/git://server.com/repo.git'.
Since the previous commit we tell apart configured remotes, i.e. those
that can have a hierarchy under 'refs/remotes/', from others that
don't, including remotes given as URL, so we know when we can't use
the faster 'git for-each-ref'-based approach.
Resurrect the old, pre-e832f5c09680 'git ls-remote'-based code for the
latter case to support listing short refs from remotes given as a URL.
The code is slightly updated from the original to
- take into account the path to the repository given on the command
line (if any), and
- omit 'ORIG_HEAD' from the query, as 'git ls-remote' will never
list it anyway.
When the remote given to __git_refs() doesn't exist, then it will be
handled by this resurrected 'git ls-remote' query. This code path
doesn't list 'HEAD' unconditionally, which has the nice side effect of
fixing two more expected test failures.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:20 +01:00
|
|
|
esac
|
|
|
|
done
|
|
|
|
fi
|
2011-10-08 16:54:39 +02:00
|
|
|
;;
|
|
|
|
esac
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
# Completes refs, short and long, local and remote, symbolic and pseudo.
|
|
|
|
#
|
|
|
|
# Usage: __git_complete_refs [<option>]...
|
|
|
|
# --remote=<remote>: The remote to list refs from, can be the name of a
|
|
|
|
# configured remote, a path, or a URL.
|
|
|
|
# --track: List unique remote branches for 'git checkout's tracking DWIMery.
|
|
|
|
# --pfx=<prefix>: A prefix to be added to each ref.
|
|
|
|
# --cur=<word>: The current ref to be completed. Defaults to the current
|
|
|
|
# word to be completed.
|
|
|
|
# --sfx=<suffix>: A suffix to be appended to each ref instead of the default
|
|
|
|
# space.
|
|
|
|
__git_complete_refs ()
|
|
|
|
{
|
|
|
|
local remote track pfx cur_="$cur" sfx=" "
|
|
|
|
|
|
|
|
while test $# != 0; do
|
|
|
|
case "$1" in
|
|
|
|
--remote=*) remote="${1##--remote=}" ;;
|
|
|
|
--track) track="yes" ;;
|
|
|
|
--pfx=*) pfx="${1##--pfx=}" ;;
|
|
|
|
--cur=*) cur_="${1##--cur=}" ;;
|
|
|
|
--sfx=*) sfx="${1##--sfx=}" ;;
|
|
|
|
*) return 1 ;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
__gitcomp_direct "$(__git_refs "$remote" "$track" "$pfx" "$cur_" "$sfx")"
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
}
|
|
|
|
|
2009-01-15 17:02:23 +01:00
|
|
|
# __git_refs2 requires 1 argument (to pass to __git_refs)
|
completion: support completing fully qualified non-fast-forward refspecs
After 'git fetch <remote> <TAB>' our completion script offers refspecs
that will fetch to a local branch with the same name as in the remote
repository, e.g. 'master:master'. This also completes
non-fast-forward refspecs, i.e. after a '+' prefix like
'+master:master', and fully qualified refspecs, e.g.
'refs/heads/master:refs/heads/master'. However, it does not complete
non-fast-forward fully qualified refspecs (or fully qualified refspecs
following any other prefix, e.g. '--option=', though currently no git
command supports such an option, but third party git commands might).
These refspecs are listed by the __git_refs2() function, which is just
a thin wrapper iterating over __git_refs()'s output, turning each
listed ref into a refspec. Now, it's certainly possible to modify
__git_refs2() and its callsite to pass an extra parameter containing
only the ref part of the current word to be completed (to follow suit
of the previous commit) to deal with prefixed fully qualified refspecs
as well. Unfortunately, keeping the current behavior unchanged in the
"no extra parameter" case brings in a bit of subtlety, which makes the
resulting code ugly and compelled me to write a 8-line long comment in
the proof of concept. Not good. However, since the callsite has to
be modified for proper functioning anyway, we might as well leave
__git_refs2() as is and introduce a new helper function without
backwards compatibility concerns.
Add the new function __git_complete_fetch_refspecs() that has all the
necessary parameters to do the right thing in all cases mentioned
above, including non-fast-forward fully qualified refspecs. This new
function can also easier benefit from optimizations coming later in
this patch series.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:14 +01:00
|
|
|
# Deprecated: use __git_complete_fetch_refspecs() instead.
|
2006-09-28 11:31:25 +02:00
|
|
|
__git_refs2 ()
|
|
|
|
{
|
2006-11-28 18:12:26 +01:00
|
|
|
local i
|
|
|
|
for i in $(__git_refs "$1"); do
|
|
|
|
echo "$i:$i"
|
2006-09-28 11:31:25 +02:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
completion: support completing fully qualified non-fast-forward refspecs
After 'git fetch <remote> <TAB>' our completion script offers refspecs
that will fetch to a local branch with the same name as in the remote
repository, e.g. 'master:master'. This also completes
non-fast-forward refspecs, i.e. after a '+' prefix like
'+master:master', and fully qualified refspecs, e.g.
'refs/heads/master:refs/heads/master'. However, it does not complete
non-fast-forward fully qualified refspecs (or fully qualified refspecs
following any other prefix, e.g. '--option=', though currently no git
command supports such an option, but third party git commands might).
These refspecs are listed by the __git_refs2() function, which is just
a thin wrapper iterating over __git_refs()'s output, turning each
listed ref into a refspec. Now, it's certainly possible to modify
__git_refs2() and its callsite to pass an extra parameter containing
only the ref part of the current word to be completed (to follow suit
of the previous commit) to deal with prefixed fully qualified refspecs
as well. Unfortunately, keeping the current behavior unchanged in the
"no extra parameter" case brings in a bit of subtlety, which makes the
resulting code ugly and compelled me to write a 8-line long comment in
the proof of concept. Not good. However, since the callsite has to
be modified for proper functioning anyway, we might as well leave
__git_refs2() as is and introduce a new helper function without
backwards compatibility concerns.
Add the new function __git_complete_fetch_refspecs() that has all the
necessary parameters to do the right thing in all cases mentioned
above, including non-fast-forward fully qualified refspecs. This new
function can also easier benefit from optimizations coming later in
this patch series.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:14 +01:00
|
|
|
# Completes refspecs for fetching from a remote repository.
|
|
|
|
# 1: The remote repository.
|
|
|
|
# 2: A prefix to be added to each listed refspec (optional).
|
|
|
|
# 3: The ref to be completed as a refspec instead of the current word to be
|
|
|
|
# completed (optional)
|
|
|
|
# 4: A suffix to be appended to each listed refspec instead of the default
|
|
|
|
# space (optional).
|
|
|
|
__git_complete_fetch_refspecs ()
|
|
|
|
{
|
|
|
|
local i remote="$1" pfx="${2-}" cur_="${3-$cur}" sfx="${4- }"
|
|
|
|
|
2017-03-23 16:29:23 +01:00
|
|
|
__gitcomp_direct "$(
|
completion: support completing fully qualified non-fast-forward refspecs
After 'git fetch <remote> <TAB>' our completion script offers refspecs
that will fetch to a local branch with the same name as in the remote
repository, e.g. 'master:master'. This also completes
non-fast-forward refspecs, i.e. after a '+' prefix like
'+master:master', and fully qualified refspecs, e.g.
'refs/heads/master:refs/heads/master'. However, it does not complete
non-fast-forward fully qualified refspecs (or fully qualified refspecs
following any other prefix, e.g. '--option=', though currently no git
command supports such an option, but third party git commands might).
These refspecs are listed by the __git_refs2() function, which is just
a thin wrapper iterating over __git_refs()'s output, turning each
listed ref into a refspec. Now, it's certainly possible to modify
__git_refs2() and its callsite to pass an extra parameter containing
only the ref part of the current word to be completed (to follow suit
of the previous commit) to deal with prefixed fully qualified refspecs
as well. Unfortunately, keeping the current behavior unchanged in the
"no extra parameter" case brings in a bit of subtlety, which makes the
resulting code ugly and compelled me to write a 8-line long comment in
the proof of concept. Not good. However, since the callsite has to
be modified for proper functioning anyway, we might as well leave
__git_refs2() as is and introduce a new helper function without
backwards compatibility concerns.
Add the new function __git_complete_fetch_refspecs() that has all the
necessary parameters to do the right thing in all cases mentioned
above, including non-fast-forward fully qualified refspecs. This new
function can also easier benefit from optimizations coming later in
this patch series.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:14 +01:00
|
|
|
for i in $(__git_refs "$remote" "" "" "$cur_") ; do
|
2017-03-23 16:29:23 +01:00
|
|
|
echo "$pfx$i:$i$sfx"
|
completion: support completing fully qualified non-fast-forward refspecs
After 'git fetch <remote> <TAB>' our completion script offers refspecs
that will fetch to a local branch with the same name as in the remote
repository, e.g. 'master:master'. This also completes
non-fast-forward refspecs, i.e. after a '+' prefix like
'+master:master', and fully qualified refspecs, e.g.
'refs/heads/master:refs/heads/master'. However, it does not complete
non-fast-forward fully qualified refspecs (or fully qualified refspecs
following any other prefix, e.g. '--option=', though currently no git
command supports such an option, but third party git commands might).
These refspecs are listed by the __git_refs2() function, which is just
a thin wrapper iterating over __git_refs()'s output, turning each
listed ref into a refspec. Now, it's certainly possible to modify
__git_refs2() and its callsite to pass an extra parameter containing
only the ref part of the current word to be completed (to follow suit
of the previous commit) to deal with prefixed fully qualified refspecs
as well. Unfortunately, keeping the current behavior unchanged in the
"no extra parameter" case brings in a bit of subtlety, which makes the
resulting code ugly and compelled me to write a 8-line long comment in
the proof of concept. Not good. However, since the callsite has to
be modified for proper functioning anyway, we might as well leave
__git_refs2() as is and introduce a new helper function without
backwards compatibility concerns.
Add the new function __git_complete_fetch_refspecs() that has all the
necessary parameters to do the right thing in all cases mentioned
above, including non-fast-forward fully qualified refspecs. This new
function can also easier benefit from optimizations coming later in
this patch series.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:14 +01:00
|
|
|
done
|
2017-03-23 16:29:23 +01:00
|
|
|
)"
|
completion: support completing fully qualified non-fast-forward refspecs
After 'git fetch <remote> <TAB>' our completion script offers refspecs
that will fetch to a local branch with the same name as in the remote
repository, e.g. 'master:master'. This also completes
non-fast-forward refspecs, i.e. after a '+' prefix like
'+master:master', and fully qualified refspecs, e.g.
'refs/heads/master:refs/heads/master'. However, it does not complete
non-fast-forward fully qualified refspecs (or fully qualified refspecs
following any other prefix, e.g. '--option=', though currently no git
command supports such an option, but third party git commands might).
These refspecs are listed by the __git_refs2() function, which is just
a thin wrapper iterating over __git_refs()'s output, turning each
listed ref into a refspec. Now, it's certainly possible to modify
__git_refs2() and its callsite to pass an extra parameter containing
only the ref part of the current word to be completed (to follow suit
of the previous commit) to deal with prefixed fully qualified refspecs
as well. Unfortunately, keeping the current behavior unchanged in the
"no extra parameter" case brings in a bit of subtlety, which makes the
resulting code ugly and compelled me to write a 8-line long comment in
the proof of concept. Not good. However, since the callsite has to
be modified for proper functioning anyway, we might as well leave
__git_refs2() as is and introduce a new helper function without
backwards compatibility concerns.
Add the new function __git_complete_fetch_refspecs() that has all the
necessary parameters to do the right thing in all cases mentioned
above, including non-fast-forward fully qualified refspecs. This new
function can also easier benefit from optimizations coming later in
this patch series.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:14 +01:00
|
|
|
}
|
|
|
|
|
2009-01-15 17:02:23 +01:00
|
|
|
# __git_refs_remotes requires 1 argument (to pass to ls-remote)
|
2006-11-27 10:44:47 +01:00
|
|
|
__git_refs_remotes ()
|
|
|
|
{
|
2011-10-08 16:54:41 +02:00
|
|
|
local i hash
|
2017-02-03 03:48:26 +01:00
|
|
|
__git ls-remote "$1" 'refs/heads/*' | \
|
2011-12-21 16:54:14 +01:00
|
|
|
while read -r hash i; do
|
2011-10-08 16:54:41 +02:00
|
|
|
echo "$i:refs/remotes/$1/${i#refs/heads/}"
|
2006-11-27 10:44:47 +01:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
__git_remotes ()
|
|
|
|
{
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
test -d "$__git_repo_path/remotes" && ls -1 "$__git_repo_path/remotes"
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
__git remote
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2017-02-03 03:48:18 +01:00
|
|
|
# Returns true if $1 matches the name of a configured remote, false otherwise.
|
|
|
|
__git_is_configured_remote ()
|
|
|
|
{
|
|
|
|
local remote
|
|
|
|
for remote in $(__git_remotes); do
|
|
|
|
if [ "$remote" = "$1" ]; then
|
|
|
|
return 0
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
return 1
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2009-11-18 01:49:10 +01:00
|
|
|
__git_list_merge_strategies ()
|
2006-11-27 09:40:47 +01:00
|
|
|
{
|
2018-01-26 02:31:42 +01:00
|
|
|
LANG=C LC_ALL=C git merge -s help 2>&1 |
|
2008-08-20 23:13:42 +02:00
|
|
|
sed -n -e '/[Aa]vailable strategies are: /,/^$/{
|
|
|
|
s/\.$//
|
|
|
|
s/.*://
|
|
|
|
s/^[ ]*//
|
|
|
|
s/[ ]*$//
|
2006-11-27 09:40:47 +01:00
|
|
|
p
|
2008-08-20 23:13:42 +02:00
|
|
|
}'
|
2006-11-27 09:40:47 +01:00
|
|
|
}
|
2009-11-18 01:49:10 +01:00
|
|
|
|
|
|
|
__git_merge_strategies=
|
|
|
|
# 'git merge -s help' (and thus detection of the merge strategy
|
|
|
|
# list) fails, unfortunately, if run outside of any git working
|
|
|
|
# tree. __git_merge_strategies is set to the empty string in
|
|
|
|
# that case, and the detection will be repeated the next time it
|
|
|
|
# is needed.
|
|
|
|
__git_compute_merge_strategies ()
|
|
|
|
{
|
2012-02-02 20:26:15 +01:00
|
|
|
test -n "$__git_merge_strategies" ||
|
|
|
|
__git_merge_strategies=$(__git_list_merge_strategies)
|
2009-11-18 01:49:10 +01:00
|
|
|
}
|
2006-11-27 09:40:47 +01:00
|
|
|
|
2019-02-16 12:24:41 +01:00
|
|
|
__git_merge_strategy_options="ours theirs subtree subtree= patience
|
|
|
|
histogram diff-algorithm= ignore-space-change ignore-all-space
|
|
|
|
ignore-space-at-eol renormalize no-renormalize no-renames
|
|
|
|
find-renames find-renames= rename-threshold="
|
|
|
|
|
bash: complete 'git diff ...branc<TAB>'
While doing a final sanity check before merging a topic Bsomething, it
is a good idea to review what damage Bsomething branch would make, by
running:
$ git diff ...Bsomething
Unfortunately, our completion script for 'git diff' doesn't offer
anything after '...'. This is because 'git diff's completion function
invokes __git_complete_file() for non-option arguments to complete the
'<tree>:<path>' extended SHA-1 notation, but this helper function
doesn't support refs after '...' or '..'. Completion of refs after
'...' or '..' is supported by the __git_complete_revlist() helper
function, but that doesn't support '<tree>:<path>'.
To support both '...<ref>' and '<tree>:<path>' notations for 'git
diff', this patch, instead of adding yet another helper function,
joins __git_complete_file() and __git_complete_revlist() into the new
common function __git_complete_revlist_file(). The old helper
functions __git_complete_file() and __git_complete_revlist() are
changed to be a direct wrapper around the new
__git_complete_revlist_file(), because they might be used in
user-supplied completion scripts and we don't want to break them.
This change will cause some wrong suggestions for other commands which
use __git_complete_file() ('git diff' and friends) or
__git_complete_revlist() ('git log' and friends), e.g. 'git diff
...master:Doc<TAB>' and 'git log master:Doc<TAB>' will complete the
path to 'Documentation/', although neither commands make any sense.
However, both of these were actively wrong to begin with as soon as
the user entered the ':', so there is no real harm done.
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-10 19:12:29 +01:00
|
|
|
__git_complete_revlist_file ()
|
2006-09-28 11:31:25 +02:00
|
|
|
{
|
completion: treat results of git ls-tree as file paths
Let's say there are files named 'foo bar.txt', and 'abc def/test.txt' in
repository. When following commands trigger a completion:
git show HEAD:fo<Tab>
git show HEAD:ab<Tab>
The completion results in bash/zsh:
git show HEAD:foo bar.txt
git show HEAD:abc def/
Where the both of them have an unescaped space in paths, so they'll be
misread by git. All entries of git ls-tree either a filename or a
directory, so __gitcomp_file() is proper rather than __gitcomp_nl().
Note the commit f12785a3, which handles quoted paths properly. Like this
case, we should dequote $cur_ for ?*:* case. For example, let's say
there is untracked directory 'abc deg', then trigger a completion:
git show HEAD:abc\ de<Tab>
git show HEAD:'abc de<Tab>
git show HEAD:"abc de<Tab>
should uniquely complete 'abc def', but bash completes 'abc def' and
'abc deg' instead. In zsh, triggering a completion:
git show HEAD:abc\ def/<Tab>
should complete 'test.txt', but nothing comes. The both problems will be
resolved by dequoting paths.
__git_complete_revlist_file() passes arguments to __gitcomp_nl() where
the first one is a list something like:
abc def/Z
foo bar.txt Z
where Z is the mark of the EOL.
- The trailing space of blob in __git ls-tree | sed.
It makes the completion results become:
git show HEAD:foo\ bar.txt\ <CURSOR>
So git will try to find a file named 'foo bar.txt ' instead.
- The trailing slash of tree in __git ls-tree | sed.
It makes the completion results on zsh become:
git show HEAD:abc\ def/ <CURSOR>
So that the last space on command like should be removed on zsh to
complete filenames under 'abc def/'.
Signed-off-by: Chayoung You <yousbe@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-01 15:05:09 +01:00
|
|
|
local dequoted_word pfx ls ref cur_="$cur"
|
2011-04-28 18:01:51 +02:00
|
|
|
case "$cur_" in
|
bash: complete 'git diff ...branc<TAB>'
While doing a final sanity check before merging a topic Bsomething, it
is a good idea to review what damage Bsomething branch would make, by
running:
$ git diff ...Bsomething
Unfortunately, our completion script for 'git diff' doesn't offer
anything after '...'. This is because 'git diff's completion function
invokes __git_complete_file() for non-option arguments to complete the
'<tree>:<path>' extended SHA-1 notation, but this helper function
doesn't support refs after '...' or '..'. Completion of refs after
'...' or '..' is supported by the __git_complete_revlist() helper
function, but that doesn't support '<tree>:<path>'.
To support both '...<ref>' and '<tree>:<path>' notations for 'git
diff', this patch, instead of adding yet another helper function,
joins __git_complete_file() and __git_complete_revlist() into the new
common function __git_complete_revlist_file(). The old helper
functions __git_complete_file() and __git_complete_revlist() are
changed to be a direct wrapper around the new
__git_complete_revlist_file(), because they might be used in
user-supplied completion scripts and we don't want to break them.
This change will cause some wrong suggestions for other commands which
use __git_complete_file() ('git diff' and friends) or
__git_complete_revlist() ('git log' and friends), e.g. 'git diff
...master:Doc<TAB>' and 'git log master:Doc<TAB>' will complete the
path to 'Documentation/', although neither commands make any sense.
However, both of these were actively wrong to begin with as soon as
the user entered the ':', so there is no real harm done.
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-10 19:12:29 +01:00
|
|
|
*..?*:*)
|
|
|
|
return
|
|
|
|
;;
|
2006-09-28 11:31:25 +02:00
|
|
|
?*:*)
|
2011-04-28 18:01:51 +02:00
|
|
|
ref="${cur_%%:*}"
|
|
|
|
cur_="${cur_#*:}"
|
completion: treat results of git ls-tree as file paths
Let's say there are files named 'foo bar.txt', and 'abc def/test.txt' in
repository. When following commands trigger a completion:
git show HEAD:fo<Tab>
git show HEAD:ab<Tab>
The completion results in bash/zsh:
git show HEAD:foo bar.txt
git show HEAD:abc def/
Where the both of them have an unescaped space in paths, so they'll be
misread by git. All entries of git ls-tree either a filename or a
directory, so __gitcomp_file() is proper rather than __gitcomp_nl().
Note the commit f12785a3, which handles quoted paths properly. Like this
case, we should dequote $cur_ for ?*:* case. For example, let's say
there is untracked directory 'abc deg', then trigger a completion:
git show HEAD:abc\ de<Tab>
git show HEAD:'abc de<Tab>
git show HEAD:"abc de<Tab>
should uniquely complete 'abc def', but bash completes 'abc def' and
'abc deg' instead. In zsh, triggering a completion:
git show HEAD:abc\ def/<Tab>
should complete 'test.txt', but nothing comes. The both problems will be
resolved by dequoting paths.
__git_complete_revlist_file() passes arguments to __gitcomp_nl() where
the first one is a list something like:
abc def/Z
foo bar.txt Z
where Z is the mark of the EOL.
- The trailing space of blob in __git ls-tree | sed.
It makes the completion results become:
git show HEAD:foo\ bar.txt\ <CURSOR>
So git will try to find a file named 'foo bar.txt ' instead.
- The trailing slash of tree in __git ls-tree | sed.
It makes the completion results on zsh become:
git show HEAD:abc\ def/ <CURSOR>
So that the last space on command like should be removed on zsh to
complete filenames under 'abc def/'.
Signed-off-by: Chayoung You <yousbe@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-01 15:05:09 +01:00
|
|
|
|
|
|
|
__git_dequote "$cur_"
|
|
|
|
|
|
|
|
case "$dequoted_word" in
|
2006-09-28 11:31:25 +02:00
|
|
|
?*/*)
|
completion: treat results of git ls-tree as file paths
Let's say there are files named 'foo bar.txt', and 'abc def/test.txt' in
repository. When following commands trigger a completion:
git show HEAD:fo<Tab>
git show HEAD:ab<Tab>
The completion results in bash/zsh:
git show HEAD:foo bar.txt
git show HEAD:abc def/
Where the both of them have an unescaped space in paths, so they'll be
misread by git. All entries of git ls-tree either a filename or a
directory, so __gitcomp_file() is proper rather than __gitcomp_nl().
Note the commit f12785a3, which handles quoted paths properly. Like this
case, we should dequote $cur_ for ?*:* case. For example, let's say
there is untracked directory 'abc deg', then trigger a completion:
git show HEAD:abc\ de<Tab>
git show HEAD:'abc de<Tab>
git show HEAD:"abc de<Tab>
should uniquely complete 'abc def', but bash completes 'abc def' and
'abc deg' instead. In zsh, triggering a completion:
git show HEAD:abc\ def/<Tab>
should complete 'test.txt', but nothing comes. The both problems will be
resolved by dequoting paths.
__git_complete_revlist_file() passes arguments to __gitcomp_nl() where
the first one is a list something like:
abc def/Z
foo bar.txt Z
where Z is the mark of the EOL.
- The trailing space of blob in __git ls-tree | sed.
It makes the completion results become:
git show HEAD:foo\ bar.txt\ <CURSOR>
So git will try to find a file named 'foo bar.txt ' instead.
- The trailing slash of tree in __git ls-tree | sed.
It makes the completion results on zsh become:
git show HEAD:abc\ def/ <CURSOR>
So that the last space on command like should be removed on zsh to
complete filenames under 'abc def/'.
Signed-off-by: Chayoung You <yousbe@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-01 15:05:09 +01:00
|
|
|
pfx="${dequoted_word%/*}"
|
|
|
|
cur_="${dequoted_word##*/}"
|
2006-09-28 11:31:25 +02:00
|
|
|
ls="$ref:$pfx"
|
|
|
|
pfx="$pfx/"
|
|
|
|
;;
|
|
|
|
*)
|
completion: treat results of git ls-tree as file paths
Let's say there are files named 'foo bar.txt', and 'abc def/test.txt' in
repository. When following commands trigger a completion:
git show HEAD:fo<Tab>
git show HEAD:ab<Tab>
The completion results in bash/zsh:
git show HEAD:foo bar.txt
git show HEAD:abc def/
Where the both of them have an unescaped space in paths, so they'll be
misread by git. All entries of git ls-tree either a filename or a
directory, so __gitcomp_file() is proper rather than __gitcomp_nl().
Note the commit f12785a3, which handles quoted paths properly. Like this
case, we should dequote $cur_ for ?*:* case. For example, let's say
there is untracked directory 'abc deg', then trigger a completion:
git show HEAD:abc\ de<Tab>
git show HEAD:'abc de<Tab>
git show HEAD:"abc de<Tab>
should uniquely complete 'abc def', but bash completes 'abc def' and
'abc deg' instead. In zsh, triggering a completion:
git show HEAD:abc\ def/<Tab>
should complete 'test.txt', but nothing comes. The both problems will be
resolved by dequoting paths.
__git_complete_revlist_file() passes arguments to __gitcomp_nl() where
the first one is a list something like:
abc def/Z
foo bar.txt Z
where Z is the mark of the EOL.
- The trailing space of blob in __git ls-tree | sed.
It makes the completion results become:
git show HEAD:foo\ bar.txt\ <CURSOR>
So git will try to find a file named 'foo bar.txt ' instead.
- The trailing slash of tree in __git ls-tree | sed.
It makes the completion results on zsh become:
git show HEAD:abc\ def/ <CURSOR>
So that the last space on command like should be removed on zsh to
complete filenames under 'abc def/'.
Signed-off-by: Chayoung You <yousbe@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-01 15:05:09 +01:00
|
|
|
cur_="$dequoted_word"
|
2006-09-28 11:31:25 +02:00
|
|
|
ls="$ref"
|
|
|
|
;;
|
2011-03-10 19:12:28 +01:00
|
|
|
esac
|
2008-07-15 07:52:04 +02:00
|
|
|
|
|
|
|
case "$COMP_WORDBREAKS" in
|
|
|
|
*:*) : great ;;
|
|
|
|
*) pfx="$ref:$pfx" ;;
|
|
|
|
esac
|
|
|
|
|
completion: treat results of git ls-tree as file paths
Let's say there are files named 'foo bar.txt', and 'abc def/test.txt' in
repository. When following commands trigger a completion:
git show HEAD:fo<Tab>
git show HEAD:ab<Tab>
The completion results in bash/zsh:
git show HEAD:foo bar.txt
git show HEAD:abc def/
Where the both of them have an unescaped space in paths, so they'll be
misread by git. All entries of git ls-tree either a filename or a
directory, so __gitcomp_file() is proper rather than __gitcomp_nl().
Note the commit f12785a3, which handles quoted paths properly. Like this
case, we should dequote $cur_ for ?*:* case. For example, let's say
there is untracked directory 'abc deg', then trigger a completion:
git show HEAD:abc\ de<Tab>
git show HEAD:'abc de<Tab>
git show HEAD:"abc de<Tab>
should uniquely complete 'abc def', but bash completes 'abc def' and
'abc deg' instead. In zsh, triggering a completion:
git show HEAD:abc\ def/<Tab>
should complete 'test.txt', but nothing comes. The both problems will be
resolved by dequoting paths.
__git_complete_revlist_file() passes arguments to __gitcomp_nl() where
the first one is a list something like:
abc def/Z
foo bar.txt Z
where Z is the mark of the EOL.
- The trailing space of blob in __git ls-tree | sed.
It makes the completion results become:
git show HEAD:foo\ bar.txt\ <CURSOR>
So git will try to find a file named 'foo bar.txt ' instead.
- The trailing slash of tree in __git ls-tree | sed.
It makes the completion results on zsh become:
git show HEAD:abc\ def/ <CURSOR>
So that the last space on command like should be removed on zsh to
complete filenames under 'abc def/'.
Signed-off-by: Chayoung You <yousbe@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-01-01 15:05:09 +01:00
|
|
|
__gitcomp_file "$(__git ls-tree "$ls" \
|
|
|
|
| sed 's/^.* //
|
|
|
|
s/$//')" \
|
|
|
|
"$pfx" "$cur_"
|
2006-09-28 11:31:25 +02:00
|
|
|
;;
|
2006-11-27 09:41:43 +01:00
|
|
|
*...*)
|
2011-04-28 18:01:51 +02:00
|
|
|
pfx="${cur_%...*}..."
|
|
|
|
cur_="${cur_#*...}"
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --pfx="$pfx" --cur="$cur_"
|
2006-11-27 09:41:43 +01:00
|
|
|
;;
|
|
|
|
*..*)
|
2011-04-28 18:01:51 +02:00
|
|
|
pfx="${cur_%..*}.."
|
|
|
|
cur_="${cur_#*..}"
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --pfx="$pfx" --cur="$cur_"
|
2007-02-04 08:38:43 +01:00
|
|
|
;;
|
2006-11-27 09:41:43 +01:00
|
|
|
*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2006-11-27 09:41:43 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
bash: complete 'git diff ...branc<TAB>'
While doing a final sanity check before merging a topic Bsomething, it
is a good idea to review what damage Bsomething branch would make, by
running:
$ git diff ...Bsomething
Unfortunately, our completion script for 'git diff' doesn't offer
anything after '...'. This is because 'git diff's completion function
invokes __git_complete_file() for non-option arguments to complete the
'<tree>:<path>' extended SHA-1 notation, but this helper function
doesn't support refs after '...' or '..'. Completion of refs after
'...' or '..' is supported by the __git_complete_revlist() helper
function, but that doesn't support '<tree>:<path>'.
To support both '...<ref>' and '<tree>:<path>' notations for 'git
diff', this patch, instead of adding yet another helper function,
joins __git_complete_file() and __git_complete_revlist() into the new
common function __git_complete_revlist_file(). The old helper
functions __git_complete_file() and __git_complete_revlist() are
changed to be a direct wrapper around the new
__git_complete_revlist_file(), because they might be used in
user-supplied completion scripts and we don't want to break them.
This change will cause some wrong suggestions for other commands which
use __git_complete_file() ('git diff' and friends) or
__git_complete_revlist() ('git log' and friends), e.g. 'git diff
...master:Doc<TAB>' and 'git log master:Doc<TAB>' will complete the
path to 'Documentation/', although neither commands make any sense.
However, both of these were actively wrong to begin with as soon as
the user entered the ':', so there is no real harm done.
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-10 19:12:29 +01:00
|
|
|
__git_complete_file ()
|
|
|
|
{
|
|
|
|
__git_complete_revlist_file
|
|
|
|
}
|
|
|
|
|
|
|
|
__git_complete_revlist ()
|
|
|
|
{
|
|
|
|
__git_complete_revlist_file
|
|
|
|
}
|
|
|
|
|
2009-03-06 05:39:31 +01:00
|
|
|
__git_complete_remote_or_refspec ()
|
|
|
|
{
|
2011-04-28 18:01:51 +02:00
|
|
|
local cur_="$cur" cmd="${words[1]}"
|
2009-03-06 05:39:33 +01:00
|
|
|
local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0
|
2012-02-22 09:58:10 +01:00
|
|
|
if [ "$cmd" = "remote" ]; then
|
2012-02-22 09:58:11 +01:00
|
|
|
((c++))
|
2012-02-22 09:58:10 +01:00
|
|
|
fi
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
while [ $c -lt $cword ]; do
|
|
|
|
i="${words[c]}"
|
2009-03-06 05:39:31 +01:00
|
|
|
case "$i" in
|
2009-12-12 11:21:46 +01:00
|
|
|
--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;;
|
completion: expand "push --delete <remote> <ref>" for refs on that <remote>
Change the completion of "push --delete <remote> <ref>" to complete
refs on that <remote>, not all refs.
Before this cloning git.git and doing "git push --delete origin
p<TAB>" will complete nothing, since a fresh clone of git.git will
have no "pu" branch, whereas origin/p<TAB> will uselessly complete
origin/pu, but fully qualified references aren't accepted by
"--delete".
Now p<TAB> will complete as "pu". The completion of giving --delete
later, e.g. "git push origin --delete p<TAB>" remains unchanged, this
is a bug, but is a general existing limitation of the bash completion,
and not how git-push is documented, so I'm not fixing that case, but
adding a failing TODO test for it.
The testing code was supplied by SZEDER Gábor in
<20170421122832.24617-1-szeder.dev@gmail.com> with minor setup
modifications on my part.
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Reviewed-by: SZEDER Gábor <szeder.dev@gmail.com>
Test-code-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-04-22 19:55:04 +02:00
|
|
|
-d|--delete) [ "$cmd" = "push" ] && lhs=0 ;;
|
2009-12-12 11:21:46 +01:00
|
|
|
--all)
|
|
|
|
case "$cmd" in
|
|
|
|
push) no_complete_refspec=1 ;;
|
|
|
|
fetch)
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
*) ;;
|
|
|
|
esac
|
|
|
|
;;
|
2018-09-20 18:37:33 +02:00
|
|
|
--multiple) no_complete_refspec=1; break ;;
|
2009-03-06 05:39:31 +01:00
|
|
|
-*) ;;
|
|
|
|
*) remote="$i"; break ;;
|
|
|
|
esac
|
2012-02-22 09:58:11 +01:00
|
|
|
((c++))
|
2009-03-06 05:39:31 +01:00
|
|
|
done
|
|
|
|
if [ -z "$remote" ]; then
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_remotes)"
|
2009-03-06 05:39:31 +01:00
|
|
|
return
|
|
|
|
fi
|
2009-03-06 05:39:33 +01:00
|
|
|
if [ $no_complete_refspec = 1 ]; then
|
|
|
|
return
|
|
|
|
fi
|
2009-03-06 05:39:31 +01:00
|
|
|
[ "$remote" = "." ] && remote=
|
2011-04-28 18:01:51 +02:00
|
|
|
case "$cur_" in
|
2009-03-06 05:39:31 +01:00
|
|
|
*:*)
|
|
|
|
case "$COMP_WORDBREAKS" in
|
|
|
|
*:*) : great ;;
|
2011-04-28 18:01:51 +02:00
|
|
|
*) pfx="${cur_%%:*}:" ;;
|
2009-03-06 05:39:31 +01:00
|
|
|
esac
|
2011-04-28 18:01:51 +02:00
|
|
|
cur_="${cur_#*:}"
|
2009-03-06 05:39:31 +01:00
|
|
|
lhs=0
|
|
|
|
;;
|
|
|
|
+*)
|
|
|
|
pfx="+"
|
2011-04-28 18:01:51 +02:00
|
|
|
cur_="${cur_#+}"
|
2009-03-06 05:39:31 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
case "$cmd" in
|
|
|
|
fetch)
|
|
|
|
if [ $lhs = 1 ]; then
|
completion: support completing fully qualified non-fast-forward refspecs
After 'git fetch <remote> <TAB>' our completion script offers refspecs
that will fetch to a local branch with the same name as in the remote
repository, e.g. 'master:master'. This also completes
non-fast-forward refspecs, i.e. after a '+' prefix like
'+master:master', and fully qualified refspecs, e.g.
'refs/heads/master:refs/heads/master'. However, it does not complete
non-fast-forward fully qualified refspecs (or fully qualified refspecs
following any other prefix, e.g. '--option=', though currently no git
command supports such an option, but third party git commands might).
These refspecs are listed by the __git_refs2() function, which is just
a thin wrapper iterating over __git_refs()'s output, turning each
listed ref into a refspec. Now, it's certainly possible to modify
__git_refs2() and its callsite to pass an extra parameter containing
only the ref part of the current word to be completed (to follow suit
of the previous commit) to deal with prefixed fully qualified refspecs
as well. Unfortunately, keeping the current behavior unchanged in the
"no extra parameter" case brings in a bit of subtlety, which makes the
resulting code ugly and compelled me to write a 8-line long comment in
the proof of concept. Not good. However, since the callsite has to
be modified for proper functioning anyway, we might as well leave
__git_refs2() as is and introduce a new helper function without
backwards compatibility concerns.
Add the new function __git_complete_fetch_refspecs() that has all the
necessary parameters to do the right thing in all cases mentioned
above, including non-fast-forward fully qualified refspecs. This new
function can also easier benefit from optimizations coming later in
this patch series.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:14 +01:00
|
|
|
__git_complete_fetch_refspecs "$remote" "$pfx" "$cur_"
|
2009-03-06 05:39:31 +01:00
|
|
|
else
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --pfx="$pfx" --cur="$cur_"
|
2009-03-06 05:39:31 +01:00
|
|
|
fi
|
|
|
|
;;
|
2012-02-22 09:58:10 +01:00
|
|
|
pull|remote)
|
2009-03-06 05:39:31 +01:00
|
|
|
if [ $lhs = 1 ]; then
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_"
|
2009-03-06 05:39:31 +01:00
|
|
|
else
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --pfx="$pfx" --cur="$cur_"
|
2009-03-06 05:39:31 +01:00
|
|
|
fi
|
|
|
|
;;
|
|
|
|
push)
|
|
|
|
if [ $lhs = 1 ]; then
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --pfx="$pfx" --cur="$cur_"
|
2009-03-06 05:39:31 +01:00
|
|
|
else
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_"
|
2009-03-06 05:39:31 +01:00
|
|
|
fi
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2009-03-06 17:30:44 +01:00
|
|
|
__git_complete_strategy ()
|
|
|
|
{
|
2009-11-18 01:49:10 +01:00
|
|
|
__git_compute_merge_strategies
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
case "$prev" in
|
2009-03-06 17:30:44 +01:00
|
|
|
-s|--strategy)
|
2009-11-18 01:49:10 +01:00
|
|
|
__gitcomp "$__git_merge_strategies"
|
2009-03-06 17:30:44 +01:00
|
|
|
return 0
|
2019-02-16 12:24:41 +01:00
|
|
|
;;
|
|
|
|
-X)
|
|
|
|
__gitcomp "$__git_merge_strategy_options"
|
|
|
|
return 0
|
|
|
|
;;
|
2009-03-06 17:30:44 +01:00
|
|
|
esac
|
|
|
|
case "$cur" in
|
|
|
|
--strategy=*)
|
2009-11-18 01:49:10 +01:00
|
|
|
__gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}"
|
2009-03-06 17:30:44 +01:00
|
|
|
return 0
|
|
|
|
;;
|
2019-02-16 12:24:41 +01:00
|
|
|
--strategy-option=*)
|
|
|
|
__gitcomp "$__git_merge_strategy_options" "" "${cur##--strategy-option=}"
|
|
|
|
return 0
|
|
|
|
;;
|
2009-03-06 17:30:44 +01:00
|
|
|
esac
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
2009-11-18 01:49:10 +01:00
|
|
|
__git_all_commands=
|
|
|
|
__git_compute_all_commands ()
|
|
|
|
{
|
2012-02-02 20:26:15 +01:00
|
|
|
test -n "$__git_all_commands" ||
|
2019-03-20 19:03:29 +01:00
|
|
|
__git_all_commands=$(__git --list-cmds=main,others,alias,nohelpers)
|
2009-11-18 01:49:10 +01:00
|
|
|
}
|
2006-11-27 09:41:01 +01:00
|
|
|
|
2015-05-10 14:50:17 +02:00
|
|
|
# Lists all set config variables starting with the given section prefix,
|
|
|
|
# with the prefix removed.
|
|
|
|
__git_get_config_variables ()
|
2010-10-11 00:06:22 +02:00
|
|
|
{
|
2015-05-10 14:50:17 +02:00
|
|
|
local section="$1" i IFS=$'\n'
|
2017-02-03 03:48:26 +01:00
|
|
|
for i in $(__git config --name-only --get-regexp "^$section\..*"); do
|
2015-08-10 11:46:07 +02:00
|
|
|
echo "${i#$section.}"
|
2010-10-11 00:06:22 +02:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
__git_pretty_aliases ()
|
|
|
|
{
|
2015-05-10 14:50:17 +02:00
|
|
|
__git_get_config_variables "pretty"
|
2010-10-11 00:06:22 +02:00
|
|
|
}
|
|
|
|
|
2009-01-15 17:02:23 +01:00
|
|
|
# __git_aliased_command requires 1 argument
|
2006-10-28 14:12:20 +02:00
|
|
|
__git_aliased_command ()
|
|
|
|
{
|
2017-02-03 03:48:26 +01:00
|
|
|
local word cmdline=$(__git config --get "alias.$1")
|
2006-10-28 14:12:20 +02:00
|
|
|
for word in $cmdline; do
|
bash: improve aliased command recognition
To support completion for aliases, the completion script tries to
figure out which git command is invoked by an alias. Its
implementation in __git_aliased_command() is rather straightforward:
it returns the first word from the alias. For simple aliases starting
with the git command (e.g. alias.last = cat-file commit HEAD) this
gives the right results. Unfortunately, it does not work with shell
command aliases, which can get rather complex, as illustrated by one
of Junio's aliases:
[alias]
lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -"
In this case the current implementation returns "!sh" as the aliased
git command, which is obviosly wrong.
The full parsing of a shell command alias like that in the completion
code is clearly unfeasible. However, we can easily improve on aliased
command recognition by eleminating stuff that is definitely not a git
command: shell commands (anything starting with '!'), command line
options (anything starting with '-'), environment variables (anything
with a '=' in it), and git itself. This way the above alias would be
handled correctly, and the completion script would correctly recognize
"log" as the aliased git command.
Of course, this solution is not perfect either, and could be fooled
easily. It's not hard to construct an alias, in which a word does not
match any of these filter patterns, but is still not a git command
(e.g. by setting an environment variable to a value which contains
spaces). It may even return false positives, when the output of a git
command is piped into an other git command, and the second gets the
command line options via $@, but options for the first one are
offered. However, the following patches will enable the user to
supply custom completion scripts for aliases, which can be used to
remedy these problematic cases.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:57 +01:00
|
|
|
case "$word" in
|
2010-02-23 22:03:00 +01:00
|
|
|
\!gitk|gitk)
|
|
|
|
echo "gitk"
|
2006-10-28 14:12:20 +02:00
|
|
|
return
|
2010-02-23 22:03:00 +01:00
|
|
|
;;
|
bash: improve aliased command recognition
To support completion for aliases, the completion script tries to
figure out which git command is invoked by an alias. Its
implementation in __git_aliased_command() is rather straightforward:
it returns the first word from the alias. For simple aliases starting
with the git command (e.g. alias.last = cat-file commit HEAD) this
gives the right results. Unfortunately, it does not work with shell
command aliases, which can get rather complex, as illustrated by one
of Junio's aliases:
[alias]
lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -"
In this case the current implementation returns "!sh" as the aliased
git command, which is obviosly wrong.
The full parsing of a shell command alias like that in the completion
code is clearly unfeasible. However, we can easily improve on aliased
command recognition by eleminating stuff that is definitely not a git
command: shell commands (anything starting with '!'), command line
options (anything starting with '-'), environment variables (anything
with a '=' in it), and git itself. This way the above alias would be
handled correctly, and the completion script would correctly recognize
"log" as the aliased git command.
Of course, this solution is not perfect either, and could be fooled
easily. It's not hard to construct an alias, in which a word does not
match any of these filter patterns, but is still not a git command
(e.g. by setting an environment variable to a value which contains
spaces). It may even return false positives, when the output of a git
command is piped into an other git command, and the second gets the
command line options via $@, but options for the first one are
offered. However, the following patches will enable the user to
supply custom completion scripts for aliases, which can be used to
remedy these problematic cases.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:57 +01:00
|
|
|
\!*) : shell command alias ;;
|
|
|
|
-*) : option ;;
|
|
|
|
*=*) : setting env ;;
|
|
|
|
git) : git itself ;;
|
2014-06-12 20:49:29 +02:00
|
|
|
\(\)) : skip parens of shell function definition ;;
|
|
|
|
{) : skip start of shell helper function ;;
|
|
|
|
:) : skip null command ;;
|
|
|
|
\'*) : skip opening quote after sh -c ;;
|
bash: improve aliased command recognition
To support completion for aliases, the completion script tries to
figure out which git command is invoked by an alias. Its
implementation in __git_aliased_command() is rather straightforward:
it returns the first word from the alias. For simple aliases starting
with the git command (e.g. alias.last = cat-file commit HEAD) this
gives the right results. Unfortunately, it does not work with shell
command aliases, which can get rather complex, as illustrated by one
of Junio's aliases:
[alias]
lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -"
In this case the current implementation returns "!sh" as the aliased
git command, which is obviosly wrong.
The full parsing of a shell command alias like that in the completion
code is clearly unfeasible. However, we can easily improve on aliased
command recognition by eleminating stuff that is definitely not a git
command: shell commands (anything starting with '!'), command line
options (anything starting with '-'), environment variables (anything
with a '=' in it), and git itself. This way the above alias would be
handled correctly, and the completion script would correctly recognize
"log" as the aliased git command.
Of course, this solution is not perfect either, and could be fooled
easily. It's not hard to construct an alias, in which a word does not
match any of these filter patterns, but is still not a git command
(e.g. by setting an environment variable to a value which contains
spaces). It may even return false positives, when the output of a git
command is piped into an other git command, and the second gets the
command line options via $@, but options for the first one are
offered. However, the following patches will enable the user to
supply custom completion scripts for aliases, which can be used to
remedy these problematic cases.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:57 +01:00
|
|
|
*)
|
|
|
|
echo "$word"
|
2006-10-28 14:12:20 +02:00
|
|
|
return
|
bash: improve aliased command recognition
To support completion for aliases, the completion script tries to
figure out which git command is invoked by an alias. Its
implementation in __git_aliased_command() is rather straightforward:
it returns the first word from the alias. For simple aliases starting
with the git command (e.g. alias.last = cat-file commit HEAD) this
gives the right results. Unfortunately, it does not work with shell
command aliases, which can get rather complex, as illustrated by one
of Junio's aliases:
[alias]
lgm = "!sh -c 'GIT_NOTES_REF=refs/notes/amlog git log \"$@\" || :' -"
In this case the current implementation returns "!sh" as the aliased
git command, which is obviosly wrong.
The full parsing of a shell command alias like that in the completion
code is clearly unfeasible. However, we can easily improve on aliased
command recognition by eleminating stuff that is definitely not a git
command: shell commands (anything starting with '!'), command line
options (anything starting with '-'), environment variables (anything
with a '=' in it), and git itself. This way the above alias would be
handled correctly, and the completion script would correctly recognize
"log" as the aliased git command.
Of course, this solution is not perfect either, and could be fooled
easily. It's not hard to construct an alias, in which a word does not
match any of these filter patterns, but is still not a git command
(e.g. by setting an environment variable to a value which contains
spaces). It may even return false positives, when the output of a git
command is piped into an other git command, and the second gets the
command line options via $@, but options for the first one are
offered. However, the following patches will enable the user to
supply custom completion scripts for aliases, which can be used to
remedy these problematic cases.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:57 +01:00
|
|
|
esac
|
2006-10-28 14:12:20 +02:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2009-09-15 12:21:43 +02:00
|
|
|
# __git_find_on_cmdline requires 1 argument
|
|
|
|
__git_find_on_cmdline ()
|
2008-03-10 16:02:23 +01:00
|
|
|
{
|
2011-04-28 18:01:52 +02:00
|
|
|
local word subcommand c=1
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
while [ $c -lt $cword ]; do
|
|
|
|
word="${words[c]}"
|
2008-03-10 16:02:23 +01:00
|
|
|
for subcommand in $1; do
|
|
|
|
if [ "$subcommand" = "$word" ]; then
|
|
|
|
echo "$subcommand"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
done
|
2012-02-22 09:58:11 +01:00
|
|
|
((c++))
|
2008-03-10 16:02:23 +01:00
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2016-06-10 12:12:05 +02:00
|
|
|
# Echo the value of an option set on the command line or config
|
|
|
|
#
|
|
|
|
# $1: short option name
|
|
|
|
# $2: long option name including =
|
|
|
|
# $3: list of possible values
|
|
|
|
# $4: config string (optional)
|
|
|
|
#
|
|
|
|
# example:
|
|
|
|
# result="$(__git_get_option_value "-d" "--do-something=" \
|
|
|
|
# "yes no" "core.doSomething")"
|
|
|
|
#
|
|
|
|
# result is then either empty (no option set) or "yes" or "no"
|
|
|
|
#
|
|
|
|
# __git_get_option_value requires 3 arguments
|
|
|
|
__git_get_option_value ()
|
|
|
|
{
|
|
|
|
local c short_opt long_opt val
|
|
|
|
local result= values config_key word
|
|
|
|
|
|
|
|
short_opt="$1"
|
|
|
|
long_opt="$2"
|
|
|
|
values="$3"
|
|
|
|
config_key="$4"
|
|
|
|
|
|
|
|
((c = $cword - 1))
|
|
|
|
while [ $c -ge 0 ]; do
|
|
|
|
word="${words[c]}"
|
|
|
|
for val in $values; do
|
|
|
|
if [ "$short_opt$val" = "$word" ] ||
|
|
|
|
[ "$long_opt$val" = "$word" ]; then
|
|
|
|
result="$val"
|
|
|
|
break 2
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
((c--))
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ -n "$config_key" ] && [ -z "$result" ]; then
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
result="$(__git config "$config_key")"
|
2016-06-10 12:12:05 +02:00
|
|
|
fi
|
|
|
|
|
|
|
|
echo "$result"
|
|
|
|
}
|
|
|
|
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
__git_has_doubledash ()
|
|
|
|
{
|
2011-04-28 18:01:52 +02:00
|
|
|
local c=1
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
while [ $c -lt $cword ]; do
|
|
|
|
if [ "--" = "${words[c]}" ]; then
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
return 0
|
|
|
|
fi
|
2012-02-22 09:58:11 +01:00
|
|
|
((c++))
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
done
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
# Try to count non option arguments passed on the command line for the
|
|
|
|
# specified git command.
|
|
|
|
# When options are used, it is necessary to use the special -- option to
|
|
|
|
# tell the implementation were non option arguments begin.
|
|
|
|
# XXX this can not be improved, since options can appear everywhere, as
|
|
|
|
# an example:
|
|
|
|
# git mv x -n y
|
|
|
|
#
|
|
|
|
# __git_count_arguments requires 1 argument: the git command executed.
|
|
|
|
__git_count_arguments ()
|
|
|
|
{
|
|
|
|
local word i c=0
|
|
|
|
|
|
|
|
# Skip "git" (first argument)
|
|
|
|
for ((i=1; i < ${#words[@]}; i++)); do
|
|
|
|
word="${words[i]}"
|
|
|
|
|
|
|
|
case "$word" in
|
|
|
|
--)
|
|
|
|
# Good; we can assume that the following are only non
|
|
|
|
# option arguments.
|
|
|
|
((c = 0))
|
|
|
|
;;
|
|
|
|
"$1")
|
|
|
|
# Skip the specified git command and discard git
|
|
|
|
# main options
|
|
|
|
((c = 0))
|
|
|
|
;;
|
|
|
|
?*)
|
|
|
|
((c++))
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
printf "%d" $c
|
|
|
|
}
|
|
|
|
|
2008-08-14 19:12:54 +02:00
|
|
|
__git_whitespacelist="nowarn warn error error-all fix"
|
2019-02-16 12:24:41 +01:00
|
|
|
__git_patchformat="mbox stgit stgit-series hg mboxrd"
|
2018-03-14 20:01:06 +01:00
|
|
|
__git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch"
|
2006-11-27 21:12:03 +01:00
|
|
|
|
|
|
|
_git_am ()
|
|
|
|
{
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
if [ -d "$__git_repo_path"/rebase-apply ]; then
|
2018-02-09 12:01:45 +01:00
|
|
|
__gitcomp "$__git_am_inprogress_options"
|
2006-11-27 21:12:03 +01:00
|
|
|
return
|
|
|
|
fi
|
|
|
|
case "$cur" in
|
|
|
|
--whitespace=*)
|
2007-02-04 08:38:43 +01:00
|
|
|
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
|
2006-11-27 21:12:03 +01:00
|
|
|
return
|
|
|
|
;;
|
2019-02-16 12:24:41 +01:00
|
|
|
--patch-format=*)
|
|
|
|
__gitcomp "$__git_patchformat" "" "${cur##--patch-format=}"
|
|
|
|
return
|
|
|
|
;;
|
2006-11-27 21:12:03 +01:00
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin am "" \
|
2018-02-09 12:01:45 +01:00
|
|
|
"$__git_am_inprogress_options"
|
2006-11-27 21:12:03 +01:00
|
|
|
return
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
_git_apply ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--whitespace=*)
|
2007-02-04 08:38:43 +01:00
|
|
|
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
|
2006-11-27 21:12:03 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
--*)
|
2018-02-09 12:01:46 +01:00
|
|
|
__gitcomp_builtin apply
|
2006-11-27 21:12:03 +01:00
|
|
|
return
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2007-02-04 08:38:23 +01:00
|
|
|
_git_add ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
2019-02-16 12:24:41 +01:00
|
|
|
--chmod=*)
|
|
|
|
__gitcomp "+x -x" "" "${cur##--chmod=}"
|
|
|
|
return
|
|
|
|
;;
|
2007-02-04 08:38:23 +01:00
|
|
|
--*)
|
2018-02-09 12:01:44 +01:00
|
|
|
__gitcomp_builtin add
|
2007-02-04 08:38:23 +01:00
|
|
|
return
|
|
|
|
esac
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
2017-02-03 12:01:55 +01:00
|
|
|
local complete_opt="--others --modified --directory --no-empty-directory"
|
|
|
|
if test -n "$(__git_find_on_cmdline "-u --update")"
|
|
|
|
then
|
|
|
|
complete_opt="--modified"
|
|
|
|
fi
|
|
|
|
__git_complete_index_file "$complete_opt"
|
2007-02-04 08:38:23 +01:00
|
|
|
}
|
|
|
|
|
2008-08-05 07:50:36 +02:00
|
|
|
_git_archive ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--format=*)
|
|
|
|
__gitcomp "$(git archive --list)" "" "${cur##--format=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--remote=*)
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_remotes)" "" "${cur##--remote=}"
|
2008-08-05 07:50:36 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
--*)
|
|
|
|
__gitcomp "
|
|
|
|
--format= --list --verbose
|
2017-02-03 12:01:59 +01:00
|
|
|
--prefix= --remote= --exec= --output
|
2008-08-05 07:50:36 +02:00
|
|
|
"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
__git_complete_file
|
|
|
|
}
|
|
|
|
|
2007-02-05 21:44:37 +01:00
|
|
|
_git_bisect ()
|
|
|
|
{
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2008-07-02 15:29:50 +02:00
|
|
|
local subcommands="start bad good skip reset visualize replay log run"
|
2009-09-15 12:21:43 +02:00
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
2008-03-10 16:02:23 +01:00
|
|
|
if [ -z "$subcommand" ]; then
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
if [ -f "$__git_repo_path"/BISECT_START ]; then
|
2010-10-10 23:39:34 +02:00
|
|
|
__gitcomp "$subcommands"
|
|
|
|
else
|
|
|
|
__gitcomp "replay start"
|
|
|
|
fi
|
2007-02-05 21:44:37 +01:00
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
2008-03-10 16:02:23 +01:00
|
|
|
case "$subcommand" in
|
2010-10-10 23:39:33 +02:00
|
|
|
bad|good|reset|skip|start)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2007-02-05 21:44:37 +01:00
|
|
|
;;
|
|
|
|
*)
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2019-02-16 12:24:41 +01:00
|
|
|
__git_ref_fieldlist="refname objecttype objectsize objectname upstream push HEAD symref"
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_branch ()
|
|
|
|
{
|
2011-04-28 18:01:52 +02:00
|
|
|
local i c=1 only_local_ref="n" has_r="n"
|
2008-03-04 19:00:59 +01:00
|
|
|
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
while [ $c -lt $cword ]; do
|
|
|
|
i="${words[c]}"
|
2008-03-04 19:00:59 +01:00
|
|
|
case "$i" in
|
2016-08-09 11:34:44 +02:00
|
|
|
-d|--delete|-m|--move) only_local_ref="y" ;;
|
|
|
|
-r|--remotes) has_r="y" ;;
|
2008-03-04 19:00:59 +01:00
|
|
|
esac
|
2012-02-22 09:58:11 +01:00
|
|
|
((c++))
|
2008-03-04 19:00:59 +01:00
|
|
|
done
|
|
|
|
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
case "$cur" in
|
2012-09-11 13:58:30 +02:00
|
|
|
--set-upstream-to=*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --cur="${cur##--set-upstream-to=}"
|
2012-09-11 13:58:30 +02:00
|
|
|
;;
|
2008-03-04 19:00:58 +01:00
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin branch
|
2008-03-04 19:00:58 +01:00
|
|
|
;;
|
2008-03-04 19:00:59 +01:00
|
|
|
*)
|
|
|
|
if [ $only_local_ref = "y" -a $has_r = "n" ]; then
|
2017-03-23 16:29:24 +01:00
|
|
|
__gitcomp_direct "$(__git_heads "" "$cur" " ")"
|
2008-03-04 19:00:59 +01:00
|
|
|
else
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2008-03-04 19:00:59 +01:00
|
|
|
fi
|
|
|
|
;;
|
2008-03-04 19:00:58 +01:00
|
|
|
esac
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2007-08-12 20:46:12 +02:00
|
|
|
_git_bundle ()
|
|
|
|
{
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
local cmd="${words[2]}"
|
|
|
|
case "$cword" in
|
2008-11-27 14:35:38 +01:00
|
|
|
2)
|
2007-08-12 20:46:12 +02:00
|
|
|
__gitcomp "create list-heads verify unbundle"
|
|
|
|
;;
|
2008-11-27 14:35:38 +01:00
|
|
|
3)
|
2007-08-12 20:46:12 +02:00
|
|
|
# looking for a file
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
case "$cmd" in
|
|
|
|
create)
|
|
|
|
__git_complete_revlist
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_checkout ()
|
|
|
|
{
|
2008-07-23 13:49:22 +02:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2009-09-24 14:23:15 +02:00
|
|
|
case "$cur" in
|
|
|
|
--conflict=*)
|
|
|
|
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
|
|
|
|
;;
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin checkout
|
2009-09-24 14:23:15 +02:00
|
|
|
;;
|
|
|
|
*)
|
2010-10-12 23:38:12 +02:00
|
|
|
# check if --track, --no-track, or --no-guess was specified
|
|
|
|
# if so, disable DWIM mode
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
local flags="--track --no-track --no-guess" track_opt="--track"
|
completion: optionally disable checkout DWIM
When we complete branch names for "git checkout", we also
complete remote branch names that could trigger the DWIM
behavior. Depending on your workflow and project, this can
be either convenient or annoying.
For instance, my clone of gitster.git contains 74 local
"jk/*" branches, but origin contains another 147. When I
want to checkout a local branch but can't quite remember the
name, tab completion shows me 251 entries. And worse, for a
topic that has been picked up for pu, the upstream branch
name is likely to be similar to mine, leading to a high
probability that I pick the wrong one and accidentally
create a new branch.
This patch adds a way for the user to tell the completion
code not to include DWIM suggestions for checkout. This can
already be done by typing:
git checkout --no-guess jk/<TAB>
but that's rather cumbersome. The downside, of course, is
that you no longer get completion support when you _do_ want
to invoke the DWIM behavior. But depending on your workflow,
that may not be a big loss (for instance, in git.git I am
much more likely to want to detach, so I'd type "git
checkout origin/jk/<TAB>" anyway).
Signed-off-by: Jeff King <peff@peff.net>
Reviewed-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-04-21 22:27:06 +02:00
|
|
|
if [ "$GIT_COMPLETION_CHECKOUT_NO_GUESS" = "1" ] ||
|
|
|
|
[ -n "$(__git_find_on_cmdline "$flags")" ]; then
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
track_opt=''
|
2010-10-12 23:38:12 +02:00
|
|
|
fi
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs $track_opt
|
2009-09-24 14:23:15 +02:00
|
|
|
;;
|
|
|
|
esac
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2018-02-09 12:01:49 +01:00
|
|
|
__git_cherry_pick_inprogress_options="--continue --quit --abort"
|
|
|
|
|
2006-11-27 09:41:59 +01:00
|
|
|
_git_cherry_pick ()
|
|
|
|
{
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
if [ -f "$__git_repo_path"/CHERRY_PICK_HEAD ]; then
|
2018-02-09 12:01:49 +01:00
|
|
|
__gitcomp "$__git_cherry_pick_inprogress_options"
|
2013-04-10 11:08:18 +02:00
|
|
|
return
|
|
|
|
fi
|
2019-02-16 12:24:41 +01:00
|
|
|
|
|
|
|
__git_complete_strategy && return
|
|
|
|
|
2006-11-27 09:41:59 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:01:49 +01:00
|
|
|
__gitcomp_builtin cherry-pick "" \
|
|
|
|
"$__git_cherry_pick_inprogress_options"
|
2006-11-27 09:41:59 +01:00
|
|
|
;;
|
|
|
|
*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2006-11-27 09:41:59 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2008-08-05 07:50:32 +02:00
|
|
|
_git_clean ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:01:50 +01:00
|
|
|
__gitcomp_builtin clean
|
2008-08-05 07:50:32 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
|
|
|
# XXX should we check for -x option ?
|
2013-09-18 19:06:08 +02:00
|
|
|
__git_complete_index_file "--others --directory"
|
2008-08-05 07:50:32 +02:00
|
|
|
}
|
|
|
|
|
2008-08-05 07:50:31 +02:00
|
|
|
_git_clone ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin clone
|
2008-08-05 07:50:31 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2016-06-10 12:12:04 +02:00
|
|
|
__git_untracked_file_modes="all no normal"
|
|
|
|
|
2006-11-28 18:12:08 +01:00
|
|
|
_git_commit ()
|
|
|
|
{
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
case "$prev" in
|
|
|
|
-c|-C)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
|
2006-11-28 18:12:08 +01:00
|
|
|
case "$cur" in
|
2009-12-05 01:51:41 +01:00
|
|
|
--cleanup=*)
|
2015-06-08 03:43:31 +02:00
|
|
|
__gitcomp "default scissors strip verbatim whitespace
|
2009-12-05 01:51:41 +01:00
|
|
|
" "" "${cur##--cleanup=}"
|
|
|
|
return
|
|
|
|
;;
|
2011-10-06 20:40:30 +02:00
|
|
|
--reuse-message=*|--reedit-message=*|\
|
|
|
|
--fixup=*|--squash=*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --cur="${cur#*=}"
|
2009-12-05 01:51:41 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
--untracked-files=*)
|
2016-06-10 12:12:04 +02:00
|
|
|
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
|
2009-12-05 01:51:41 +01:00
|
|
|
return
|
|
|
|
;;
|
2006-11-28 18:12:08 +01:00
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin commit
|
2006-11-28 18:12:08 +01:00
|
|
|
return
|
|
|
|
esac
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
if __git rev-parse --verify --quiet HEAD >/dev/null; then
|
2013-04-27 22:10:03 +02:00
|
|
|
__git_complete_index_file "--committable"
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
else
|
|
|
|
# This is the first commit
|
|
|
|
__git_complete_index_file "--cached"
|
|
|
|
fi
|
2006-11-28 18:12:08 +01:00
|
|
|
}
|
|
|
|
|
2007-08-23 07:42:11 +02:00
|
|
|
_git_describe ()
|
|
|
|
{
|
2008-07-26 12:26:56 +02:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:01:54 +01:00
|
|
|
__gitcomp_builtin describe
|
2008-07-26 12:26:56 +02:00
|
|
|
return
|
|
|
|
esac
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2007-08-23 07:42:11 +02:00
|
|
|
}
|
|
|
|
|
2013-01-16 08:51:58 +01:00
|
|
|
__git_diff_algorithms="myers minimal patience histogram"
|
|
|
|
|
2016-12-04 15:41:27 +01:00
|
|
|
__git_diff_submodule_formats="diff log short"
|
2016-08-09 20:34:46 +02:00
|
|
|
|
2009-01-19 22:18:00 +01:00
|
|
|
__git_diff_common_options="--stat --numstat --shortstat --summary
|
2007-11-23 02:11:35 +01:00
|
|
|
--patch-with-stat --name-only --name-status --color
|
|
|
|
--no-color --color-words --no-renames --check
|
2008-08-22 19:25:06 +02:00
|
|
|
--full-index --binary --abbrev --diff-filter=
|
2017-10-26 08:32:27 +02:00
|
|
|
--find-copies-harder --ignore-cr-at-eol
|
2007-11-23 02:11:35 +01:00
|
|
|
--text --ignore-space-at-eol --ignore-space-change
|
2014-09-03 17:00:41 +02:00
|
|
|
--ignore-all-space --ignore-blank-lines --exit-code
|
|
|
|
--quiet --ext-diff --no-ext-diff
|
2008-04-06 18:56:08 +02:00
|
|
|
--no-prefix --src-prefix= --dst-prefix=
|
2008-12-28 19:45:32 +01:00
|
|
|
--inter-hunk-context=
|
2013-01-12 17:02:13 +01:00
|
|
|
--patience --histogram --minimal
|
2016-01-20 18:34:58 +01:00
|
|
|
--raw --word-diff --word-diff-regex=
|
2009-10-07 10:48:51 +02:00
|
|
|
--dirstat --dirstat= --dirstat-by-file
|
|
|
|
--dirstat-by-file= --cumulative
|
2013-01-16 08:51:58 +01:00
|
|
|
--diff-algorithm=
|
2018-02-09 12:01:55 +01:00
|
|
|
--submodule --submodule= --ignore-submodules
|
2009-01-19 22:18:00 +01:00
|
|
|
"
|
|
|
|
|
|
|
|
_git_diff ()
|
|
|
|
{
|
|
|
|
__git_has_doubledash && return
|
|
|
|
|
|
|
|
case "$cur" in
|
2013-01-16 08:51:58 +01:00
|
|
|
--diff-algorithm=*)
|
|
|
|
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
|
|
|
|
return
|
|
|
|
;;
|
2016-08-09 20:34:46 +02:00
|
|
|
--submodule=*)
|
|
|
|
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
|
|
|
|
return
|
|
|
|
;;
|
2009-01-19 22:18:00 +01:00
|
|
|
--*)
|
2009-03-22 00:29:27 +01:00
|
|
|
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex
|
2010-09-23 14:33:51 +02:00
|
|
|
--base --ours --theirs --no-index
|
2009-01-19 22:18:00 +01:00
|
|
|
$__git_diff_common_options
|
2008-04-06 18:56:08 +02:00
|
|
|
"
|
2007-11-23 02:11:35 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
bash: complete 'git diff ...branc<TAB>'
While doing a final sanity check before merging a topic Bsomething, it
is a good idea to review what damage Bsomething branch would make, by
running:
$ git diff ...Bsomething
Unfortunately, our completion script for 'git diff' doesn't offer
anything after '...'. This is because 'git diff's completion function
invokes __git_complete_file() for non-option arguments to complete the
'<tree>:<path>' extended SHA-1 notation, but this helper function
doesn't support refs after '...' or '..'. Completion of refs after
'...' or '..' is supported by the __git_complete_revlist() helper
function, but that doesn't support '<tree>:<path>'.
To support both '...<ref>' and '<tree>:<path>' notations for 'git
diff', this patch, instead of adding yet another helper function,
joins __git_complete_file() and __git_complete_revlist() into the new
common function __git_complete_revlist_file(). The old helper
functions __git_complete_file() and __git_complete_revlist() are
changed to be a direct wrapper around the new
__git_complete_revlist_file(), because they might be used in
user-supplied completion scripts and we don't want to break them.
This change will cause some wrong suggestions for other commands which
use __git_complete_file() ('git diff' and friends) or
__git_complete_revlist() ('git log' and friends), e.g. 'git diff
...master:Doc<TAB>' and 'git log master:Doc<TAB>' will complete the
path to 'Documentation/', although neither commands make any sense.
However, both of these were actively wrong to begin with as soon as
the user entered the ':', so there is no real harm done.
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-03-10 19:12:29 +01:00
|
|
|
__git_complete_revlist_file
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2013-10-13 00:29:35 +02:00
|
|
|
__git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff
|
2019-04-04 09:34:39 +02:00
|
|
|
tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc
|
|
|
|
codecompare smerge
|
2009-04-06 10:31:27 +02:00
|
|
|
"
|
|
|
|
|
|
|
|
_git_difftool ()
|
|
|
|
{
|
2009-10-28 10:45:38 +01:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2009-04-06 10:31:27 +02:00
|
|
|
case "$cur" in
|
|
|
|
--tool=*)
|
|
|
|
__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--*)
|
2018-02-09 12:01:55 +01:00
|
|
|
__gitcomp_builtin difftool "$__git_diff_common_options
|
|
|
|
--base --cached --ours --theirs
|
|
|
|
--pickaxe-all --pickaxe-regex
|
|
|
|
--relative --staged
|
|
|
|
"
|
2009-04-06 10:31:27 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2013-06-02 16:03:41 +02:00
|
|
|
__git_complete_revlist_file
|
2009-04-06 10:31:27 +02:00
|
|
|
}
|
|
|
|
|
2014-02-09 15:35:31 +01:00
|
|
|
__git_fetch_recurse_submodules="yes on-demand no"
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_fetch ()
|
|
|
|
{
|
2009-03-06 05:39:33 +01:00
|
|
|
case "$cur" in
|
2014-02-09 15:35:31 +01:00
|
|
|
--recurse-submodules=*)
|
|
|
|
__gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}"
|
|
|
|
return
|
|
|
|
;;
|
2019-02-16 12:24:41 +01:00
|
|
|
--filter=*)
|
2019-05-29 14:44:32 +02:00
|
|
|
__gitcomp "blob:none blob:limit= sparse:oid=" "" "${cur##--filter=}"
|
2019-02-16 12:24:41 +01:00
|
|
|
return
|
|
|
|
;;
|
2009-03-06 05:39:33 +01:00
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin fetch
|
2009-03-06 05:39:33 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2009-03-06 05:39:31 +01:00
|
|
|
__git_complete_remote_or_refspec
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2018-11-03 07:03:18 +01:00
|
|
|
__git_format_patch_extra_options="
|
|
|
|
--full-index --not --all --no-prefix --src-prefix=
|
|
|
|
--dst-prefix= --notes
|
2012-10-16 02:21:50 +02:00
|
|
|
"
|
|
|
|
|
2006-11-27 09:41:43 +01:00
|
|
|
_git_format_patch ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
2009-03-23 11:26:51 +01:00
|
|
|
--thread=*)
|
|
|
|
__gitcomp "
|
|
|
|
deep shallow
|
|
|
|
" "" "${cur##--thread=}"
|
|
|
|
return
|
|
|
|
;;
|
2006-11-27 09:41:43 +01:00
|
|
|
--*)
|
2018-11-03 07:03:18 +01:00
|
|
|
__gitcomp_builtin format-patch "$__git_format_patch_extra_options"
|
2006-11-27 09:41:43 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
__git_complete_revlist
|
|
|
|
}
|
|
|
|
|
2009-03-22 19:49:07 +01:00
|
|
|
_git_fsck ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin fsck
|
2009-03-22 19:49:07 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2010-02-23 22:03:00 +01:00
|
|
|
_git_gitk ()
|
|
|
|
{
|
|
|
|
_gitk
|
|
|
|
}
|
|
|
|
|
2017-03-23 16:38:37 +01:00
|
|
|
# Lists matching symbol names from a tag (as in ctags) file.
|
|
|
|
# 1: List symbol names matching this word.
|
|
|
|
# 2: The tag file to list symbol names from.
|
|
|
|
# 3: A prefix to be added to each listed symbol name (optional).
|
|
|
|
# 4: A suffix to be appended to each listed symbol name (optional).
|
|
|
|
__git_match_ctag () {
|
|
|
|
awk -v pfx="${3-}" -v sfx="${4-}" "
|
|
|
|
/^${1//\//\\/}/ { print pfx \$1 sfx }
|
|
|
|
" "$2"
|
2011-10-21 19:30:21 +02:00
|
|
|
}
|
|
|
|
|
2017-03-23 16:38:38 +01:00
|
|
|
# Complete symbol names from a tag file.
|
|
|
|
# Usage: __git_complete_symbol [<option>]...
|
|
|
|
# --tags=<file>: The tag file to list symbol names from instead of the
|
|
|
|
# default "tags".
|
|
|
|
# --pfx=<prefix>: A prefix to be added to each symbol name.
|
|
|
|
# --cur=<word>: The current symbol name to be completed. Defaults to
|
|
|
|
# the current word to be completed.
|
|
|
|
# --sfx=<suffix>: A suffix to be appended to each symbol name instead
|
|
|
|
# of the default space.
|
|
|
|
__git_complete_symbol () {
|
|
|
|
local tags=tags pfx="" cur_="${cur-}" sfx=" "
|
|
|
|
|
|
|
|
while test $# != 0; do
|
|
|
|
case "$1" in
|
|
|
|
--tags=*) tags="${1##--tags=}" ;;
|
|
|
|
--pfx=*) pfx="${1##--pfx=}" ;;
|
|
|
|
--cur=*) cur_="${1##--cur=}" ;;
|
|
|
|
--sfx=*) sfx="${1##--sfx=}" ;;
|
|
|
|
*) return 1 ;;
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
if test -r "$tags"; then
|
|
|
|
__gitcomp_direct "$(__git_match_ctag "$cur_" "$tags" "$pfx" "$sfx")"
|
|
|
|
fi
|
2011-10-21 19:30:21 +02:00
|
|
|
}
|
|
|
|
|
2008-08-02 02:56:33 +02:00
|
|
|
_git_grep ()
|
|
|
|
{
|
|
|
|
__git_has_doubledash && return
|
|
|
|
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:01:59 +01:00
|
|
|
__gitcomp_builtin grep
|
2008-08-02 02:56:33 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2009-10-12 11:00:09 +02:00
|
|
|
|
2011-10-21 19:30:21 +02:00
|
|
|
case "$cword,$prev" in
|
|
|
|
2,*|*,-*)
|
2017-03-23 16:38:38 +01:00
|
|
|
__git_complete_symbol && return
|
2011-10-21 19:30:21 +02:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2008-08-02 02:56:33 +02:00
|
|
|
}
|
|
|
|
|
2008-07-24 02:07:23 +02:00
|
|
|
_git_help ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:00 +01:00
|
|
|
__gitcomp_builtin help
|
2008-07-24 02:07:23 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2018-05-20 20:40:08 +02:00
|
|
|
if test -n "$GIT_TESTING_ALL_COMMAND_LIST"
|
|
|
|
then
|
2019-03-20 19:03:29 +01:00
|
|
|
__gitcomp "$GIT_TESTING_ALL_COMMAND_LIST $(__git --list-cmds=alias,list-guide) gitk"
|
2018-05-20 20:40:08 +02:00
|
|
|
else
|
2019-03-20 19:03:29 +01:00
|
|
|
__gitcomp "$(__git --list-cmds=main,nohelpers,alias,list-guide) gitk"
|
2018-05-20 20:40:08 +02:00
|
|
|
fi
|
2008-07-24 02:07:23 +02:00
|
|
|
}
|
|
|
|
|
2008-08-05 07:50:33 +02:00
|
|
|
_git_init ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--shared=*)
|
|
|
|
__gitcomp "
|
|
|
|
false true umask group all world everybody
|
|
|
|
" "" "${cur##--shared=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--*)
|
2018-02-09 12:02:01 +01:00
|
|
|
__gitcomp_builtin init
|
2008-08-05 07:50:33 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2008-08-05 07:50:37 +02:00
|
|
|
_git_ls_files ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin ls-files
|
2008-08-05 07:50:37 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
|
|
|
# XXX ignore options like --modified and always suggest all cached
|
|
|
|
# files.
|
|
|
|
__git_complete_index_file "--cached"
|
2008-08-05 07:50:37 +02:00
|
|
|
}
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_ls_remote ()
|
|
|
|
{
|
2017-02-03 12:01:56 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:03 +01:00
|
|
|
__gitcomp_builtin ls-remote
|
2017-02-03 12:01:56 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_remotes)"
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
_git_ls_tree ()
|
|
|
|
{
|
2018-03-24 21:35:24 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
|
|
|
__gitcomp_builtin ls-tree
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
__git_complete_file
|
|
|
|
}
|
|
|
|
|
2009-02-16 17:34:56 +01:00
|
|
|
# Options that go well for log, shortlog and gitk
|
|
|
|
__git_log_common_options="
|
|
|
|
--not --all
|
|
|
|
--branches --tags --remotes
|
2009-07-13 17:11:45 +02:00
|
|
|
--first-parent --merges --no-merges
|
2009-02-16 17:34:56 +01:00
|
|
|
--max-count=
|
|
|
|
--max-age= --since= --after=
|
|
|
|
--min-age= --until= --before=
|
2011-03-23 10:38:51 +01:00
|
|
|
--min-parents= --max-parents=
|
|
|
|
--no-min-parents --no-max-parents
|
2009-02-16 17:34:56 +01:00
|
|
|
"
|
|
|
|
# Options that go well for log and gitk (not shortlog)
|
|
|
|
__git_log_gitk_options="
|
|
|
|
--dense --sparse --full-history
|
|
|
|
--simplify-merges --simplify-by-decoration
|
2011-04-14 19:53:13 +02:00
|
|
|
--left-right --notes --no-notes
|
2009-02-16 17:34:56 +01:00
|
|
|
"
|
|
|
|
# Options that go well for log and shortlog (not gitk)
|
|
|
|
__git_log_shortlog_options="
|
|
|
|
--author= --committer= --grep=
|
log: teach --invert-grep option
"git log --grep=<string>" shows only commits with messages that
match the given string, but sometimes it is useful to be able to
show only commits that do *not* have certain messages (e.g. "show
me ones that are not FIXUP commits").
Originally, we had the invert-grep flag in grep_opt, but because
"git grep --invert-grep" does not make sense except in conjunction
with "--files-with-matches", which is already covered by
"--files-without-matches", it was moved it to revisions structure.
To have the flag there expresses the function to the feature better.
When the newly inserted two tests run, the history would have commits
with messages "initial", "second", "third", "fourth", "fifth", "sixth"
and "Second", committed in this order. The commits that does not match
either "th" or "Sec" is "second" and "initial". For the case insensitive
case only "initial" matches.
Signed-off-by: Christoph Junghans <ottxor@gentoo.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-01-13 02:33:32 +01:00
|
|
|
--all-match --invert-grep
|
2009-02-16 17:34:56 +01:00
|
|
|
"
|
|
|
|
|
2019-02-16 12:24:41 +01:00
|
|
|
__git_log_pretty_formats="oneline short medium full fuller email raw format: mboxrd"
|
|
|
|
__git_log_date_formats="relative iso8601 iso8601-strict rfc2822 short local default raw unix format:"
|
2009-01-16 17:02:15 +01:00
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_log ()
|
|
|
|
{
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
__git_has_doubledash && return
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
|
2009-02-16 17:34:57 +01:00
|
|
|
local merge=""
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
if [ -f "$__git_repo_path/MERGE_HEAD" ]; then
|
2009-02-16 17:34:57 +01:00
|
|
|
merge="--merge"
|
|
|
|
fi
|
2017-03-23 16:38:39 +01:00
|
|
|
case "$prev,$cur" in
|
|
|
|
-L,:*:*)
|
|
|
|
return # fall back to Bash filename completion
|
|
|
|
;;
|
|
|
|
-L,:*)
|
|
|
|
__git_complete_symbol --cur="${cur#:}" --sfx=":"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
-G,*|-S,*)
|
|
|
|
__git_complete_symbol
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2006-11-27 09:42:18 +01:00
|
|
|
case "$cur" in
|
2011-10-08 03:09:34 +02:00
|
|
|
--pretty=*|--format=*)
|
2010-10-11 00:06:22 +02:00
|
|
|
__gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
|
2011-10-08 03:09:34 +02:00
|
|
|
" "" "${cur#*=}"
|
2009-02-24 14:33:29 +01:00
|
|
|
return
|
|
|
|
;;
|
2007-08-23 07:39:22 +02:00
|
|
|
--date=*)
|
2009-05-04 08:25:34 +02:00
|
|
|
__gitcomp "$__git_log_date_formats" "" "${cur##--date=}"
|
2007-08-23 07:39:22 +02:00
|
|
|
return
|
|
|
|
;;
|
2009-10-07 10:48:50 +02:00
|
|
|
--decorate=*)
|
2015-05-01 19:21:00 +02:00
|
|
|
__gitcomp "full short no" "" "${cur##--decorate=}"
|
2009-10-07 10:48:50 +02:00
|
|
|
return
|
|
|
|
;;
|
2016-08-09 20:34:46 +02:00
|
|
|
--diff-algorithm=*)
|
|
|
|
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--submodule=*)
|
|
|
|
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
|
|
|
|
return
|
|
|
|
;;
|
2006-11-27 09:42:18 +01:00
|
|
|
--*)
|
2007-02-04 08:38:43 +01:00
|
|
|
__gitcomp "
|
2009-02-16 17:34:56 +01:00
|
|
|
$__git_log_common_options
|
|
|
|
$__git_log_shortlog_options
|
|
|
|
$__git_log_gitk_options
|
2007-05-24 07:51:30 +02:00
|
|
|
--root --topo-order --date-order --reverse
|
2009-06-03 22:20:58 +02:00
|
|
|
--follow --full-diff
|
2006-11-27 09:42:18 +01:00
|
|
|
--abbrev-commit --abbrev=
|
2007-08-23 07:39:22 +02:00
|
|
|
--relative-date --date=
|
2009-02-24 14:33:29 +01:00
|
|
|
--pretty= --format= --oneline
|
2014-10-05 01:20:38 +02:00
|
|
|
--show-signature
|
2016-04-05 12:45:35 +02:00
|
|
|
--cherry-mark
|
2009-02-16 17:34:56 +01:00
|
|
|
--cherry-pick
|
2008-06-19 23:15:53 +02:00
|
|
|
--graph
|
2009-10-07 10:48:50 +02:00
|
|
|
--decorate --decorate=
|
2009-01-19 22:18:00 +01:00
|
|
|
--walk-reflogs
|
2009-02-16 17:34:56 +01:00
|
|
|
--parents --children
|
2009-02-16 17:34:57 +01:00
|
|
|
$merge
|
2009-01-19 22:18:00 +01:00
|
|
|
$__git_diff_common_options
|
2009-01-19 22:17:59 +01:00
|
|
|
--pickaxe-all --pickaxe-regex
|
2007-02-04 08:38:43 +01:00
|
|
|
"
|
2006-11-27 09:42:18 +01:00
|
|
|
return
|
|
|
|
;;
|
2017-03-23 16:38:39 +01:00
|
|
|
-L:*:*)
|
|
|
|
return # fall back to Bash filename completion
|
|
|
|
;;
|
|
|
|
-L:*)
|
|
|
|
__git_complete_symbol --cur="${cur#-L:}" --sfx=":"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
-G*)
|
|
|
|
__git_complete_symbol --pfx="-G" --cur="${cur#-G}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
-S*)
|
|
|
|
__git_complete_symbol --pfx="-S" --cur="${cur#-S}"
|
|
|
|
return
|
|
|
|
;;
|
2006-11-27 09:42:18 +01:00
|
|
|
esac
|
2006-11-27 09:41:43 +01:00
|
|
|
__git_complete_revlist
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2006-11-27 09:40:47 +01:00
|
|
|
_git_merge ()
|
|
|
|
{
|
2009-03-06 17:30:44 +01:00
|
|
|
__git_complete_strategy && return
|
|
|
|
|
2006-11-27 09:40:47 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin merge
|
2006-11-27 09:40:47 +01:00
|
|
|
return
|
|
|
|
esac
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2006-11-27 09:40:47 +01:00
|
|
|
}
|
|
|
|
|
2008-08-15 00:41:10 +02:00
|
|
|
_git_mergetool ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--tool=*)
|
2009-04-06 10:31:27 +02:00
|
|
|
__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}"
|
2008-08-15 00:41:10 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
--*)
|
2018-10-24 18:25:37 +02:00
|
|
|
__gitcomp "--tool= --prompt --no-prompt --gui --no-gui"
|
2008-08-15 00:41:10 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_merge_base ()
|
|
|
|
{
|
2014-01-11 15:27:12 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:05 +01:00
|
|
|
__gitcomp_builtin merge-base
|
2014-01-11 15:27:12 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2008-08-05 07:50:38 +02:00
|
|
|
_git_mv ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:06 +01:00
|
|
|
__gitcomp_builtin mv
|
2008-08-05 07:50:38 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
|
|
|
if [ $(__git_count_arguments "mv") -gt 0 ]; then
|
|
|
|
# We need to show both cached and untracked files (including
|
|
|
|
# empty directories) since this may not be the last argument.
|
|
|
|
__git_complete_index_file "--cached --others --directory"
|
|
|
|
else
|
|
|
|
__git_complete_index_file "--cached"
|
|
|
|
fi
|
2008-08-05 07:50:38 +02:00
|
|
|
}
|
|
|
|
|
2010-01-28 02:05:55 +01:00
|
|
|
_git_notes ()
|
|
|
|
{
|
2018-03-07 02:05:04 +01:00
|
|
|
local subcommands='add append copy edit get-ref list merge prune remove show'
|
2010-10-10 23:43:33 +02:00
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
2010-01-28 02:05:55 +01:00
|
|
|
|
2010-10-10 23:43:33 +02:00
|
|
|
case "$subcommand,$cur" in
|
|
|
|
,--*)
|
2018-02-09 12:02:08 +01:00
|
|
|
__gitcomp_builtin notes
|
2010-10-10 23:43:33 +02:00
|
|
|
;;
|
|
|
|
,*)
|
2012-04-15 21:44:17 +02:00
|
|
|
case "$prev" in
|
2010-10-10 23:43:33 +02:00
|
|
|
--ref)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2010-10-10 23:43:33 +02:00
|
|
|
;;
|
|
|
|
*)
|
|
|
|
__gitcomp "$subcommands --ref"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
;;
|
2018-03-07 02:05:03 +01:00
|
|
|
*,--reuse-message=*|*,--reedit-message=*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --cur="${cur#*=}"
|
2010-10-10 23:43:33 +02:00
|
|
|
;;
|
2018-03-07 02:05:02 +01:00
|
|
|
*,--*)
|
|
|
|
__gitcomp_builtin notes_$subcommand
|
2010-10-10 23:43:33 +02:00
|
|
|
;;
|
2018-03-07 02:05:04 +01:00
|
|
|
prune,*|get-ref,*)
|
2018-03-07 02:05:02 +01:00
|
|
|
# this command does not take a ref, do not complete it
|
2010-01-28 02:05:55 +01:00
|
|
|
;;
|
|
|
|
*)
|
2012-04-15 21:44:17 +02:00
|
|
|
case "$prev" in
|
2010-10-10 23:43:33 +02:00
|
|
|
-m|-F)
|
|
|
|
;;
|
|
|
|
*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2010-10-10 23:43:33 +02:00
|
|
|
;;
|
|
|
|
esac
|
2010-01-28 02:05:55 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_pull ()
|
|
|
|
{
|
2009-03-06 05:39:33 +01:00
|
|
|
__git_complete_strategy && return
|
|
|
|
|
|
|
|
case "$cur" in
|
2014-02-09 15:35:31 +01:00
|
|
|
--recurse-submodules=*)
|
|
|
|
__gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}"
|
|
|
|
return
|
|
|
|
;;
|
2009-03-06 05:39:33 +01:00
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin pull
|
2018-02-09 12:02:09 +01:00
|
|
|
|
2009-03-06 05:39:33 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2009-03-06 05:39:31 +01:00
|
|
|
__git_complete_remote_or_refspec
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2017-02-02 00:07:53 +01:00
|
|
|
__git_push_recurse_submodules="check on-demand only"
|
2014-02-09 15:35:31 +01:00
|
|
|
|
2014-07-22 20:24:58 +02:00
|
|
|
__git_complete_force_with_lease ()
|
|
|
|
{
|
|
|
|
local cur_=$1
|
|
|
|
|
|
|
|
case "$cur_" in
|
|
|
|
--*=)
|
|
|
|
;;
|
|
|
|
*:*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --cur="${cur_#*:}"
|
2014-07-22 20:24:58 +02:00
|
|
|
;;
|
|
|
|
*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs --cur="$cur_"
|
2014-07-22 20:24:58 +02:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2006-09-28 11:31:25 +02:00
|
|
|
_git_push ()
|
|
|
|
{
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
case "$prev" in
|
2009-03-06 05:39:33 +01:00
|
|
|
--repo)
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_remotes)"
|
2009-03-06 05:39:33 +01:00
|
|
|
return
|
2014-07-22 20:24:56 +02:00
|
|
|
;;
|
|
|
|
--recurse-submodules)
|
|
|
|
__gitcomp "$__git_push_recurse_submodules"
|
|
|
|
return
|
|
|
|
;;
|
2009-03-06 05:39:33 +01:00
|
|
|
esac
|
|
|
|
case "$cur" in
|
|
|
|
--repo=*)
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_remotes)" "" "${cur##--repo=}"
|
2009-03-06 05:39:33 +01:00
|
|
|
return
|
|
|
|
;;
|
2014-02-09 15:35:31 +01:00
|
|
|
--recurse-submodules=*)
|
|
|
|
__gitcomp "$__git_push_recurse_submodules" "" "${cur##--recurse-submodules=}"
|
|
|
|
return
|
|
|
|
;;
|
2014-07-22 20:24:58 +02:00
|
|
|
--force-with-lease=*)
|
|
|
|
__git_complete_force_with_lease "${cur##--force-with-lease=}"
|
|
|
|
return
|
|
|
|
;;
|
2009-03-06 05:39:33 +01:00
|
|
|
--*)
|
2018-02-09 12:02:10 +01:00
|
|
|
__gitcomp_builtin push
|
2009-03-06 05:39:33 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2009-03-06 05:39:31 +01:00
|
|
|
__git_complete_remote_or_refspec
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2018-08-13 13:33:27 +02:00
|
|
|
_git_range_diff ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
|
|
|
__gitcomp "
|
2018-08-13 13:33:30 +02:00
|
|
|
--creation-factor= --no-dual-color
|
2018-08-13 13:33:27 +02:00
|
|
|
$__git_diff_common_options
|
|
|
|
"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
__git_complete_revlist
|
|
|
|
}
|
|
|
|
|
2006-11-27 09:42:07 +01:00
|
|
|
_git_rebase ()
|
|
|
|
{
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
if [ -f "$__git_repo_path"/rebase-merge/interactive ]; then
|
2018-02-11 10:43:27 +01:00
|
|
|
__gitcomp "--continue --skip --abort --quit --edit-todo --show-current-patch"
|
2015-08-05 15:40:00 +02:00
|
|
|
return
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
elif [ -d "$__git_repo_path"/rebase-apply ] || \
|
|
|
|
[ -d "$__git_repo_path"/rebase-merge ]; then
|
2018-02-11 10:43:27 +01:00
|
|
|
__gitcomp "--continue --skip --abort --quit --show-current-patch"
|
2006-11-27 09:42:07 +01:00
|
|
|
return
|
|
|
|
fi
|
2009-03-06 17:30:44 +01:00
|
|
|
__git_complete_strategy && return
|
2006-11-27 09:42:07 +01:00
|
|
|
case "$cur" in
|
2009-10-17 11:33:38 +02:00
|
|
|
--whitespace=*)
|
|
|
|
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}"
|
|
|
|
return
|
|
|
|
;;
|
2006-11-27 09:42:07 +01:00
|
|
|
--*)
|
2009-10-17 11:33:38 +02:00
|
|
|
__gitcomp "
|
|
|
|
--onto --merge --strategy --interactive
|
rebase: introduce the --rebase-merges option
Once upon a time, this here developer thought: wouldn't it be nice if,
say, Git for Windows' patches on top of core Git could be represented as
a thicket of branches, and be rebased on top of core Git in order to
maintain a cherry-pick'able set of patch series?
The original attempt to answer this was: git rebase --preserve-merges.
However, that experiment was never intended as an interactive option,
and it only piggy-backed on git rebase --interactive because that
command's implementation looked already very, very familiar: it was
designed by the same person who designed --preserve-merges: yours truly.
Some time later, some other developer (I am looking at you, Andreas!
;-)) decided that it would be a good idea to allow --preserve-merges to
be combined with --interactive (with caveats!) and the Git maintainer
(well, the interim Git maintainer during Junio's absence, that is)
agreed, and that is when the glamor of the --preserve-merges design
started to fall apart rather quickly and unglamorously.
The reason? In --preserve-merges mode, the parents of a merge commit (or
for that matter, of *any* commit) were not stated explicitly, but were
*implied* by the commit name passed to the `pick` command.
This made it impossible, for example, to reorder commits. Not to mention
to move commits between branches or, deity forbid, to split topic branches
into two.
Alas, these shortcomings also prevented that mode (whose original
purpose was to serve Git for Windows' needs, with the additional hope
that it may be useful to others, too) from serving Git for Windows'
needs.
Five years later, when it became really untenable to have one unwieldy,
big hodge-podge patch series of partly related, partly unrelated patches
in Git for Windows that was rebased onto core Git's tags from time to
time (earning the undeserved wrath of the developer of the ill-fated
git-remote-hg series that first obsoleted Git for Windows' competing
approach, only to be abandoned without maintainer later) was really
untenable, the "Git garden shears" were born [*1*/*2*]: a script,
piggy-backing on top of the interactive rebase, that would first
determine the branch topology of the patches to be rebased, create a
pseudo todo list for further editing, transform the result into a real
todo list (making heavy use of the `exec` command to "implement" the
missing todo list commands) and finally recreate the patch series on
top of the new base commit.
That was in 2013. And it took about three weeks to come up with the
design and implement it as an out-of-tree script. Needless to say, the
implementation needed quite a few years to stabilize, all the while the
design itself proved itself sound.
With this patch, the goodness of the Git garden shears comes to `git
rebase -i` itself. Passing the `--rebase-merges` option will generate
a todo list that can be understood readily, and where it is obvious
how to reorder commits. New branches can be introduced by inserting
`label` commands and calling `merge <label>`. And once this mode will
have become stable and universally accepted, we can deprecate the design
mistake that was `--preserve-merges`.
Link *1*:
https://github.com/msysgit/msysgit/blob/master/share/msysGit/shears.sh
Link *2*:
https://github.com/git-for-windows/build-extra/blob/master/shears.sh
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-25 14:29:04 +02:00
|
|
|
--rebase-merges --preserve-merges --stat --no-stat
|
2009-10-17 11:33:38 +02:00
|
|
|
--committer-date-is-author-date --ignore-date
|
|
|
|
--ignore-whitespace --whitespace=
|
2016-01-21 21:52:24 +01:00
|
|
|
--autosquash --no-autosquash
|
|
|
|
--fork-point --no-fork-point
|
|
|
|
--autostash --no-autostash
|
|
|
|
--verify --no-verify
|
|
|
|
--keep-empty --root --force-rebase --no-ff
|
2018-03-07 02:05:01 +01:00
|
|
|
--rerere-autoupdate
|
2016-01-21 21:52:24 +01:00
|
|
|
--exec
|
2009-10-17 11:33:38 +02:00
|
|
|
"
|
|
|
|
|
2006-11-27 09:42:07 +01:00
|
|
|
return
|
|
|
|
esac
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2006-11-27 09:42:07 +01:00
|
|
|
}
|
|
|
|
|
2010-12-16 07:56:08 +01:00
|
|
|
_git_reflog ()
|
|
|
|
{
|
|
|
|
local subcommands="show delete expire"
|
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
|
|
|
|
|
|
|
if [ -z "$subcommand" ]; then
|
|
|
|
__gitcomp "$subcommands"
|
|
|
|
else
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2010-12-16 07:56:08 +01:00
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2009-05-04 08:25:35 +02:00
|
|
|
__git_send_email_confirm_options="always never auto cc compose"
|
2009-06-18 14:31:32 +02:00
|
|
|
__git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all"
|
2009-05-04 08:25:35 +02:00
|
|
|
|
2008-07-14 10:21:02 +02:00
|
|
|
_git_send_email ()
|
|
|
|
{
|
2015-11-19 23:52:12 +01:00
|
|
|
case "$prev" in
|
|
|
|
--to|--cc|--bcc|--from)
|
2017-02-03 03:48:26 +01:00
|
|
|
__gitcomp "$(__git send-email --dump-aliases)"
|
2015-11-19 23:52:12 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2008-07-14 10:21:02 +02:00
|
|
|
case "$cur" in
|
2009-05-04 08:25:35 +02:00
|
|
|
--confirm=*)
|
|
|
|
__gitcomp "
|
|
|
|
$__git_send_email_confirm_options
|
|
|
|
" "" "${cur##--confirm=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--suppress-cc=*)
|
|
|
|
__gitcomp "
|
|
|
|
$__git_send_email_suppresscc_options
|
|
|
|
" "" "${cur##--suppress-cc=}"
|
|
|
|
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--smtp-encryption=*)
|
|
|
|
__gitcomp "ssl tls" "" "${cur##--smtp-encryption=}"
|
|
|
|
return
|
|
|
|
;;
|
2012-10-16 02:21:50 +02:00
|
|
|
--thread=*)
|
|
|
|
__gitcomp "
|
|
|
|
deep shallow
|
|
|
|
" "" "${cur##--thread=}"
|
|
|
|
return
|
|
|
|
;;
|
2015-11-19 23:52:12 +01:00
|
|
|
--to=*|--cc=*|--bcc=*|--from=*)
|
2017-02-03 03:48:26 +01:00
|
|
|
__gitcomp "$(__git send-email --dump-aliases)" "" "${cur#--*=}"
|
2015-11-19 23:52:12 +01:00
|
|
|
return
|
|
|
|
;;
|
2008-07-14 10:21:02 +02:00
|
|
|
--*)
|
2018-11-03 07:03:18 +01:00
|
|
|
__gitcomp_builtin send-email "--annotate --bcc --cc --cc-cmd --chain-reply-to
|
2009-05-04 08:25:35 +02:00
|
|
|
--compose --confirm= --dry-run --envelope-sender
|
|
|
|
--from --identity
|
2008-07-14 10:21:02 +02:00
|
|
|
--in-reply-to --no-chain-reply-to --no-signed-off-by-cc
|
2018-03-04 00:58:14 +01:00
|
|
|
--no-suppress-from --no-thread --quiet --reply-to
|
2008-07-14 10:21:02 +02:00
|
|
|
--signed-off-by-cc --smtp-pass --smtp-server
|
2009-05-04 08:25:35 +02:00
|
|
|
--smtp-server-port --smtp-encryption= --smtp-user
|
|
|
|
--subject --suppress-cc= --suppress-from --thread --to
|
2012-10-16 02:21:50 +02:00
|
|
|
--validate --no-validate
|
2018-11-03 07:03:18 +01:00
|
|
|
$__git_format_patch_extra_options"
|
2008-07-14 10:21:02 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2012-10-16 02:21:50 +02:00
|
|
|
__git_complete_revlist
|
2008-07-14 10:21:02 +02:00
|
|
|
}
|
|
|
|
|
bash: support user-supplied completion scripts for user's git commands
The bash completion script already provides support to complete
aliases, options and refs for aliases (if the alias can be traced back
to a supported git command by __git_aliased_command()), and the user's
custom git commands, but it does not support the options of the user's
custom git commands (of course; how could it know about the options of
a custom git command?). Users of such custom git commands could
extend git's bash completion script by writing functions to support
their commands, but they might have issues with it: they might not
have the rights to modify a system-wide git completion script, and
they will need to track and merge upstream changes in the future.
This patch addresses this by providing means for users to supply
custom completion scriplets for their custom git commands without
modifying the main git bash completion script.
Instead of having a huge hard-coded list of command-completion
function pairs (in _git()), the completion script will figure out
which completion function to call based on the command's name. That
is, when completing the options of 'git foo', the main completion
script will check whether the function '_git_foo' is declared, and if
declared, it will invoke that function to perform the completion. If
such a function is not declared, it will fall back to complete file
names. So, users will only need to provide this '_git_foo' completion
function in a separate file, source that file, and it will be used the
next time they press TAB after 'git foo '.
There are two git commands (stage and whatchanged), for which the
completion functions of other commands were used, therefore they
got their own completion function.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:58 +01:00
|
|
|
_git_stage ()
|
|
|
|
{
|
|
|
|
_git_add
|
|
|
|
}
|
|
|
|
|
2016-06-10 12:12:06 +02:00
|
|
|
_git_status ()
|
|
|
|
{
|
|
|
|
local complete_opt
|
|
|
|
local untracked_state
|
|
|
|
|
|
|
|
case "$cur" in
|
|
|
|
--ignore-submodules=*)
|
|
|
|
__gitcomp "none untracked dirty all" "" "${cur##--ignore-submodules=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--untracked-files=*)
|
|
|
|
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--column=*)
|
|
|
|
__gitcomp "
|
|
|
|
always never auto column row plain dense nodense
|
|
|
|
" "" "${cur##--column=}"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin status
|
2016-06-10 12:12:06 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
untracked_state="$(__git_get_option_value "-u" "--untracked-files=" \
|
|
|
|
"$__git_untracked_file_modes" "status.showUntrackedFiles")"
|
|
|
|
|
|
|
|
case "$untracked_state" in
|
|
|
|
no)
|
|
|
|
# --ignored option does not matter
|
|
|
|
complete_opt=
|
|
|
|
;;
|
|
|
|
all|normal|*)
|
|
|
|
complete_opt="--cached --directory --no-empty-directory --others"
|
|
|
|
|
|
|
|
if [ -n "$(__git_find_on_cmdline "--ignored")" ]; then
|
|
|
|
complete_opt="$complete_opt --ignored --exclude=*"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
|
|
|
__git_complete_index_file "$complete_opt"
|
|
|
|
}
|
|
|
|
|
2019-03-29 11:39:18 +01:00
|
|
|
_git_switch ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--conflict=*)
|
|
|
|
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
|
|
|
|
;;
|
|
|
|
--*)
|
|
|
|
__gitcomp_builtin switch
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
# check if --track, --no-track, or --no-guess was specified
|
|
|
|
# if so, disable DWIM mode
|
|
|
|
local track_opt="--track" only_local_ref=n
|
|
|
|
if [ "$GIT_COMPLETION_CHECKOUT_NO_GUESS" = "1" ] ||
|
|
|
|
[ -n "$(__git_find_on_cmdline "--track --no-track --no-guess")" ]; then
|
|
|
|
track_opt=''
|
|
|
|
fi
|
|
|
|
# explicit --guess enables DWIM mode regardless of
|
|
|
|
# $GIT_COMPLETION_CHECKOUT_NO_GUESS
|
|
|
|
if [ -n "$(__git_find_on_cmdline "--guess")" ]; then
|
|
|
|
track_opt='--track'
|
|
|
|
fi
|
|
|
|
if [ -z "$(__git_find_on_cmdline "-d --detach")" ]; then
|
|
|
|
only_local_ref=y
|
2019-06-20 11:55:22 +02:00
|
|
|
else
|
|
|
|
# --guess --detach is invalid combination, no
|
|
|
|
# dwim will be done when --detach is specified
|
|
|
|
track_opt=
|
2019-03-29 11:39:18 +01:00
|
|
|
fi
|
|
|
|
if [ $only_local_ref = y -a -z "$track_opt" ]; then
|
|
|
|
__gitcomp_direct "$(__git_heads "" "$cur" " ")"
|
|
|
|
else
|
|
|
|
__git_complete_refs $track_opt
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2009-05-09 03:23:32 +02:00
|
|
|
__git_config_get_set_variables ()
|
|
|
|
{
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
local prevword word config_file= c=$cword
|
2009-05-09 03:23:32 +02:00
|
|
|
while [ $c -gt 1 ]; do
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
word="${words[c]}"
|
2009-05-09 03:23:32 +02:00
|
|
|
case "$word" in
|
2013-02-12 13:20:42 +01:00
|
|
|
--system|--global|--local|--file=*)
|
2009-05-09 03:23:32 +02:00
|
|
|
config_file="$word"
|
|
|
|
break
|
|
|
|
;;
|
|
|
|
-f|--file)
|
|
|
|
config_file="$word $prevword"
|
|
|
|
break
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
prevword=$word
|
|
|
|
c=$((--c))
|
|
|
|
done
|
|
|
|
|
2017-02-03 03:48:26 +01:00
|
|
|
__git config $config_file --name-only --list
|
2009-05-09 03:23:32 +02:00
|
|
|
}
|
|
|
|
|
2018-05-26 15:55:28 +02:00
|
|
|
__git_config_vars=
|
|
|
|
__git_compute_config_vars ()
|
|
|
|
{
|
|
|
|
test -n "$__git_config_vars" ||
|
|
|
|
__git_config_vars="$(git help --config-for-completion | sort | uniq)"
|
|
|
|
}
|
|
|
|
|
2007-01-29 01:16:53 +01:00
|
|
|
_git_config ()
|
2006-11-27 10:44:47 +01:00
|
|
|
{
|
2018-05-26 15:55:30 +02:00
|
|
|
local varname
|
|
|
|
|
|
|
|
if [ "${BASH_VERSINFO[0]:-0}" -ge 4 ]; then
|
|
|
|
varname="${prev,,}"
|
|
|
|
else
|
|
|
|
varname="$(echo "$prev" |tr A-Z a-z)"
|
|
|
|
fi
|
|
|
|
|
|
|
|
case "$varname" in
|
2013-04-29 14:49:40 +02:00
|
|
|
branch.*.remote|branch.*.pushremote)
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_remotes)"
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
branch.*.merge)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
2013-04-29 14:49:39 +02:00
|
|
|
branch.*.rebase)
|
2018-04-25 14:29:38 +02:00
|
|
|
__gitcomp "false true merges preserve interactive"
|
2013-04-29 14:49:39 +02:00
|
|
|
return
|
|
|
|
;;
|
2013-04-29 14:49:41 +02:00
|
|
|
remote.pushdefault)
|
|
|
|
__gitcomp_nl "$(__git_remotes)"
|
|
|
|
return
|
|
|
|
;;
|
2006-11-27 10:44:47 +01:00
|
|
|
remote.*.fetch)
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
local remote="${prev#remote.}"
|
2006-11-27 10:44:47 +01:00
|
|
|
remote="${remote%.fetch}"
|
2011-10-08 16:54:42 +02:00
|
|
|
if [ -z "$cur" ]; then
|
2013-05-21 02:33:03 +02:00
|
|
|
__gitcomp_nl "refs/heads/" "" "" ""
|
2011-10-08 16:54:42 +02:00
|
|
|
return
|
|
|
|
fi
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_refs_remotes "$remote")"
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
remote.*.push)
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
local remote="${prev#remote.}"
|
2006-11-27 10:44:47 +01:00
|
|
|
remote="${remote%.push}"
|
2017-02-13 20:20:36 +01:00
|
|
|
__gitcomp_nl "$(__git for-each-ref \
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
--format='%(refname):%(refname)' refs/heads)"
|
2007-02-04 08:38:37 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
pull.twohead|pull.octopus)
|
2009-11-18 01:49:10 +01:00
|
|
|
__git_compute_merge_strategies
|
|
|
|
__gitcomp "$__git_merge_strategies"
|
2007-02-04 08:38:37 +01:00
|
|
|
return
|
|
|
|
;;
|
2009-04-25 13:46:14 +02:00
|
|
|
color.branch|color.diff|color.interactive|\
|
|
|
|
color.showbranch|color.status|color.ui)
|
2007-02-04 08:38:37 +01:00
|
|
|
__gitcomp "always never auto"
|
|
|
|
return
|
|
|
|
;;
|
2009-02-12 16:55:54 +01:00
|
|
|
color.pager)
|
|
|
|
__gitcomp "false true"
|
|
|
|
return
|
|
|
|
;;
|
2007-02-04 08:38:37 +01:00
|
|
|
color.*.*)
|
|
|
|
__gitcomp "
|
2008-12-15 18:45:49 +01:00
|
|
|
normal black red green yellow blue magenta cyan white
|
2007-02-04 08:38:37 +01:00
|
|
|
bold dim ul blink reverse
|
|
|
|
"
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
2013-04-29 14:49:38 +02:00
|
|
|
diff.submodule)
|
2019-02-16 12:24:41 +01:00
|
|
|
__gitcomp "$__git_diff_submodule_formats"
|
2013-04-29 14:49:38 +02:00
|
|
|
return
|
|
|
|
;;
|
2009-05-04 08:25:33 +02:00
|
|
|
help.format)
|
|
|
|
__gitcomp "man info web html"
|
|
|
|
return
|
|
|
|
;;
|
2009-05-04 08:25:34 +02:00
|
|
|
log.date)
|
|
|
|
__gitcomp "$__git_log_date_formats"
|
|
|
|
return
|
|
|
|
;;
|
2018-05-05 08:51:44 +02:00
|
|
|
sendemail.aliasfiletype)
|
2009-05-04 08:25:35 +02:00
|
|
|
__gitcomp "mutt mailrc pine elm gnus"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
sendemail.confirm)
|
|
|
|
__gitcomp "$__git_send_email_confirm_options"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
sendemail.suppresscc)
|
|
|
|
__gitcomp "$__git_send_email_suppresscc_options"
|
|
|
|
return
|
|
|
|
;;
|
git-send-email: add --transfer-encoding option
The thread at http://thread.gmane.org/gmane.comp.version-control.git/257392
details problems when applying patches with "git am" in a repository with
CRLF line endings. In the example in the thread, the repository originated
from "git-svn" so it is not possible to use core.eol and friends on it.
Right now, the best option is to use "git am --keep-cr". However, when
a patch create new files, the patch application process will reject the
new file because it finds a "/dev/null\r" string instead of "/dev/null".
The problem is that SMTP transport is CRLF-unsafe. Sending a patch by
email is the same as passing it through "dos2unix | unix2dos". The newly
introduced CRLFs are normally transparent because git-am strips them. The
keepcr=true setting preserves them, but it is mostly working by chance
and it would be very problematic to have a "git am" workflow in a
repository with mixed LF and CRLF line endings.
The MIME solution to this is the quoted-printable transfer enconding.
This is not something that we want to enable by default, since it makes
received emails horrible to look at. However, it is a very good match
for projects that store CRLF line endings in the repository.
The only disadvantage of quoted-printable is that quoted-printable
patches fail to apply if the maintainer uses "git am --keep-cr". This
is because the decoded patch will have two carriage returns at the end
of the line. Therefore, add support for base64 transfer encoding too,
which makes received emails downright impossible to look at outside
a MUA, but really just works.
The patch covers all bases, including users that still live in the late
80s, by also providing a 7bit content transfer encoding that refuses
to send emails with non-ASCII character in them. And finally, "8bit"
will add a Content-Transfer-Encoding header but otherwise do nothing.
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-11-25 15:00:27 +01:00
|
|
|
sendemail.transferencoding)
|
|
|
|
__gitcomp "7bit 8bit quoted-printable base64"
|
|
|
|
return
|
|
|
|
;;
|
2009-05-09 03:23:32 +02:00
|
|
|
--get|--get-all|--unset|--unset-all)
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_config_get_set_variables)"
|
2009-05-09 03:23:32 +02:00
|
|
|
return
|
|
|
|
;;
|
2006-11-27 10:44:47 +01:00
|
|
|
*.*)
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:01:53 +01:00
|
|
|
__gitcomp_builtin config
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
branch.*.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur##*.}"
|
2018-05-26 15:55:29 +02:00
|
|
|
__gitcomp "remote pushRemote merge mergeOptions rebase" "$pfx" "$cur_"
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
branch.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur#*.}"
|
2017-03-23 16:29:24 +01:00
|
|
|
__gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")"
|
2018-05-26 15:55:29 +02:00
|
|
|
__gitcomp_nl_append $'autoSetupMerge\nautoSetupRebase\n' "$pfx" "$cur_"
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
2009-05-04 08:25:32 +02:00
|
|
|
guitool.*.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur##*.}"
|
2009-05-04 08:25:32 +02:00
|
|
|
__gitcomp "
|
2018-05-26 15:55:29 +02:00
|
|
|
argPrompt cmd confirm needsFile noConsole noRescan
|
|
|
|
prompt revPrompt revUnmerged title
|
2011-04-28 18:01:51 +02:00
|
|
|
" "$pfx" "$cur_"
|
2009-05-04 08:25:32 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
difftool.*.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur##*.}"
|
|
|
|
__gitcomp "cmd path" "$pfx" "$cur_"
|
2009-05-04 08:25:32 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
man.*.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur##*.}"
|
|
|
|
__gitcomp "cmd path" "$pfx" "$cur_"
|
2009-05-04 08:25:32 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
mergetool.*.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur##*.}"
|
|
|
|
__gitcomp "cmd path trustExitCode" "$pfx" "$cur_"
|
2009-05-04 08:25:32 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
pager.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur#*.}"
|
2009-11-18 01:49:10 +01:00
|
|
|
__git_compute_all_commands
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$__git_all_commands" "$pfx" "$cur_"
|
2009-05-04 08:25:32 +02:00
|
|
|
return
|
|
|
|
;;
|
2006-11-27 10:44:47 +01:00
|
|
|
remote.*.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur##*.}"
|
2007-05-24 08:07:45 +02:00
|
|
|
__gitcomp "
|
2008-12-15 18:45:49 +01:00
|
|
|
url proxy fetch push mirror skipDefaultUpdate
|
2018-05-26 15:55:29 +02:00
|
|
|
receivepack uploadpack tagOpt pushurl
|
2011-04-28 18:01:51 +02:00
|
|
|
" "$pfx" "$cur_"
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
remote.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur#*.}"
|
completion: optimize refs completion
After a unique command or option is completed, in most cases it is a
good thing to add a trailing a space, but sometimes it doesn't make
sense, e.g. when the completed word is an option taking an argument
('--option=') or a configuration section ('core.'). Therefore the
completion script uses the '-o nospace' option to prevent bash from
automatically appending a space to unique completions, and it has the
__gitcomp() function to add that trailing space only when necessary.
See 72e5e989 (bash: Add space after unique command name is completed.,
2007-02-04), 78d4d6a2 (bash: Support unique completion on git-config.,
2007-02-04), and b3391775 (bash: Support unique completion when
possible., 2007-02-04).
__gitcomp() therefore iterates over all possible completion words it
got as argument, and checks each word whether a trailing space is
necessary or not. This is ok for commands, options, etc., i.e. when
the number of words is relatively small, but can be noticeably slow
for large number of refs. However, while options might or might not
need that trailing space, refs are always handled uniformly and always
get that trailing space (or a trailing '.' for 'git config
branch.<head>.'). Since refs listed by __git_refs() & co. are
separated by newline, this allows us some optimizations with
'compgen'.
So, add a specialized variant of __gitcomp() that only deals with
possible completion words separated by a newline and uniformly appends
the trailing space to all words using 'compgen -S " "' (or any other
suffix, if specified), so no iteration over all words is needed. But
we need to fiddle with IFS, because the default IFS containing a space
would cause the added space suffix to be stripped off when compgen's
output is stored in the COMPREPLY array. Therefore we use only
newline as IFS, hence the requirement for the newline-separated
possible completion words.
Convert all callsites of __gitcomp() where it's called with refs, i.e.
when it gets the output of either __git_refs(), __git_heads(),
__git_tags(), __git_refs2(), __git_refs_remotes(), or the odd 'git
for-each-ref' somewhere in _git_config(). Also convert callsites
where it gets other uniformly handled newline separated word lists,
i.e. either remotes from __git_remotes(), names of set configuration
variables from __git_config_get_set_variables(), stashes, or commands.
Here are some timing results for dealing with 10000 refs.
Before:
$ refs="$(__git_refs ~/tmp/git/repo-with-10k-refs/)"
$ time __gitcomp "$refs"
real 0m1.134s
user 0m1.060s
sys 0m0.130s
After:
$ time __gitcomp_nl "$refs"
real 0m0.373s
user 0m0.360s
sys 0m0.020s
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-10-15 14:57:23 +02:00
|
|
|
__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "."
|
2018-05-26 15:55:29 +02:00
|
|
|
__gitcomp_nl_append "pushDefault" "$pfx" "$cur_"
|
2006-11-27 10:44:47 +01:00
|
|
|
return
|
|
|
|
;;
|
2009-05-04 08:25:32 +02:00
|
|
|
url.*.*)
|
2011-04-28 18:01:51 +02:00
|
|
|
local pfx="${cur%.*}." cur_="${cur##*.}"
|
|
|
|
__gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_"
|
2009-05-04 08:25:32 +02:00
|
|
|
return
|
|
|
|
;;
|
2018-05-27 20:28:00 +02:00
|
|
|
*.*)
|
|
|
|
__git_compute_config_vars
|
|
|
|
__gitcomp "$__git_config_vars"
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
__git_compute_config_vars
|
|
|
|
__gitcomp "$(echo "$__git_config_vars" | sed 's/\.[^ ]*/./g')"
|
2006-11-27 10:44:47 +01:00
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2007-02-05 05:52:08 +01:00
|
|
|
_git_remote ()
|
|
|
|
{
|
2017-02-03 12:01:58 +01:00
|
|
|
local subcommands="
|
|
|
|
add rename remove set-head set-branches
|
|
|
|
get-url set-url show prune update
|
|
|
|
"
|
2009-09-15 12:21:43 +02:00
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
2008-03-10 16:02:23 +01:00
|
|
|
if [ -z "$subcommand" ]; then
|
2017-02-03 12:01:58 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:11 +01:00
|
|
|
__gitcomp_builtin remote
|
2017-02-03 12:01:58 +01:00
|
|
|
;;
|
|
|
|
*)
|
|
|
|
__gitcomp "$subcommands"
|
|
|
|
;;
|
|
|
|
esac
|
2007-02-05 05:52:08 +01:00
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
2017-02-03 12:01:58 +01:00
|
|
|
case "$subcommand,$cur" in
|
|
|
|
add,--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin remote_add
|
2007-02-05 05:52:08 +01:00
|
|
|
;;
|
2017-02-03 12:01:58 +01:00
|
|
|
add,*)
|
|
|
|
;;
|
|
|
|
set-head,--*)
|
2018-02-09 12:02:11 +01:00
|
|
|
__gitcomp_builtin remote_set-head
|
2017-02-03 12:01:58 +01:00
|
|
|
;;
|
|
|
|
set-branches,--*)
|
2018-02-09 12:02:11 +01:00
|
|
|
__gitcomp_builtin remote_set-branches
|
2007-02-05 05:52:08 +01:00
|
|
|
;;
|
2017-02-03 12:01:58 +01:00
|
|
|
set-head,*|set-branches,*)
|
2012-02-22 09:58:10 +01:00
|
|
|
__git_complete_remote_or_refspec
|
|
|
|
;;
|
2017-02-03 12:01:58 +01:00
|
|
|
update,--*)
|
2018-02-09 12:02:11 +01:00
|
|
|
__gitcomp_builtin remote_update
|
2017-02-03 12:01:58 +01:00
|
|
|
;;
|
|
|
|
update,*)
|
2018-05-25 12:48:42 +02:00
|
|
|
__gitcomp "$(__git_remotes) $(__git_get_config_variables "remotes")"
|
2007-05-24 07:46:49 +02:00
|
|
|
;;
|
2017-02-03 12:01:58 +01:00
|
|
|
set-url,--*)
|
2018-02-09 12:02:11 +01:00
|
|
|
__gitcomp_builtin remote_set-url
|
2017-02-03 12:01:58 +01:00
|
|
|
;;
|
|
|
|
get-url,--*)
|
2018-02-09 12:02:11 +01:00
|
|
|
__gitcomp_builtin remote_get-url
|
2017-02-03 12:01:58 +01:00
|
|
|
;;
|
|
|
|
prune,--*)
|
2018-02-09 12:02:11 +01:00
|
|
|
__gitcomp_builtin remote_prune
|
2017-02-03 12:01:58 +01:00
|
|
|
;;
|
2007-02-05 05:52:08 +01:00
|
|
|
*)
|
2017-02-03 12:01:58 +01:00
|
|
|
__gitcomp_nl "$(__git_remotes)"
|
2007-02-05 05:52:08 +01:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2009-10-09 22:49:06 +02:00
|
|
|
_git_replace ()
|
|
|
|
{
|
2017-02-03 12:01:57 +01:00
|
|
|
case "$cur" in
|
2019-02-16 12:24:41 +01:00
|
|
|
--format=*)
|
|
|
|
__gitcomp "short medium long" "" "${cur##--format=}"
|
|
|
|
return
|
|
|
|
;;
|
2017-02-03 12:01:57 +01:00
|
|
|
--*)
|
2018-02-09 12:02:13 +01:00
|
|
|
__gitcomp_builtin replace
|
2017-02-03 12:01:57 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2009-10-09 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2017-02-03 12:01:54 +01:00
|
|
|
_git_rerere ()
|
|
|
|
{
|
|
|
|
local subcommands="clear forget diff remaining status gc"
|
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
|
|
|
if test -z "$subcommand"
|
|
|
|
then
|
|
|
|
__gitcomp "$subcommands"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2006-11-04 19:57:44 +01:00
|
|
|
_git_reset ()
|
|
|
|
{
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2007-02-04 08:38:43 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:14 +01:00
|
|
|
__gitcomp_builtin reset
|
2007-02-04 08:38:43 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2006-11-04 19:57:44 +01:00
|
|
|
}
|
|
|
|
|
2019-04-25 11:45:56 +02:00
|
|
|
_git_restore ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--conflict=*)
|
|
|
|
__gitcomp "diff3 merge" "" "${cur##--conflict=}"
|
|
|
|
;;
|
|
|
|
--source=*)
|
|
|
|
__git_complete_refs --cur="${cur##--source=}"
|
|
|
|
;;
|
|
|
|
--*)
|
|
|
|
__gitcomp_builtin restore
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2018-02-09 12:02:15 +01:00
|
|
|
__git_revert_inprogress_options="--continue --quit --abort"
|
|
|
|
|
2008-08-05 07:50:34 +02:00
|
|
|
_git_revert ()
|
|
|
|
{
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
if [ -f "$__git_repo_path"/REVERT_HEAD ]; then
|
2018-02-09 12:02:15 +01:00
|
|
|
__gitcomp "$__git_revert_inprogress_options"
|
2015-05-25 11:59:35 +02:00
|
|
|
return
|
|
|
|
fi
|
2019-02-16 12:24:41 +01:00
|
|
|
__git_complete_strategy && return
|
2008-08-05 07:50:34 +02:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin revert "" \
|
2018-02-09 12:02:15 +01:00
|
|
|
"$__git_revert_inprogress_options"
|
2008-08-05 07:50:34 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2008-08-05 07:50:34 +02:00
|
|
|
}
|
|
|
|
|
2008-07-23 23:21:08 +02:00
|
|
|
_git_rm ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:16 +01:00
|
|
|
__gitcomp_builtin rm
|
2008-07-23 23:21:08 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
|
|
|
|
__git_complete_index_file "--cached"
|
2008-07-23 23:21:08 +02:00
|
|
|
}
|
|
|
|
|
2007-05-24 07:25:34 +02:00
|
|
|
_git_shortlog ()
|
|
|
|
{
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2007-05-24 07:25:34 +02:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
|
|
|
__gitcomp "
|
2009-02-16 17:34:56 +01:00
|
|
|
$__git_log_common_options
|
|
|
|
$__git_log_shortlog_options
|
2017-02-03 12:01:59 +01:00
|
|
|
--numbered --summary --email
|
2007-05-24 07:25:34 +02:00
|
|
|
"
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
__git_complete_revlist
|
|
|
|
}
|
|
|
|
|
2006-12-15 08:20:03 +01:00
|
|
|
_git_show ()
|
|
|
|
{
|
2008-10-31 01:04:46 +01:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2006-12-15 08:20:03 +01:00
|
|
|
case "$cur" in
|
2011-10-08 03:09:34 +02:00
|
|
|
--pretty=*|--format=*)
|
2010-10-11 00:06:22 +02:00
|
|
|
__gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases)
|
2011-10-08 03:09:34 +02:00
|
|
|
" "" "${cur#*=}"
|
2009-02-24 14:33:29 +01:00
|
|
|
return
|
|
|
|
;;
|
2013-01-16 08:51:58 +01:00
|
|
|
--diff-algorithm=*)
|
|
|
|
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}"
|
|
|
|
return
|
|
|
|
;;
|
2016-08-09 20:34:46 +02:00
|
|
|
--submodule=*)
|
|
|
|
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
|
|
|
|
return
|
|
|
|
;;
|
2006-12-15 08:20:03 +01:00
|
|
|
--*)
|
2009-05-17 05:42:43 +02:00
|
|
|
__gitcomp "--pretty= --format= --abbrev-commit --oneline
|
2014-10-05 01:20:38 +02:00
|
|
|
--show-signature
|
2009-01-19 22:18:00 +01:00
|
|
|
$__git_diff_common_options
|
|
|
|
"
|
2006-12-15 08:20:03 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2013-06-02 16:03:42 +02:00
|
|
|
__git_complete_revlist_file
|
2006-12-15 08:20:03 +01:00
|
|
|
}
|
|
|
|
|
2008-07-23 23:36:15 +02:00
|
|
|
_git_show_branch ()
|
|
|
|
{
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-05-27 10:38:26 +02:00
|
|
|
__gitcomp_builtin show-branch
|
2008-07-23 23:36:15 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
__git_complete_revlist
|
|
|
|
}
|
|
|
|
|
2007-08-03 11:04:37 +02:00
|
|
|
_git_stash ()
|
|
|
|
{
|
2016-01-26 10:37:19 +01:00
|
|
|
local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked'
|
2018-04-20 01:25:13 +02:00
|
|
|
local subcommands='push list show apply clear drop pop create branch'
|
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands save")"
|
2018-04-20 01:25:14 +02:00
|
|
|
if [ -n "$(__git_find_on_cmdline "-p")" ]; then
|
|
|
|
subcommand="push"
|
|
|
|
fi
|
2008-06-27 16:37:15 +02:00
|
|
|
if [ -z "$subcommand" ]; then
|
2009-09-15 12:21:44 +02:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
|
|
|
__gitcomp "$save_opts"
|
|
|
|
;;
|
2018-04-20 01:25:13 +02:00
|
|
|
sa*)
|
|
|
|
if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
|
|
|
|
__gitcomp "save"
|
|
|
|
fi
|
|
|
|
;;
|
2009-09-15 12:21:44 +02:00
|
|
|
*)
|
|
|
|
if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then
|
|
|
|
__gitcomp "$subcommands"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
esac
|
2008-06-27 16:37:15 +02:00
|
|
|
else
|
|
|
|
case "$subcommand,$cur" in
|
2017-05-16 21:59:45 +02:00
|
|
|
push,--*)
|
|
|
|
__gitcomp "$save_opts --message"
|
|
|
|
;;
|
2008-06-27 16:37:15 +02:00
|
|
|
save,--*)
|
2009-09-15 12:21:44 +02:00
|
|
|
__gitcomp "$save_opts"
|
2008-06-27 16:37:15 +02:00
|
|
|
;;
|
2009-06-09 00:57:39 +02:00
|
|
|
apply,--*|pop,--*)
|
2009-09-15 12:21:44 +02:00
|
|
|
__gitcomp "--index --quiet"
|
2008-08-05 07:50:35 +02:00
|
|
|
;;
|
2016-01-26 10:37:19 +01:00
|
|
|
drop,--*)
|
|
|
|
__gitcomp "--quiet"
|
2008-08-05 07:50:35 +02:00
|
|
|
;;
|
2018-09-27 21:59:00 +02:00
|
|
|
list,--*)
|
|
|
|
__gitcomp "--name-status --oneline --patch-with-stat"
|
|
|
|
;;
|
2016-01-26 10:37:19 +01:00
|
|
|
show,--*|branch,--*)
|
|
|
|
;;
|
|
|
|
branch,*)
|
2016-02-22 14:02:50 +01:00
|
|
|
if [ $cword -eq 3 ]; then
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2016-01-26 10:37:19 +01:00
|
|
|
else
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
__gitcomp_nl "$(__git stash list \
|
2016-01-26 10:37:19 +01:00
|
|
|
| sed -n -e 's/:.*//p')"
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
show,*|apply,*|drop,*|pop,*)
|
completion: don't use __gitdir() for git commands
Several completion functions contain the following pattern to run git
commands respecting the path to the repository specified on the
command line:
git --git-dir="$(__gitdir)" <cmd> <options>
This imposes the overhead of fork()ing a subshell for the command
substitution and potentially fork()+exec()ing 'git rev-parse' inside
__gitdir().
Now, if neither '--gitdir=<path>' nor '-C <path>' options are
specified on the command line, then those git commands are perfectly
capable to discover the repository on their own. If either one or
both of those options are specified on the command line, then, again,
the git commands could discover the repository, if we pass them all of
those options from the command line.
This means we don't have to run __gitdir() at all for git commands and
can spare its fork()+exec() overhead.
Use Bash parameter expansions to check the $__git_dir variable and
$__git_C_args array and to assemble the appropriate '--git-dir=<path>'
and '-C <path>' options if either one or both are present on the
command line. These parameter expansions are, however, rather long,
so instead of changing all git executions and make already long lines
even longer, encapsulate running git with '--git-dir=<path> -C <path>'
options into the new __git() wrapper function. Furthermore, this
wrapper function will also enable us to silence error messages from
git commands uniformly in one place in a later commit.
There's one tricky case, though: in __git_refs() local refs are listed
with 'git for-each-ref', where "local" is not necessarily the
repository we are currently in, but it might mean a remote repository
in the filesystem (e.g. listing refs for 'git fetch /some/other/repo
<TAB>'). Use one-shot variable assignment to override $__git_dir with
the path of the repository where the refs should come from. Although
one-shot variable assignments in front of shell functions are to be
avoided in our scripts in general, in the Bash completion script we
can do that safely.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:25 +01:00
|
|
|
__gitcomp_nl "$(__git stash list \
|
2008-08-05 07:50:35 +02:00
|
|
|
| sed -n -e 's/:.*//p')"
|
|
|
|
;;
|
2008-06-27 16:37:15 +02:00
|
|
|
*)
|
|
|
|
;;
|
|
|
|
esac
|
2008-03-10 16:02:23 +01:00
|
|
|
fi
|
2007-08-03 11:04:37 +02:00
|
|
|
}
|
|
|
|
|
2007-08-23 07:50:49 +02:00
|
|
|
_git_submodule ()
|
|
|
|
{
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2019-04-25 09:41:18 +02:00
|
|
|
local subcommands="add status init deinit update set-branch summary foreach sync absorbgitdirs"
|
2017-02-03 12:01:53 +01:00
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
|
|
|
if [ -z "$subcommand" ]; then
|
2007-08-23 07:50:49 +02:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2017-02-03 12:01:53 +01:00
|
|
|
__gitcomp "--quiet"
|
2007-08-23 07:50:49 +02:00
|
|
|
;;
|
|
|
|
*)
|
2008-03-10 16:02:23 +01:00
|
|
|
__gitcomp "$subcommands"
|
2007-08-23 07:50:49 +02:00
|
|
|
;;
|
|
|
|
esac
|
|
|
|
return
|
|
|
|
fi
|
2017-02-03 12:01:53 +01:00
|
|
|
|
|
|
|
case "$subcommand,$cur" in
|
|
|
|
add,--*)
|
|
|
|
__gitcomp "--branch --force --name --reference --depth"
|
|
|
|
;;
|
|
|
|
status,--*)
|
|
|
|
__gitcomp "--cached --recursive"
|
|
|
|
;;
|
|
|
|
deinit,--*)
|
|
|
|
__gitcomp "--force --all"
|
|
|
|
;;
|
|
|
|
update,--*)
|
|
|
|
__gitcomp "
|
|
|
|
--init --remote --no-fetch
|
|
|
|
--recommend-shallow --no-recommend-shallow
|
|
|
|
--force --rebase --merge --reference --depth --recursive --jobs
|
|
|
|
"
|
|
|
|
;;
|
2019-02-08 12:21:34 +01:00
|
|
|
set-branch,--*)
|
|
|
|
__gitcomp "--default --branch"
|
|
|
|
;;
|
2017-02-03 12:01:53 +01:00
|
|
|
summary,--*)
|
|
|
|
__gitcomp "--cached --files --summary-limit"
|
|
|
|
;;
|
|
|
|
foreach,--*|sync,--*)
|
|
|
|
__gitcomp "--recursive"
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
;;
|
|
|
|
esac
|
2007-08-23 07:50:49 +02:00
|
|
|
}
|
|
|
|
|
2008-03-10 16:02:25 +01:00
|
|
|
_git_svn ()
|
|
|
|
{
|
|
|
|
local subcommands="
|
|
|
|
init fetch clone rebase dcommit log find-rev
|
|
|
|
set-tree commit-diff info create-ignore propget
|
2009-02-14 17:21:53 +01:00
|
|
|
proplist show-ignore show-externals branch tag blame
|
2009-12-30 01:58:48 +01:00
|
|
|
migrate mkdirs reset gc
|
2008-03-10 16:02:25 +01:00
|
|
|
"
|
2009-09-15 12:21:43 +02:00
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
2008-03-10 16:02:25 +01:00
|
|
|
if [ -z "$subcommand" ]; then
|
|
|
|
__gitcomp "$subcommands"
|
|
|
|
else
|
|
|
|
local remote_opts="--username= --config-dir= --no-auth-cache"
|
|
|
|
local fc_opts="
|
|
|
|
--follow-parent --authors-file= --repack=
|
|
|
|
--no-metadata --use-svm-props --use-svnsync-props
|
|
|
|
--log-window-size= --no-checkout --quiet
|
2009-02-14 17:21:53 +01:00
|
|
|
--repack-flags --use-log-author --localtime
|
2017-02-05 03:18:57 +01:00
|
|
|
--add-author-from
|
2013-05-04 01:10:18 +02:00
|
|
|
--ignore-paths= --include-paths= $remote_opts
|
2008-03-10 16:02:25 +01:00
|
|
|
"
|
|
|
|
local init_opts="
|
|
|
|
--template= --shared= --trunk= --tags=
|
|
|
|
--branches= --stdlayout --minimize-url
|
|
|
|
--no-metadata --use-svm-props --use-svnsync-props
|
2017-02-05 03:18:57 +01:00
|
|
|
--rewrite-root= --prefix= $remote_opts
|
2008-03-10 16:02:25 +01:00
|
|
|
"
|
|
|
|
local cmt_opts="
|
|
|
|
--edit --rmdir --find-copies-harder --copy-similarity=
|
|
|
|
"
|
|
|
|
|
|
|
|
case "$subcommand,$cur" in
|
|
|
|
fetch,--*)
|
|
|
|
__gitcomp "--revision= --fetch-all $fc_opts"
|
|
|
|
;;
|
|
|
|
clone,--*)
|
|
|
|
__gitcomp "--revision= $fc_opts $init_opts"
|
|
|
|
;;
|
|
|
|
init,--*)
|
|
|
|
__gitcomp "$init_opts"
|
|
|
|
;;
|
|
|
|
dcommit,--*)
|
|
|
|
__gitcomp "
|
|
|
|
--merge --strategy= --verbose --dry-run
|
2009-02-14 17:21:53 +01:00
|
|
|
--fetch-all --no-rebase --commit-url
|
2011-11-03 19:33:30 +01:00
|
|
|
--revision --interactive $cmt_opts $fc_opts
|
2008-03-10 16:02:25 +01:00
|
|
|
"
|
|
|
|
;;
|
|
|
|
set-tree,--*)
|
|
|
|
__gitcomp "--stdin $cmt_opts $fc_opts"
|
|
|
|
;;
|
|
|
|
create-ignore,--*|propget,--*|proplist,--*|show-ignore,--*|\
|
2009-12-30 01:58:48 +01:00
|
|
|
show-externals,--*|mkdirs,--*)
|
2008-03-10 16:02:25 +01:00
|
|
|
__gitcomp "--revision="
|
|
|
|
;;
|
|
|
|
log,--*)
|
|
|
|
__gitcomp "
|
|
|
|
--limit= --revision= --verbose --incremental
|
|
|
|
--oneline --show-commit --non-recursive
|
2009-02-14 17:21:53 +01:00
|
|
|
--authors-file= --color
|
2008-03-10 16:02:25 +01:00
|
|
|
"
|
|
|
|
;;
|
|
|
|
rebase,--*)
|
|
|
|
__gitcomp "
|
|
|
|
--merge --verbose --strategy= --local
|
2009-02-14 17:21:53 +01:00
|
|
|
--fetch-all --dry-run $fc_opts
|
2008-03-10 16:02:25 +01:00
|
|
|
"
|
|
|
|
;;
|
|
|
|
commit-diff,--*)
|
|
|
|
__gitcomp "--message= --file= --revision= $cmt_opts"
|
|
|
|
;;
|
|
|
|
info,--*)
|
|
|
|
__gitcomp "--url"
|
|
|
|
;;
|
2009-02-14 17:21:53 +01:00
|
|
|
branch,--*)
|
|
|
|
__gitcomp "--dry-run --message --tag"
|
|
|
|
;;
|
|
|
|
tag,--*)
|
|
|
|
__gitcomp "--dry-run --message"
|
|
|
|
;;
|
|
|
|
blame,--*)
|
|
|
|
__gitcomp "--git-format"
|
|
|
|
;;
|
|
|
|
migrate,--*)
|
|
|
|
__gitcomp "
|
|
|
|
--config-dir= --ignore-paths= --minimize
|
|
|
|
--no-auth-cache --username=
|
|
|
|
"
|
|
|
|
;;
|
2009-12-30 01:58:48 +01:00
|
|
|
reset,--*)
|
|
|
|
__gitcomp "--revision= --parent"
|
|
|
|
;;
|
2008-03-10 16:02:25 +01:00
|
|
|
*)
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2007-09-01 05:47:01 +02:00
|
|
|
_git_tag ()
|
|
|
|
{
|
|
|
|
local i c=1 f=0
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
while [ $c -lt $cword ]; do
|
|
|
|
i="${words[c]}"
|
2007-09-01 05:47:01 +02:00
|
|
|
case "$i" in
|
2018-03-18 05:01:35 +01:00
|
|
|
-d|--delete|-v|--verify)
|
2017-03-23 16:29:24 +01:00
|
|
|
__gitcomp_direct "$(__git_tags "" "$cur" " ")"
|
2007-09-01 05:47:01 +02:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
-f)
|
|
|
|
f=1
|
|
|
|
;;
|
|
|
|
esac
|
2012-02-22 09:58:11 +01:00
|
|
|
((c++))
|
2007-09-01 05:47:01 +02:00
|
|
|
done
|
|
|
|
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
case "$prev" in
|
2007-09-01 05:47:01 +02:00
|
|
|
-m|-F)
|
|
|
|
;;
|
2008-11-27 14:35:38 +01:00
|
|
|
-*|tag)
|
2007-09-01 05:47:01 +02:00
|
|
|
if [ $f = 1 ]; then
|
2017-03-23 16:29:24 +01:00
|
|
|
__gitcomp_direct "$(__git_tags "" "$cur" " ")"
|
2007-09-01 05:47:01 +02:00
|
|
|
fi
|
|
|
|
;;
|
|
|
|
*)
|
completion: wrap __git_refs() for better option parsing
__git_refs() currently accepts two optional positional parameters: a
remote and a flag for 'git checkout's tracking DWIMery. To fix a
minor bug, and, more importantly, for faster refs completion, this
series will add three more parameters: a prefix, the current word to
be completed and a suffix, i.e. the options accepted by __gitcomp() &
friends, and will change __git_refs() to list only refs matching that
given current word and to add that given prefix and suffix to the
listed refs.
However, __git_refs() is the helper function that is most likely used
in users' custom completion scriptlets for their own git commands, and
we don't want to break those, so
- we can't change __git_refs()'s default output format, i.e. we
can't by default append a trailing space to every listed ref,
meaning that the suffix parameter containing the default trailing
space would have to be specified on every invocation, and
- we can't change the position of existing positional parameters
either, so there would have to be plenty of set-but-empty
placeholder positional parameters all over the completion script.
Furthermore, with five positional parameters it would be really hard
to remember which position means what.
To keep callsites simple, add the new wrapper function
__git_complete_refs() around __git_refs(), which:
- instead of positional parameters accepts real '--opt=val'-style
options and with minimalistic option parsing translates them to
__git_refs()'s and __gitcomp_nl()'s positional parameters, and
- includes the '__gitcomp_nl "$(__git_refs ...)" ...' command
substitution to make its behavior match its name and the behavior
of other __git_complete_* functions, and to limit future changes
in this series to __git_refs() and this new wrapper function.
Call this wrapper function instead of __git_refs() wherever possible
throughout the completion script, i.e. when __git_refs()'s output is
fed to __gitcomp_nl() right away without further processing, which
means all callsites except a single one in the __git_refs2() helper.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:12 +01:00
|
|
|
__git_complete_refs
|
2007-09-01 05:47:01 +02:00
|
|
|
;;
|
|
|
|
esac
|
2014-12-04 19:07:35 +01:00
|
|
|
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2018-02-09 12:02:19 +01:00
|
|
|
__gitcomp_builtin tag
|
2014-12-04 19:07:35 +01:00
|
|
|
;;
|
|
|
|
esac
|
2007-09-01 05:47:01 +02:00
|
|
|
}
|
|
|
|
|
bash: support user-supplied completion scripts for user's git commands
The bash completion script already provides support to complete
aliases, options and refs for aliases (if the alias can be traced back
to a supported git command by __git_aliased_command()), and the user's
custom git commands, but it does not support the options of the user's
custom git commands (of course; how could it know about the options of
a custom git command?). Users of such custom git commands could
extend git's bash completion script by writing functions to support
their commands, but they might have issues with it: they might not
have the rights to modify a system-wide git completion script, and
they will need to track and merge upstream changes in the future.
This patch addresses this by providing means for users to supply
custom completion scriplets for their custom git commands without
modifying the main git bash completion script.
Instead of having a huge hard-coded list of command-completion
function pairs (in _git()), the completion script will figure out
which completion function to call based on the command's name. That
is, when completing the options of 'git foo', the main completion
script will check whether the function '_git_foo' is declared, and if
declared, it will invoke that function to perform the completion. If
such a function is not declared, it will fall back to complete file
names. So, users will only need to provide this '_git_foo' completion
function in a separate file, source that file, and it will be used the
next time they press TAB after 'git foo '.
There are two git commands (stage and whatchanged), for which the
completion functions of other commands were used, therefore they
got their own completion function.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:58 +01:00
|
|
|
_git_whatchanged ()
|
|
|
|
{
|
|
|
|
_git_log
|
|
|
|
}
|
|
|
|
|
2016-05-22 11:33:51 +02:00
|
|
|
_git_worktree ()
|
|
|
|
{
|
2018-02-12 10:49:39 +01:00
|
|
|
local subcommands="add list lock move prune remove unlock"
|
2016-05-22 11:33:51 +02:00
|
|
|
local subcommand="$(__git_find_on_cmdline "$subcommands")"
|
|
|
|
if [ -z "$subcommand" ]; then
|
|
|
|
__gitcomp "$subcommands"
|
|
|
|
else
|
|
|
|
case "$subcommand,$cur" in
|
|
|
|
add,--*)
|
2018-02-09 12:02:20 +01:00
|
|
|
__gitcomp_builtin worktree_add
|
2016-05-22 11:33:51 +02:00
|
|
|
;;
|
|
|
|
list,--*)
|
2018-02-09 12:02:20 +01:00
|
|
|
__gitcomp_builtin worktree_list
|
2016-05-22 11:33:51 +02:00
|
|
|
;;
|
2016-06-13 14:18:24 +02:00
|
|
|
lock,--*)
|
2018-02-09 12:02:20 +01:00
|
|
|
__gitcomp_builtin worktree_lock
|
2016-06-13 14:18:24 +02:00
|
|
|
;;
|
2016-05-22 11:33:51 +02:00
|
|
|
prune,--*)
|
2018-02-09 12:02:20 +01:00
|
|
|
__gitcomp_builtin worktree_prune
|
2016-05-22 11:33:51 +02:00
|
|
|
;;
|
2018-02-12 10:49:39 +01:00
|
|
|
remove,--*)
|
|
|
|
__gitcomp "--force"
|
|
|
|
;;
|
2016-05-22 11:33:51 +02:00
|
|
|
*)
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2018-03-24 21:35:22 +01:00
|
|
|
__git_complete_common () {
|
|
|
|
local command="$1"
|
|
|
|
|
|
|
|
case "$cur" in
|
|
|
|
--*)
|
|
|
|
__gitcomp_builtin "$command"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
|
|
|
__git_cmds_with_parseopt_helper=
|
|
|
|
__git_support_parseopt_helper () {
|
|
|
|
test -n "$__git_cmds_with_parseopt_helper" ||
|
2018-05-20 20:39:57 +02:00
|
|
|
__git_cmds_with_parseopt_helper="$(__git --list-cmds=parseopt)"
|
2018-03-24 21:35:22 +01:00
|
|
|
|
|
|
|
case " $__git_cmds_with_parseopt_helper " in
|
|
|
|
*" $1 "*)
|
|
|
|
return 0
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
return 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2018-03-24 21:35:21 +01:00
|
|
|
__git_complete_command () {
|
|
|
|
local command="$1"
|
|
|
|
local completion_func="_git_${command//-/_}"
|
2018-05-23 07:38:25 +02:00
|
|
|
if ! declare -f $completion_func >/dev/null 2>/dev/null &&
|
|
|
|
declare -f _completion_loader >/dev/null 2>/dev/null
|
|
|
|
then
|
|
|
|
_completion_loader "git-$command"
|
|
|
|
fi
|
|
|
|
if declare -f $completion_func >/dev/null 2>/dev/null
|
|
|
|
then
|
2018-03-24 21:35:21 +01:00
|
|
|
$completion_func
|
|
|
|
return 0
|
2018-05-23 07:38:25 +02:00
|
|
|
elif __git_support_parseopt_helper "$command"
|
|
|
|
then
|
2018-03-24 21:35:22 +01:00
|
|
|
__git_complete_common "$command"
|
|
|
|
return 0
|
2018-03-24 21:35:21 +01:00
|
|
|
else
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
2012-06-13 10:08:50 +02:00
|
|
|
__git_main ()
|
2006-09-28 11:31:25 +02:00
|
|
|
{
|
2017-02-03 03:48:28 +01:00
|
|
|
local i c=1 command __git_dir __git_repo_path
|
completion: respect 'git -C <path>'
'git -C <path>' option(s) on the command line should be taken into
account during completion, because
- like '--git-dir=<path>', it can lead us to a different repository,
- a few git commands executed in the completion script do care about
in which directory they are executed, and
- the command for which we are providing completion might care about
in which directory it will be executed.
However, unlike '--git-dir=<path>', the '-C <path>' option can be
specified multiple times and their effect is cumulative, so we can't
just store a single '<path>' in a variable. Nor can we simply
concatenate a path from '-C <path1> -C <path2> ...', because e.g. (in
an arguably pathological corner case) a relative path might be
followed by an absolute path.
Instead, store all '-C <path>' options word by word in the
$__git_C_args array in the main git completion function, and pass this
array, if present, to 'git rev-parse --absolute-git-dir' when
discovering the repository in __gitdir(), and let it take care of
multiple options, relative paths, absolute paths and everything.
Also pass all '-C <path> options via the $__git_C_args array to those
git executions which require a worktree and for which it matters from
which directory they are executed from. There are only three such
cases:
- 'git diff-index' and 'git ls-files' in __git_ls_files_helper()
used for git-aware filename completion, and
- the 'git ls-tree' used for completing the 'ref:path' notation.
The other git commands executed in the completion script don't need
these '-C <path>' options, because __gitdir() already took those
options into account. It would not hurt them, either, but let's not
induce unnecessary code churn.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:24 +01:00
|
|
|
local __git_C_args C_args_count=0
|
2006-11-05 12:21:57 +01:00
|
|
|
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
while [ $c -lt $cword ]; do
|
|
|
|
i="${words[c]}"
|
2006-11-05 12:21:57 +01:00
|
|
|
case "$i" in
|
|
|
|
--git-dir=*) __git_dir="${i#--git-dir=}" ;;
|
2013-06-22 13:25:17 +02:00
|
|
|
--git-dir) ((c++)) ; __git_dir="${words[c]}" ;;
|
2006-11-05 12:21:57 +01:00
|
|
|
--bare) __git_dir="." ;;
|
2008-07-24 02:07:23 +02:00
|
|
|
--help) command="help"; break ;;
|
2013-06-22 13:25:17 +02:00
|
|
|
-c|--work-tree|--namespace) ((c++)) ;;
|
completion: respect 'git -C <path>'
'git -C <path>' option(s) on the command line should be taken into
account during completion, because
- like '--git-dir=<path>', it can lead us to a different repository,
- a few git commands executed in the completion script do care about
in which directory they are executed, and
- the command for which we are providing completion might care about
in which directory it will be executed.
However, unlike '--git-dir=<path>', the '-C <path>' option can be
specified multiple times and their effect is cumulative, so we can't
just store a single '<path>' in a variable. Nor can we simply
concatenate a path from '-C <path1> -C <path2> ...', because e.g. (in
an arguably pathological corner case) a relative path might be
followed by an absolute path.
Instead, store all '-C <path>' options word by word in the
$__git_C_args array in the main git completion function, and pass this
array, if present, to 'git rev-parse --absolute-git-dir' when
discovering the repository in __gitdir(), and let it take care of
multiple options, relative paths, absolute paths and everything.
Also pass all '-C <path> options via the $__git_C_args array to those
git executions which require a worktree and for which it matters from
which directory they are executed from. There are only three such
cases:
- 'git diff-index' and 'git ls-files' in __git_ls_files_helper()
used for git-aware filename completion, and
- the 'git ls-tree' used for completing the 'ref:path' notation.
The other git commands executed in the completion script don't need
these '-C <path>' options, because __gitdir() already took those
options into account. It would not hurt them, either, but let's not
induce unnecessary code churn.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:24 +01:00
|
|
|
-C) __git_C_args[C_args_count++]=-C
|
|
|
|
((c++))
|
|
|
|
__git_C_args[C_args_count++]="${words[c]}"
|
|
|
|
;;
|
completion: fix completion after 'git --option <TAB>'
The bash completion doesn't work when certain options to git itself are
specified, e.g. 'git --no-pager <TAB>' errors out with
error: invalid key: alias.--no-pager
The main _git() completion function finds out the git command name by
looping through all the words on the command line and searching for
the first word that is not a known option for the git command.
Unfortunately the list of known git options was not updated in a long
time, and newer options are not skipped but mistaken for a git command.
Such a misrecognized "command" is then passed to __git_aliased_command(),
which in turn passes it to a 'git config' query, hence the error.
Currently the following options are misrecognized for a git command:
-c --no-pager --exec-path --html-path --man-path --info-path
--no-replace-objects --work-tree= --namespace=
To fix this we could just update the list of options to be skipped,
but the same issue will likely arise, if the git command learns a new
option in the future. Therefore, to make it more future proof against
new options, this patch changes that loop to skip all option-looking
words, i.e. words starting with a dash.
We also have to handle the '-c' option specially, because it takes a
configutation parameter in a separate word, which must be skipped,
too.
[fc: added tests]
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2012-04-15 21:44:20 +02:00
|
|
|
-*) ;;
|
2006-11-05 12:21:57 +01:00
|
|
|
*) command="$i"; break ;;
|
|
|
|
esac
|
2012-02-22 09:58:11 +01:00
|
|
|
((c++))
|
2006-11-05 12:21:57 +01:00
|
|
|
done
|
|
|
|
|
2008-03-10 16:02:22 +01:00
|
|
|
if [ -z "$command" ]; then
|
completion: don't offer commands when 'git --opt' needs an argument
The main git options '--git-dir', '-c', '-C', '--worktree' and
'--namespace' require an argument, but attempting completion right
after them lists git commands.
Don't offer anything right after these options, thus let Bash fall
back to filename completion, because
- the three options '--git-dir', '-C' and '--worktree' do actually
require a path argument, and
- we don't complete the required argument of '-c' and '--namespace',
and in that case the "standard" behavior of our completion script
is to not offer anything, but fall back to filename completion.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:21 +01:00
|
|
|
case "$prev" in
|
|
|
|
--git-dir|-C|--work-tree)
|
|
|
|
# these need a path argument, let's fall back to
|
|
|
|
# Bash filename completion
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
-c|--namespace)
|
|
|
|
# we don't support completing these options' arguments
|
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
bash: get --pretty=m<tab> completion to work with bash v4
Bash's programmable completion provides the COMP_WORDS array variable,
which holds the individual words in the current command line. In bash
versions prior to v4 "words are split on shell metacharacters as the
shell parser would separate them" (quote from bash v3.2.48's man
page). This behavior has changed with bash v4, and the command line
"is split into words as readline would split it, using COMP_WORDBREAKS
as" "the set of characters that the readline library treats as word
separators" (quote from bash v4's man page).
Since COMP_WORDBREAKS contains the characters : and = by default, this
behavior change in bash affects git's completion script. For example,
before bash 4, running
$ git log --pretty=m <tab><tab>
would give a list of pretty-printing formats starting with 'm' but now
it completes on branch names.
It would be possible to work around this by removing '=' and ':' from
COMP_WORDBREAKS, but as noticed in v1.5.6.4~9^2 (bash completion:
Resolve git show ref:path<tab> losing ref: portion, 2008-07-15), that
would break *other* completion scripts. The bash-completion library
includes a better workaround: the _get_comp_words_by_ref function
re-assembles a copy of COMP_WORDS, excluding a collection of word
separators of the caller's choice. Use it.
As a bonus, this also improves behavior when tab is pressed with the
cursor in the middle of a word.
To avoid breaking setups with the bash-completion library not already
loaded, if the _get_comp_words_by_ref function is not defined then a
shim that just reads COMP_WORDS will be used instead (no change from
the current behavior in that case).
Signed-off-by: Peter van der Does <peter@avirtualhome.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Explained-by: SZEDER Gábor <szeder@ira.uka.de>
2010-12-02 09:17:13 +01:00
|
|
|
case "$cur" in
|
2007-08-23 07:39:22 +02:00
|
|
|
--*) __gitcomp "
|
2008-03-06 17:52:37 +01:00
|
|
|
--paginate
|
2007-08-23 07:39:22 +02:00
|
|
|
--no-pager
|
|
|
|
--git-dir=
|
|
|
|
--bare
|
|
|
|
--version
|
|
|
|
--exec-path
|
2012-04-15 21:44:19 +02:00
|
|
|
--exec-path=
|
2009-04-05 04:15:16 +02:00
|
|
|
--html-path
|
2013-06-22 13:25:18 +02:00
|
|
|
--man-path
|
2012-04-15 21:44:18 +02:00
|
|
|
--info-path
|
2008-03-06 17:52:37 +01:00
|
|
|
--work-tree=
|
ref namespaces: infrastructure
Add support for dividing the refs of a single repository into multiple
namespaces, each of which can have its own branches, tags, and HEAD.
Git can expose each namespace as an independent repository to pull from
and push to, while sharing the object store, and exposing all the refs
to operations such as git-gc.
Storing multiple repositories as namespaces of a single repository
avoids storing duplicate copies of the same objects, such as when
storing multiple branches of the same source. The alternates mechanism
provides similar support for avoiding duplicates, but alternates do not
prevent duplication between new objects added to the repositories
without ongoing maintenance, while namespaces do.
To specify a namespace, set the GIT_NAMESPACE environment variable to
the namespace. For each ref namespace, git stores the corresponding
refs in a directory under refs/namespaces/. For example,
GIT_NAMESPACE=foo will store refs under refs/namespaces/foo/. You can
also specify namespaces via the --namespace option to git.
Note that namespaces which include a / will expand to a hierarchy of
namespaces; for example, GIT_NAMESPACE=foo/bar will store refs under
refs/namespaces/foo/refs/namespaces/bar/. This makes paths in
GIT_NAMESPACE behave hierarchically, so that cloning with
GIT_NAMESPACE=foo/bar produces the same result as cloning with
GIT_NAMESPACE=foo and cloning from that repo with GIT_NAMESPACE=bar. It
also avoids ambiguity with strange namespace paths such as
foo/refs/heads/, which could otherwise generate directory/file conflicts
within the refs directory.
Add the infrastructure for ref namespaces: handle the GIT_NAMESPACE
environment variable and --namespace option, and support iterating over
refs in a namespace.
Signed-off-by: Josh Triplett <josh@joshtriplett.org>
Signed-off-by: Jamey Sharp <jamey@minilop.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-07-05 19:54:44 +02:00
|
|
|
--namespace=
|
2012-04-15 21:44:18 +02:00
|
|
|
--no-replace-objects
|
2008-03-06 17:52:37 +01:00
|
|
|
--help
|
2007-08-23 07:39:22 +02:00
|
|
|
"
|
|
|
|
;;
|
2018-05-20 20:40:08 +02:00
|
|
|
*)
|
|
|
|
if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
|
|
|
|
then
|
|
|
|
__gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST"
|
|
|
|
else
|
2019-03-20 19:03:29 +01:00
|
|
|
__gitcomp "$(__git --list-cmds=list-mainporcelain,others,nohelpers,alias,list-complete,config)"
|
2018-05-20 20:40:08 +02:00
|
|
|
fi
|
|
|
|
;;
|
2007-02-04 08:38:27 +01:00
|
|
|
esac
|
|
|
|
return
|
2006-11-05 12:21:57 +01:00
|
|
|
fi
|
2006-10-28 14:12:20 +02:00
|
|
|
|
2018-03-24 21:35:21 +01:00
|
|
|
__git_complete_command "$command" && return
|
bash: support user-supplied completion scripts for aliases
Shell command aliases can get rather complex, and the completion
script can not always determine correctly the git command invoked by
such an alias. For such cases users might want to provide custom
completion scripts the same way like for their custom commands made
possible by the previous patch.
The current completion script does not allow this, because if it
encounters an alias, then it will unconditionally perform completion
for the aliased git command (in case it can determine the aliased git
command, of course). With this patch the completion script will first
search for a completion function for the command given on the command
line, be it a git command, a custom git command of the user, or an
alias, and invoke that function to perform the completion. This has
no effect on git commands, because they can not be aliased anyway. If
it is an alias and there is a completion function for that alias (e.g.
_git_foo() for the alias 'foo'), then it will be invoked to perform
completion, allowing users to provide custom completion functions for
aliases. If such a completion function can not be found, only then
will the completion script check whether the command given on the
command line is an alias or not, and proceed as usual (i.e. find out
the aliased git command and provide completion for it).
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:59 +01:00
|
|
|
|
2006-11-05 12:21:57 +01:00
|
|
|
local expansion=$(__git_aliased_command "$command")
|
bash: support user-supplied completion scripts for aliases
Shell command aliases can get rather complex, and the completion
script can not always determine correctly the git command invoked by
such an alias. For such cases users might want to provide custom
completion scripts the same way like for their custom commands made
possible by the previous patch.
The current completion script does not allow this, because if it
encounters an alias, then it will unconditionally perform completion
for the aliased git command (in case it can determine the aliased git
command, of course). With this patch the completion script will first
search for a completion function for the command given on the command
line, be it a git command, a custom git command of the user, or an
alias, and invoke that function to perform the completion. This has
no effect on git commands, because they can not be aliased anyway. If
it is an alias and there is a completion function for that alias (e.g.
_git_foo() for the alias 'foo'), then it will be invoked to perform
completion, allowing users to provide custom completion functions for
aliases. If such a completion function can not be found, only then
will the completion script check whether the command given on the
command line is an alias or not, and proceed as usual (i.e. find out
the aliased git command and provide completion for it).
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:59 +01:00
|
|
|
if [ -n "$expansion" ]; then
|
2014-04-09 20:50:04 +02:00
|
|
|
words[1]=$expansion
|
2018-03-24 21:35:21 +01:00
|
|
|
__git_complete_command "$expansion"
|
bash: support user-supplied completion scripts for aliases
Shell command aliases can get rather complex, and the completion
script can not always determine correctly the git command invoked by
such an alias. For such cases users might want to provide custom
completion scripts the same way like for their custom commands made
possible by the previous patch.
The current completion script does not allow this, because if it
encounters an alias, then it will unconditionally perform completion
for the aliased git command (in case it can determine the aliased git
command, of course). With this patch the completion script will first
search for a completion function for the command given on the command
line, be it a git command, a custom git command of the user, or an
alias, and invoke that function to perform the completion. This has
no effect on git commands, because they can not be aliased anyway. If
it is an alias and there is a completion function for that alias (e.g.
_git_foo() for the alias 'foo'), then it will be invoked to perform
completion, allowing users to provide custom completion functions for
aliases. If such a completion function can not be found, only then
will the completion script check whether the command given on the
command line is an alias or not, and proceed as usual (i.e. find out
the aliased git command and provide completion for it).
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-02-23 22:02:59 +01:00
|
|
|
fi
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2012-06-13 10:08:50 +02:00
|
|
|
__gitk_main ()
|
2006-09-28 11:31:25 +02:00
|
|
|
{
|
bash: offer only paths after '--'
Many git commands use '--' to separate subcommands, options, and refs
from paths. However, the programmable completion for several of these
commands does not respect the '--', and offer subcommands, options, or
refs after a '--', although only paths are permitted. e.g. 'git bisect
-- <TAB>' offers subcommands, 'git log -- --<TAB>' offers options and
'git log -- git<TAB>' offers all gitgui tags.
The completion for the following commands share this wrong behaviour:
am add bisect commit diff log reset shortlog submodule gitk.
To avoid this, we check the presence of a '--' on the command line first
and let the shell do filename completion, if one is found.
Signed-off-by: SZEDER Gábor <szeder@ira.uka.de>
Acked-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-08 18:56:14 +02:00
|
|
|
__git_has_doubledash && return
|
|
|
|
|
2017-02-03 03:48:28 +01:00
|
|
|
local __git_repo_path
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
__git_find_repo_path
|
|
|
|
|
2008-04-27 17:35:10 +02:00
|
|
|
local merge=""
|
completion: cache the path to the repository
After the previous changes in this series there are only a handful of
$(__gitdir) command substitutions left in the completion script, but
there is still a bit of room for improvements:
1. The command substitution involves the forking of a subshell,
which has considerable overhead on some platforms.
2. There are a few cases, where this command substitution is
executed more than once during a single completion, which means
multiple subshells and possibly multiple 'git rev-parse'
executions. __gitdir() is invoked twice while completing refs
for e.g. 'git log', 'git rebase', 'gitk', or while completing
remote refs for 'git fetch' or 'git push'.
Both of these points can be addressed by using the
__git_find_repo_path() helper function introduced in the previous
commit:
1. __git_find_repo_path() stores the path to the repository in a
variable instead of printing it, so the command substitution
around the function can be avoided. Or rather: the command
substitution should be avoided to make the new value of the
variable set inside the function visible to the callers.
(Yes, there is now a command substitution inside
__git_find_repo_path() around each 'git rev-parse', but that's
executed only if necessary, and only once per completion, see
point 2. below.)
2. $__git_repo_path, the variable holding the path to the
repository, is declared local in the toplevel completion
functions __git_main() and __gitk_main(). Thus, once set, the
path is visible in all completion functions, including all
subsequent calls to __git_find_repo_path(), meaning that they
wouldn't have to re-discover the path to the repository.
So call __git_find_repo_path() and use $__git_repo_path instead of the
$(__gitdir) command substitution to access paths in the .git
directory. Turn tests checking __gitdir()'s repository discovery into
tests of __git_find_repo_path() such that only the tested function
changes but the expected results don't, ensuring that repo discovery
keeps working as it did before.
As __gitdir() is not used anymore in the completion script, mark it as
deprecated and direct users' attention to __git_find_repo_path() and
$__git_repo_path. Yet keep four __gitdir() tests to ensure that it
handles success and failure of __git_find_repo_path() and that it
still handles its optional remote argument, because users' custom
completion scriptlets might depend on it.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:29 +01:00
|
|
|
if [ -f "$__git_repo_path/MERGE_HEAD" ]; then
|
2008-04-27 17:35:10 +02:00
|
|
|
merge="--merge"
|
|
|
|
fi
|
2007-02-04 08:38:43 +01:00
|
|
|
case "$cur" in
|
|
|
|
--*)
|
2009-02-16 17:34:56 +01:00
|
|
|
__gitcomp "
|
|
|
|
$__git_log_common_options
|
|
|
|
$__git_log_gitk_options
|
|
|
|
$merge
|
|
|
|
"
|
2007-02-04 08:38:43 +01:00
|
|
|
return
|
|
|
|
;;
|
|
|
|
esac
|
2007-02-04 08:38:47 +01:00
|
|
|
__git_complete_revlist
|
2006-09-28 11:31:25 +02:00
|
|
|
}
|
|
|
|
|
2018-06-11 20:20:53 +02:00
|
|
|
if [[ -n ${ZSH_VERSION-} ]] &&
|
|
|
|
# Don't define these functions when sourced from 'git-completion.zsh',
|
|
|
|
# it has its own implementations.
|
|
|
|
[[ -z ${GIT_SOURCING_ZSH_COMPLETION-} ]]; then
|
2012-11-18 12:08:09 +01:00
|
|
|
echo "WARNING: this script is deprecated, please see git-completion.zsh" 1>&2
|
2012-05-14 17:35:18 +02:00
|
|
|
|
2012-11-29 09:20:57 +01:00
|
|
|
autoload -U +X compinit && compinit
|
|
|
|
|
2012-11-18 12:08:09 +01:00
|
|
|
__gitcomp ()
|
|
|
|
{
|
|
|
|
emulate -L zsh
|
2012-05-14 17:35:18 +02:00
|
|
|
|
2012-11-18 12:08:09 +01:00
|
|
|
local cur_="${3-$cur}"
|
|
|
|
|
|
|
|
case "$cur_" in
|
|
|
|
--*=)
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
local c IFS=$' \t\n'
|
|
|
|
local -a array
|
|
|
|
for c in ${=1}; do
|
|
|
|
c="$c${4-}"
|
|
|
|
case $c in
|
|
|
|
--*=*|*.) ;;
|
|
|
|
*) c="$c " ;;
|
|
|
|
esac
|
2013-08-21 22:49:31 +02:00
|
|
|
array[${#array[@]}+1]="$c"
|
2012-11-18 12:08:09 +01:00
|
|
|
done
|
|
|
|
compset -P '*[=:]'
|
|
|
|
compadd -Q -S '' -p "${2-}" -a -- array && _ret=0
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
completion: fill COMPREPLY directly when completing refs
__gitcomp_nl() iterates over all the possible completion words it gets
as argument
- filtering matching words,
- appending a trailing space to each matching word (in all but two
cases),
- prepending a prefix to each matching word (when completing words
after e.g. '--option=<TAB>' or 'master..<TAB>'), and
- adding each matching word to the COMPREPLY array.
This takes a while when a lot of refs are passed to __gitcomp_nl().
The previous changes in this series ensure that __git_refs() lists
only refs matching the current word to be completed, making a second
filtering in __gitcomp_nl() redundant.
Adding the necessary prefix and suffix could be done in __git_refs()
as well:
- When refs come from 'git for-each-ref', then that prefix and
suffix could be added much more efficiently using a 'git
for-each-ref' format containing said prefix and suffix. Care
should be taken, though, because that prefix might contain
'for-each-ref' format specifiers as part of the left hand side of
a '..' range or '...' symmetric difference notation or
fetch/push/etc. refspec, e.g. 'git log "evil-%(refname)..br<TAB>'.
Doubling every '%' in the prefix will prevent 'git for-each-ref'
from interpolating any of those contained specifiers.
- When refs come from 'git ls-remote', then that prefix and suffix
can be added in the shell loop that has to process 'git
ls-remote's output anyway.
- Finally, the prefix and suffix can be added to that handful of
potentially matching symbolic and pseudo refs right away in the
shell loop listing them.
And then all what is still left to do is to assign a bunch of
newline-separated words to a shell array, which can be done without a
shell loop iterating over each word, basically making all of
__gitcomp_nl() unnecessary for refs completion.
Add the helper function __gitcomp_direct() to fill the COMPREPLY array
with prefiltered and preprocessed words without any additional
processing, without a shell loop, with just one single compound
assignment. Modify __git_refs() to accept prefix and suffix
parameters and add them to each and every listed ref as described
above. Modify __git_complete_refs() to pass the prefix and suffix
parameters to __git_refs() and to feed __git_refs()'s output to
__gitcomp_direct() instead of __gitcomp_nl().
This speeds up refs completion when there are a lot of refs matching
the current word to be completed. Listing all branches for completion
in a repo with 100k local branches, all packed, best of five:
On Linux, near the beginning of this series, for reference:
$ time __git_complete_refs
real 0m2.028s
user 0m1.692s
sys 0m0.344s
Before this patch:
real 0m1.135s
user 0m1.112s
sys 0m0.024s
After:
real 0m0.367s
user 0m0.352s
sys 0m0.020s
On Windows, near the beginning:
real 0m13.078s
user 0m1.609s
sys 0m0.060s
Before this patch:
real 0m2.093s
user 0m1.641s
sys 0m0.060s
After:
real 0m0.683s
user 0m0.203s
sys 0m0.076s
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-23 16:29:22 +01:00
|
|
|
__gitcomp_direct ()
|
|
|
|
{
|
|
|
|
emulate -L zsh
|
|
|
|
|
|
|
|
local IFS=$'\n'
|
|
|
|
compset -P '*[=:]'
|
|
|
|
compadd -Q -- ${=1} && _ret=0
|
|
|
|
}
|
|
|
|
|
2012-11-18 12:08:09 +01:00
|
|
|
__gitcomp_nl ()
|
|
|
|
{
|
|
|
|
emulate -L zsh
|
|
|
|
|
|
|
|
local IFS=$'\n'
|
|
|
|
compset -P '*[=:]'
|
|
|
|
compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0
|
|
|
|
}
|
|
|
|
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
__gitcomp_file_direct ()
|
|
|
|
{
|
|
|
|
emulate -L zsh
|
|
|
|
|
|
|
|
local IFS=$'\n'
|
|
|
|
compset -P '*[=:]'
|
2019-01-01 15:05:08 +01:00
|
|
|
compadd -f -- ${=1} && _ret=0
|
completion: fill COMPREPLY directly when completing paths
During git-aware path completion, when a lot of path components have
to be listed, a significant amount of time is spent in
__gitcomp_file(), or more accurately in the shell loop of
__gitcompappend(), iterating over all the path components filtering
path components matching the current word to be completed, adding
prefix path components, and placing the resulting matching paths into
the COMPREPLY array.
Now, a previous patch in this series made 'git ls-files' and 'git
diff-index' list only paths matching the current word to be completed,
so an additional filtering in __gitcomp_file() is not necessary
anymore. Adding the prefix path components could be done much more
efficiently in __git_index_files()'s 'awk' script while stripping
trailing path components and removing duplicates and quoting. And
then the resulting paths won't require any more filtering or
processing before being handed over to Bash, so we could fill the
COMPREPLY array directly.
Unfortunately, we can't simply use the __gitcomp_direct() helper
function to do that, because __gitcomp_file() does one additional
thing: it tells Bash that we are doing filename completion, so the
shell will kindly do four important things for us:
1. Append a trailing space to all filenames.
2. Append a trailing '/' to all directory names.
3. Escape any meta, globbing, separator, etc. characters.
4. List only the current path component when listing possible
completions (i.e. 'dir/subdir/f<TAB>' will list 'file1', 'file2',
etc. instead of the whole 'dir/subdir/file1',
'dir/subdir/file2').
While we could let __git_index_files()'s 'awk' script take care of the
first two points, the third one gets tricky, and we absolutely need
the shell's support for the fourth.
Add the helper function __gitcomp_file_direct(), which, just like
__gitcomp_direct(), fills the COMPREPLY array with prefiltered and
preprocessed paths without any additional processing, without a shell
loop, with just one single compound assignment, and, similar to
__gitcomp_file(), tells Bash and ZSH that we are doing filename
completion. Extend __git_index_files()'s 'awk' script a bit to
prepend any prefix path components to all listed paths. Finally,
modify __git_complete_index_file() to feed __git_index_files()'s
output to ___gitcomp_file_direct() instead of __gitcomp_file().
After this patch there is no shell loop left in the path completion
code path.
This speeds up path completion when there are a lot of paths matching
the current word to be completed. In a pathological repository with
100k files in a single directory, listing all those files:
Before this patch, best of five, using GNU awk on Linux:
$ time cur=dir/ __git_complete_index_file
real 0m0.983s
user 0m1.004s
sys 0m0.033s
After:
real 0m0.313s
user 0m0.341s
sys 0m0.029s
Difference: -68.2%
Speedup: 3.1x
To see the benefits of the whole patch series, the same command with
v2.17.0:
real 0m2.736s
user 0m2.472s
sys 0m0.610s
Difference: -88.6%
Speedup: 8.7x
Note that this patch changes the output of the __git_index_files()
helper function by unconditionally prepending the prefix path
components to every listed path. This would break users' completion
scriptlets that directly run:
__gitcomp_file "$(__git_index_files ...)" "$pfx" "$cur_"
because that would add the prefix path components once more.
However, __git_index_files() is kind of a "helper function of a helper
function", and users' completion scriptlets should have been using
__git_complete_index_file() for git-aware path completion in the first
place, so this is likely doesn't worth worrying about.
Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:42:36 +02:00
|
|
|
}
|
|
|
|
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
__gitcomp_file ()
|
|
|
|
{
|
|
|
|
emulate -L zsh
|
|
|
|
|
|
|
|
local IFS=$'\n'
|
|
|
|
compset -P '*[=:]'
|
2019-01-01 15:05:08 +01:00
|
|
|
compadd -p "${2-}" -f -- ${=1} && _ret=0
|
git-completion.bash: add support for path completion
The git-completion.bash script did not implemented full, git aware,
support to complete paths, for git commands that operate on files within
the current working directory or the index.
As an example:
git add <TAB>
will suggest all files in the current working directory, including
ignored files and files that have not been modified.
Support path completion, for git commands where the non-option arguments
always refer to paths within the current working directory or the index,
as follows:
* the path completion for the "git rm" and "git ls-files"
commands will suggest all cached files.
* the path completion for the "git add" command will suggest all
untracked and modified files. Ignored files are excluded.
* the path completion for the "git clean" command will suggest all
untracked files. Ignored files are excluded.
* the path completion for the "git mv" command will suggest all cached
files when expanding the first argument, and all untracked and cached
files for subsequent arguments. In the latter case, empty directories
are included and ignored files are excluded.
* the path completion for the "git commit" command will suggest all
files that have been modified from the HEAD, if HEAD exists, otherwise
it will suggest all cached files.
For all affected commands, completion will always stop at directory
boundary. Only standard ignored files are excluded, using the
--exclude-standard option of the ls-files command.
When using a recent Bash version, Git path completion will be the same
as builtin file completion, e.g.
git add contrib/
will suggest relative file names.
Signed-off-by: Manlio Perillo <manlio.perillo@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-01-11 19:48:43 +01:00
|
|
|
}
|
|
|
|
|
2012-11-18 12:08:09 +01:00
|
|
|
_git ()
|
|
|
|
{
|
2013-05-08 09:37:00 +02:00
|
|
|
local _ret=1 cur cword prev
|
|
|
|
cur=${words[CURRENT]}
|
|
|
|
prev=${words[CURRENT-1]}
|
|
|
|
let cword=CURRENT-1
|
|
|
|
emulate ksh -c __${service}_main
|
2013-05-08 09:37:01 +02:00
|
|
|
let _ret && _default && _ret=0
|
2012-11-18 12:08:09 +01:00
|
|
|
return _ret
|
|
|
|
}
|
|
|
|
|
|
|
|
compdef _git git gitk
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
__git_func_wrap ()
|
|
|
|
{
|
2012-05-14 17:35:18 +02:00
|
|
|
local cur words cword prev
|
|
|
|
_get_comp_words_by_ref -n =: cur words cword prev
|
|
|
|
$1
|
|
|
|
}
|
|
|
|
|
|
|
|
# Setup completion for certain functions defined above by setting common
|
|
|
|
# variables and workarounds.
|
|
|
|
# This is NOT a public function; use at your own risk.
|
|
|
|
__git_complete ()
|
|
|
|
{
|
|
|
|
local wrapper="__git_wrap${2}"
|
|
|
|
eval "$wrapper () { __git_func_wrap $2 ; }"
|
|
|
|
complete -o bashdefault -o default -o nospace -F $wrapper $1 2>/dev/null \
|
|
|
|
|| complete -o default -o nospace -F $wrapper $1
|
|
|
|
}
|
|
|
|
|
2012-05-19 04:41:35 +02:00
|
|
|
# wrapper for backwards compatibility
|
|
|
|
_git ()
|
|
|
|
{
|
2012-06-13 10:08:50 +02:00
|
|
|
__git_wrap__git_main
|
2012-05-19 04:41:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
# wrapper for backwards compatibility
|
|
|
|
_gitk ()
|
|
|
|
{
|
2012-06-13 10:08:50 +02:00
|
|
|
__git_wrap__gitk_main
|
2012-05-19 04:41:35 +02:00
|
|
|
}
|
|
|
|
|
2012-06-13 10:08:50 +02:00
|
|
|
__git_complete git __git_main
|
|
|
|
__git_complete gitk __gitk_main
|
2006-09-28 11:31:25 +02:00
|
|
|
|
|
|
|
# The following are necessary only for Cygwin, and only are needed
|
|
|
|
# when the user has tab-completed the executable name and consequently
|
|
|
|
# included the '.exe' suffix.
|
|
|
|
#
|
2006-11-05 12:20:25 +01:00
|
|
|
if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then
|
2012-06-13 10:08:50 +02:00
|
|
|
__git_complete git.exe __git_main
|
2006-11-05 12:20:25 +01:00
|
|
|
fi
|