git-commit-vandalism/t/t9902-completion.sh

1687 lines
39 KiB
Bash
Raw Normal View History

#!/bin/sh
#
# Copyright (c) 2012 Felipe Contreras
#
test_description='test bash completion'
. ./lib-bash.sh
complete ()
{
# do nothing
return 0
}
# Be careful when updating this list:
#
# (1) The build tree may have build artifact from different branch, or
# the user's $PATH may have a random executable that may begin
# with "git-check" that are not part of the subcommands this build
# will ship, e.g. "check-ignore". The tests for completion for
# subcommand names tests how "check" is expanded; we limit the
# possible candidates to "checkout" and "check-attr" to make sure
# "check-attr", which is known by the filter function as a
# subcommand to be thrown out, while excluding other random files
# that happen to begin with "check" to avoid letting them get in
# the way.
#
# (2) A test makes sure that common subcommands are included in the
# completion for "git <TAB>", and a plumbing is excluded. "add",
# "filter-branch" and "ls-files" are listed for this.
GIT_TESTING_COMMAND_COMPLETION='add checkout check-attr filter-branch ls-files'
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash"
# We don't need this function to actually join words or do anything special.
# Also, it's cleaner to avoid touching bash's internal completion variables.
# So let's override it with a minimal version for testing purposes.
_get_comp_words_by_ref ()
{
while [ $# -gt 0 ]; do
case "$1" in
cur)
cur=${_words[_cword]}
;;
prev)
prev=${_words[_cword-1]}
;;
words)
words=("${_words[@]}")
;;
cword)
cword=$_cword
;;
esac
shift
done
}
print_comp ()
{
local IFS=$'\n'
echo "${COMPREPLY[*]}" > out
}
run_completion ()
{
local -a COMPREPLY _words
local _cword
_words=( $1 )
test "${1: -1}" = ' ' && _words[${#_words[@]}+1]=''
(( _cword = ${#_words[@]} - 1 ))
__git_wrap__git_main && print_comp
}
# Test high-level completion
# Arguments are:
# 1: typed text so far (cur)
# 2: expected completion
test_completion ()
{
if test $# -gt 1
then
printf '%s\n' "$2" >expected
else
t9902-completion: ignore COMPREPLY element order in some tests The order or possible completion words in the COMPREPLY array doesn't actually matter, as long as all the right words are in there, because Bash will sort them anyway. Yet, our tests looking at the elements of COMPREPLY always expect them to be in a specific order. Now, this hasn't been an issue before, but the next patch is about to optimize a bit more our git-aware path completion, and as a harmless side effect the order of elements in COMPREPLY will change. Worse, the order will be downright undefined, because after the next patch path components will come directly from iterating through an associative array in 'awk', and the order of iteration over the elements in those arrays is undefined, and indeed different 'awk' implementations produce different order. Consequently, we can't get away with simply adjusting the expected results in the affected tests. Modify the 'test_completion' helper function to sort both the expected and the actual results, i.e. the elements in COMPREPLY, before comparing them, so the tests using this helper function will work regardless of the order of elements. Note that this change still leaves a bunch of tests depending on the order of elements in COMPREPLY, tests that focus on a specific helper function and therefore don't use the 'test_completion' helper. I would rather deal with those later, when (if ever) the need actually arises, than create unnecessary code churn now. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:12 +02:00
sed -e 's/Z$//' |sort >expected
fi &&
run_completion "$1" &&
t9902-completion: ignore COMPREPLY element order in some tests The order or possible completion words in the COMPREPLY array doesn't actually matter, as long as all the right words are in there, because Bash will sort them anyway. Yet, our tests looking at the elements of COMPREPLY always expect them to be in a specific order. Now, this hasn't been an issue before, but the next patch is about to optimize a bit more our git-aware path completion, and as a harmless side effect the order of elements in COMPREPLY will change. Worse, the order will be downright undefined, because after the next patch path components will come directly from iterating through an associative array in 'awk', and the order of iteration over the elements in those arrays is undefined, and indeed different 'awk' implementations produce different order. Consequently, we can't get away with simply adjusting the expected results in the affected tests. Modify the 'test_completion' helper function to sort both the expected and the actual results, i.e. the elements in COMPREPLY, before comparing them, so the tests using this helper function will work regardless of the order of elements. Note that this change still leaves a bunch of tests depending on the order of elements in COMPREPLY, tests that focus on a specific helper function and therefore don't use the 'test_completion' helper. I would rather deal with those later, when (if ever) the need actually arises, than create unnecessary code churn now. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:12 +02:00
sort out >out_sorted &&
test_cmp expected out_sorted
}
# Test __gitcomp.
# The first argument is the typed text so far (cur); the rest are
# passed to __gitcomp. Expected output comes is read from the
# standard input, like test_completion().
test_gitcomp ()
{
local -a COMPREPLY &&
sed -e 's/Z$//' >expected &&
local cur="$1" &&
shift &&
__gitcomp "$@" &&
print_comp &&
test_cmp expected out
}
# Test __gitcomp_nl
# Arguments are:
# 1: current word (cur)
# -: the rest are passed to __gitcomp_nl
test_gitcomp_nl ()
{
local -a COMPREPLY &&
sed -e 's/Z$//' >expected &&
local cur="$1" &&
shift &&
__gitcomp_nl "$@" &&
print_comp &&
test_cmp expected out
}
invalid_variable_name='${foo.bar}'
actual="$TRASH_DIRECTORY/actual"
if test_have_prereq MINGW
then
ROOT="$(pwd -W)"
else
ROOT="$(pwd)"
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
test_expect_success 'setup for __git_find_repo_path/__gitdir tests' '
mkdir -p subdir/subsubdir &&
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
mkdir -p non-repo &&
git init otherrepo
'
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
test_expect_success '__git_find_repo_path - from command line (through $__git_dir)' '
echo "$ROOT/otherrepo/.git" >expected &&
(
__git_dir="$ROOT/otherrepo/.git" &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - .git directory in cwd' '
echo ".git" >expected &&
(
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - .git directory in parent' '
echo "$ROOT/.git" >expected &&
(
cd subdir/subsubdir &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - cwd is a .git directory' '
echo "." >expected &&
(
cd .git &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - parent is a .git directory' '
echo "$ROOT/.git" >expected &&
(
cd .git/refs/heads &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - $GIT_DIR set while .git directory in cwd' '
echo "$ROOT/otherrepo/.git" >expected &&
(
GIT_DIR="$ROOT/otherrepo/.git" &&
export GIT_DIR &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - $GIT_DIR set while .git directory in parent' '
echo "$ROOT/otherrepo/.git" >expected &&
(
GIT_DIR="$ROOT/otherrepo/.git" &&
export GIT_DIR &&
cd subdir &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - from command line while "git -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
echo "$ROOT/.git" >expected &&
(
__git_dir="$ROOT/.git" &&
__git_C_args=(-C otherrepo) &&
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 &&
echo "$__git_repo_path" >"$actual"
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
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - relative dir from command line and "git -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
echo "$ROOT/otherrepo/.git" >expected &&
(
cd subdir &&
__git_dir="otherrepo/.git" &&
__git_C_args=(-C ..) &&
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 &&
echo "$__git_repo_path" >"$actual"
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
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - $GIT_DIR set while "git -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
echo "$ROOT/.git" >expected &&
(
GIT_DIR="$ROOT/.git" &&
export GIT_DIR &&
__git_C_args=(-C otherrepo) &&
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 &&
echo "$__git_repo_path" >"$actual"
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
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - relative dir in $GIT_DIR and "git -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
echo "$ROOT/otherrepo/.git" >expected &&
(
cd subdir &&
GIT_DIR="otherrepo/.git" &&
export GIT_DIR &&
__git_C_args=(-C ..) &&
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 &&
echo "$__git_repo_path" >"$actual"
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
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - "git -C" while .git directory in cwd' '
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
echo "$ROOT/otherrepo/.git" >expected &&
(
__git_C_args=(-C otherrepo) &&
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 &&
echo "$__git_repo_path" >"$actual"
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
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - "git -C" while cwd is a .git directory' '
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
echo "$ROOT/otherrepo/.git" >expected &&
(
cd .git &&
__git_C_args=(-C .. -C otherrepo) &&
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 &&
echo "$__git_repo_path" >"$actual"
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
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - "git -C" while .git directory in parent' '
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
echo "$ROOT/otherrepo/.git" >expected &&
(
cd subdir &&
__git_C_args=(-C .. -C otherrepo) &&
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 &&
echo "$__git_repo_path" >"$actual"
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
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - non-existing path in "git -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
(
__git_C_args=(-C non-existing) &&
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
test_must_fail __git_find_repo_path &&
printf "$__git_repo_path" >"$actual"
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
) &&
test_must_be_empty "$actual"
'
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
test_expect_success '__git_find_repo_path - non-existing path in $__git_dir' '
(
__git_dir="non-existing" &&
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
test_must_fail __git_find_repo_path &&
printf "$__git_repo_path" >"$actual"
) &&
test_must_be_empty "$actual"
'
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
test_expect_success '__git_find_repo_path - non-existing $GIT_DIR' '
(
GIT_DIR="$ROOT/non-existing" &&
export GIT_DIR &&
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
test_must_fail __git_find_repo_path &&
printf "$__git_repo_path" >"$actual"
) &&
test_must_be_empty "$actual"
'
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
test_expect_success '__git_find_repo_path - gitfile in cwd' '
echo "$ROOT/otherrepo/.git" >expected &&
echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
test_when_finished "rm -f subdir/.git" &&
(
cd subdir &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_find_repo_path - gitfile in parent' '
echo "$ROOT/otherrepo/.git" >expected &&
echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
test_when_finished "rm -f subdir/.git" &&
(
cd subdir/subsubdir &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success SYMLINKS '__git_find_repo_path - resulting path avoids symlinks' '
echo "$ROOT/otherrepo/.git" >expected &&
mkdir otherrepo/dir &&
test_when_finished "rm -rf otherrepo/dir" &&
ln -s otherrepo/dir link &&
test_when_finished "rm -f link" &&
(
cd link &&
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 &&
echo "$__git_repo_path" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_find_repo_path - not a git repository' '
(
cd non-repo &&
GIT_CEILING_DIRECTORIES="$ROOT" &&
export GIT_CEILING_DIRECTORIES &&
test_must_fail __git_find_repo_path &&
printf "$__git_repo_path" >"$actual"
) &&
test_must_be_empty "$actual"
'
test_expect_success '__gitdir - finds repo' '
echo "$ROOT/.git" >expected &&
(
cd subdir/subsubdir &&
__gitdir >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__gitdir - returns error when cant find repo' '
(
__git_dir="non-existing" &&
test_must_fail __gitdir >"$actual"
) &&
test_must_be_empty "$actual"
'
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
test_expect_success '__gitdir - repo as argument' '
echo "otherrepo/.git" >expected &&
(
__gitdir "otherrepo" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__gitdir - remote as argument' '
echo "remote" >expected &&
(
__gitdir "remote" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_dequote - plain unquoted word' '
__git_dequote unquoted-word &&
verbose test unquoted-word = "$dequoted_word"
'
# input: b\a\c\k\'\\\"s\l\a\s\h\es
# expected: back'\"slashes
test_expect_success '__git_dequote - backslash escaped' '
__git_dequote "b\a\c\k\\'\''\\\\\\\"s\l\a\s\h\es" &&
verbose test "back'\''\\\"slashes" = "$dequoted_word"
'
# input: sin'gle\' '"quo'ted
# expected: single\ "quoted
test_expect_success '__git_dequote - single quoted' '
__git_dequote "'"sin'gle\\\\' '\\\"quo'ted"'" &&
verbose test '\''single\ "quoted'\'' = "$dequoted_word"
'
# input: dou"ble\\" "\"\quot"ed
# expected: double\ "\quoted
test_expect_success '__git_dequote - double quoted' '
__git_dequote '\''dou"ble\\" "\"\quot"ed'\'' &&
verbose test '\''double\ "\quoted'\'' = "$dequoted_word"
'
# input: 'open single quote
test_expect_success '__git_dequote - open single quote' '
__git_dequote "'\''open single quote" &&
verbose test "open single quote" = "$dequoted_word"
'
# input: "open double quote
test_expect_success '__git_dequote - open double quote' '
__git_dequote "\"open double quote" &&
verbose test "open double quote" = "$dequoted_word"
'
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
test_expect_success '__gitcomp_direct - puts everything into COMPREPLY as-is' '
sed -e "s/Z$//g" >expected <<-EOF &&
with-trailing-space Z
without-trailing-spaceZ
--option Z
--option=Z
$invalid_variable_name Z
EOF
(
cur=should_be_ignored &&
__gitcomp_direct "$(cat expected)" &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__gitcomp - trailing space - options' '
test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message=
--reset-author" <<-EOF
--reuse-message=Z
--reedit-message=Z
--reset-author Z
EOF
'
test_expect_success '__gitcomp - trailing space - config keys' '
test_gitcomp "br" "branch. branch.autosetupmerge
branch.autosetuprebase browser." <<-\EOF
branch.Z
branch.autosetupmerge Z
branch.autosetuprebase Z
browser.Z
EOF
'
test_expect_success '__gitcomp - option parameter' '
test_gitcomp "--strategy=re" "octopus ours recursive resolve subtree" \
"" "re" <<-\EOF
recursive Z
resolve Z
EOF
'
test_expect_success '__gitcomp - prefix' '
test_gitcomp "branch.me" "remote merge mergeoptions rebase" \
"branch.maint." "me" <<-\EOF
branch.maint.merge Z
branch.maint.mergeoptions Z
EOF
'
test_expect_success '__gitcomp - suffix' '
test_gitcomp "branch.me" "master maint next pu" "branch." \
"ma" "." <<-\EOF
branch.master.Z
branch.maint.Z
EOF
'
test_expect_success '__gitcomp - doesnt fail because of invalid variable name' '
__gitcomp "$invalid_variable_name"
'
read -r -d "" refs <<-\EOF
maint
master
next
pu
EOF
test_expect_success '__gitcomp_nl - trailing space' '
test_gitcomp_nl "m" "$refs" <<-EOF
maint Z
master Z
EOF
'
test_expect_success '__gitcomp_nl - prefix' '
test_gitcomp_nl "--fixup=m" "$refs" "--fixup=" "m" <<-EOF
--fixup=maint Z
--fixup=master Z
EOF
'
test_expect_success '__gitcomp_nl - suffix' '
test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF
branch.maint.Z
branch.master.Z
EOF
'
test_expect_success '__gitcomp_nl - no suffix' '
test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF
maintZ
masterZ
EOF
'
test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name' '
__gitcomp_nl "$invalid_variable_name"
'
test_expect_success '__git_remotes - list remotes from $GIT_DIR/remotes and from config file' '
cat >expect <<-EOF &&
remote_from_file_1
remote_from_file_2
remote_in_config_1
remote_in_config_2
EOF
test_when_finished "rm -rf .git/remotes" &&
mkdir -p .git/remotes &&
>.git/remotes/remote_from_file_1 &&
>.git/remotes/remote_from_file_2 &&
test_when_finished "git remote remove remote_in_config_1" &&
git remote add remote_in_config_1 git://remote_1 &&
test_when_finished "git remote remove remote_in_config_2" &&
git remote add remote_in_config_2 git://remote_2 &&
(
__git_remotes >actual
) &&
test_cmp expect actual
'
test_expect_success '__git_is_configured_remote' '
test_when_finished "git remote remove remote_1" &&
git remote add remote_1 git://remote_1 &&
test_when_finished "git remote remove remote_2" &&
git remote add remote_2 git://remote_2 &&
(
verbose __git_is_configured_remote remote_2 &&
test_must_fail __git_is_configured_remote non-existent
)
'
test_expect_success 'setup for ref completion' '
git commit --allow-empty -m initial &&
git branch matching-branch &&
git tag matching-tag &&
(
cd otherrepo &&
git commit --allow-empty -m initial &&
git branch -m master master-in-other &&
git branch branch-in-other &&
git tag tag-in-other
) &&
git remote add other "$ROOT/otherrepo/.git" &&
git fetch --no-tags other &&
rm -f .git/FETCH_HEAD &&
git init thirdrepo
'
test_expect_success '__git_refs - simple' '
cat >expected <<-EOF &&
HEAD
master
matching-branch
other/branch-in-other
other/master-in-other
matching-tag
EOF
(
cur= &&
__git_refs >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - full refs' '
cat >expected <<-EOF &&
refs/heads/master
refs/heads/matching-branch
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/other/branch-in-other
refs/remotes/other/master-in-other
refs/tags/matching-tag
EOF
(
cur=refs/heads/ &&
__git_refs >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - repo given on the command line' '
cat >expected <<-EOF &&
HEAD
branch-in-other
master-in-other
tag-in-other
EOF
(
__git_dir="$ROOT/otherrepo/.git" &&
cur= &&
__git_refs >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - remote on local file system' '
cat >expected <<-EOF &&
HEAD
branch-in-other
master-in-other
tag-in-other
EOF
(
cur= &&
__git_refs otherrepo >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - remote on local file system - full refs' '
cat >expected <<-EOF &&
refs/heads/branch-in-other
refs/heads/master-in-other
refs/tags/tag-in-other
EOF
(
cur=refs/ &&
__git_refs otherrepo >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - configured remote' '
cat >expected <<-EOF &&
HEAD
branch-in-other
master-in-other
EOF
(
cur= &&
__git_refs other >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - configured remote - full refs' '
cat >expected <<-EOF &&
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
HEAD
refs/heads/branch-in-other
refs/heads/master-in-other
refs/tags/tag-in-other
EOF
(
cur=refs/ &&
__git_refs other >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - configured remote - repo given on the command line' '
cat >expected <<-EOF &&
HEAD
branch-in-other
master-in-other
EOF
(
cd thirdrepo &&
__git_dir="$ROOT/.git" &&
cur= &&
__git_refs other >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - configured remote - full refs - repo given on the command line' '
cat >expected <<-EOF &&
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
HEAD
refs/heads/branch-in-other
refs/heads/master-in-other
refs/tags/tag-in-other
EOF
(
cd thirdrepo &&
__git_dir="$ROOT/.git" &&
cur=refs/ &&
__git_refs other >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - configured remote - remote name matches a directory' '
cat >expected <<-EOF &&
HEAD
branch-in-other
master-in-other
EOF
mkdir other &&
test_when_finished "rm -rf other" &&
(
cur= &&
__git_refs other >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_refs - URL remote' '
cat >expected <<-EOF &&
HEAD
branch-in-other
master-in-other
tag-in-other
EOF
(
cur= &&
__git_refs "file://$ROOT/otherrepo/.git" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - URL remote - full refs' '
cat >expected <<-EOF &&
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
HEAD
refs/heads/branch-in-other
refs/heads/master-in-other
refs/tags/tag-in-other
EOF
(
cur=refs/ &&
__git_refs "file://$ROOT/otherrepo/.git" >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_refs - non-existing remote' '
(
cur= &&
__git_refs non-existing >"$actual"
) &&
test_must_be_empty "$actual"
'
test_expect_success '__git_refs - non-existing remote - full refs' '
(
cur=refs/ &&
__git_refs non-existing >"$actual"
) &&
test_must_be_empty "$actual"
'
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
test_expect_success '__git_refs - non-existing URL remote' '
(
cur= &&
__git_refs "file://$ROOT/non-existing" >"$actual"
) &&
test_must_be_empty "$actual"
'
test_expect_success '__git_refs - non-existing URL remote - full refs' '
(
cur=refs/ &&
__git_refs "file://$ROOT/non-existing" >"$actual"
) &&
test_must_be_empty "$actual"
'
test_expect_success '__git_refs - not in a git repository' '
(
GIT_CEILING_DIRECTORIES="$ROOT" &&
export GIT_CEILING_DIRECTORIES &&
cd subdir &&
cur= &&
__git_refs >"$actual"
) &&
test_must_be_empty "$actual"
'
test_expect_success '__git_refs - unique remote branches for git checkout DWIMery' '
cat >expected <<-EOF &&
HEAD
master
matching-branch
other/ambiguous
other/branch-in-other
other/master-in-other
remote/ambiguous
remote/branch-in-remote
matching-tag
branch-in-other
branch-in-remote
master-in-other
EOF
for remote_ref in refs/remotes/other/ambiguous \
refs/remotes/remote/ambiguous \
refs/remotes/remote/branch-in-remote
do
git update-ref $remote_ref master &&
test_when_finished "git update-ref -d $remote_ref"
done &&
(
cur= &&
__git_refs "" 1 >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - after --opt=' '
cat >expected <<-EOF &&
HEAD
master
matching-branch
other/branch-in-other
other/master-in-other
matching-tag
EOF
(
cur="--opt=" &&
__git_refs "" "" "" "" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - after --opt= - full refs' '
cat >expected <<-EOF &&
refs/heads/master
refs/heads/matching-branch
refs/remotes/other/branch-in-other
refs/remotes/other/master-in-other
refs/tags/matching-tag
EOF
(
cur="--opt=refs/" &&
__git_refs "" "" "" refs/ >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git refs - exluding refs' '
cat >expected <<-EOF &&
^HEAD
^master
^matching-branch
^other/branch-in-other
^other/master-in-other
^matching-tag
EOF
(
cur=^ &&
__git_refs >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git refs - exluding full refs' '
cat >expected <<-EOF &&
^refs/heads/master
^refs/heads/matching-branch
^refs/remotes/other/branch-in-other
^refs/remotes/other/master-in-other
^refs/tags/matching-tag
EOF
(
cur=^refs/ &&
__git_refs >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success 'setup for filtering matching refs' '
git branch matching/branch &&
git tag matching/tag &&
git -C otherrepo branch matching/branch-in-other &&
git fetch --no-tags other &&
rm -f .git/FETCH_HEAD
'
test_expect_success '__git_refs - dont filter refs unless told so' '
cat >expected <<-EOF &&
HEAD
master
matching-branch
matching/branch
other/branch-in-other
other/master-in-other
other/matching/branch-in-other
matching-tag
matching/tag
EOF
(
cur=master &&
__git_refs >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - only matching refs' '
cat >expected <<-EOF &&
matching-branch
matching/branch
matching-tag
matching/tag
EOF
(
cur=mat &&
__git_refs "" "" "" "$cur" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - only matching refs - full refs' '
cat >expected <<-EOF &&
refs/heads/matching-branch
refs/heads/matching/branch
EOF
(
cur=refs/heads/mat &&
__git_refs "" "" "" "$cur" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - only matching refs - remote on local file system' '
cat >expected <<-EOF &&
master-in-other
matching/branch-in-other
EOF
(
cur=ma &&
__git_refs otherrepo "" "" "$cur" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - only matching refs - configured remote' '
cat >expected <<-EOF &&
master-in-other
matching/branch-in-other
EOF
(
cur=ma &&
__git_refs other "" "" "$cur" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - only matching refs - remote - full refs' '
cat >expected <<-EOF &&
refs/heads/master-in-other
refs/heads/matching/branch-in-other
EOF
(
cur=refs/heads/ma &&
__git_refs other "" "" "$cur" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success '__git_refs - only matching refs - checkout DWIMery' '
cat >expected <<-EOF &&
matching-branch
matching/branch
matching-tag
matching/tag
matching/branch-in-other
EOF
for remote_ref in refs/remotes/other/ambiguous \
refs/remotes/remote/ambiguous \
refs/remotes/remote/branch-in-remote
do
git update-ref $remote_ref master &&
test_when_finished "git update-ref -d $remote_ref"
done &&
(
cur=mat &&
__git_refs "" 1 "" "$cur" >"$actual"
) &&
test_cmp expected "$actual"
'
test_expect_success 'teardown after filtering matching refs' '
git branch -d matching/branch &&
git tag -d matching/tag &&
git update-ref -d refs/remotes/other/matching/branch-in-other &&
git -C otherrepo branch -D matching/branch-in-other
'
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
test_expect_success '__git_refs - for-each-ref format specifiers in prefix' '
cat >expected <<-EOF &&
evil-%%-%42-%(refname)..master
EOF
(
cur="evil-%%-%42-%(refname)..mas" &&
__git_refs "" "" "evil-%%-%42-%(refname).." mas >"$actual"
) &&
test_cmp expected "$actual"
'
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
test_expect_success '__git_complete_refs - simple' '
sed -e "s/Z$//" >expected <<-EOF &&
HEAD Z
master Z
matching-branch Z
other/branch-in-other Z
other/master-in-other Z
matching-tag Z
EOF
(
cur= &&
__git_complete_refs &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_refs - matching' '
sed -e "s/Z$//" >expected <<-EOF &&
matching-branch Z
matching-tag Z
EOF
(
cur=mat &&
__git_complete_refs &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_refs - remote' '
sed -e "s/Z$//" >expected <<-EOF &&
HEAD Z
branch-in-other Z
master-in-other Z
EOF
(
cur=
__git_complete_refs --remote=other &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_refs - track' '
sed -e "s/Z$//" >expected <<-EOF &&
HEAD Z
master Z
matching-branch Z
other/branch-in-other Z
other/master-in-other Z
matching-tag Z
branch-in-other Z
master-in-other Z
EOF
(
cur=
__git_complete_refs --track &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_refs - current word' '
sed -e "s/Z$//" >expected <<-EOF &&
matching-branch Z
matching-tag Z
EOF
(
cur="--option=mat" &&
__git_complete_refs --cur="${cur#*=}" &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_refs - prefix' '
sed -e "s/Z$//" >expected <<-EOF &&
v1.0..matching-branch Z
v1.0..matching-tag Z
EOF
(
cur=v1.0..mat &&
__git_complete_refs --pfx=v1.0.. --cur=mat &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_refs - suffix' '
cat >expected <<-EOF &&
HEAD.
master.
matching-branch.
other/branch-in-other.
other/master-in-other.
matching-tag.
EOF
(
cur= &&
__git_complete_refs --sfx=. &&
print_comp
) &&
test_cmp expected out
'
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
test_expect_success '__git_complete_fetch_refspecs - simple' '
sed -e "s/Z$//" >expected <<-EOF &&
HEAD:HEAD Z
branch-in-other:branch-in-other Z
master-in-other:master-in-other Z
EOF
(
cur= &&
__git_complete_fetch_refspecs other &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_fetch_refspecs - matching' '
sed -e "s/Z$//" >expected <<-EOF &&
branch-in-other:branch-in-other Z
EOF
(
cur=br &&
__git_complete_fetch_refspecs other "" br &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_fetch_refspecs - prefix' '
sed -e "s/Z$//" >expected <<-EOF &&
+HEAD:HEAD Z
+branch-in-other:branch-in-other Z
+master-in-other:master-in-other Z
EOF
(
cur="+" &&
__git_complete_fetch_refspecs other "+" "" &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_fetch_refspecs - fully qualified' '
sed -e "s/Z$//" >expected <<-EOF &&
refs/heads/branch-in-other:refs/heads/branch-in-other Z
refs/heads/master-in-other:refs/heads/master-in-other Z
refs/tags/tag-in-other:refs/tags/tag-in-other Z
EOF
(
cur=refs/ &&
__git_complete_fetch_refspecs other "" refs/ &&
print_comp
) &&
test_cmp expected out
'
test_expect_success '__git_complete_fetch_refspecs - fully qualified & prefix' '
sed -e "s/Z$//" >expected <<-EOF &&
+refs/heads/branch-in-other:refs/heads/branch-in-other Z
+refs/heads/master-in-other:refs/heads/master-in-other Z
+refs/tags/tag-in-other:refs/tags/tag-in-other Z
EOF
(
cur=+refs/ &&
__git_complete_fetch_refspecs other + refs/ &&
print_comp
) &&
test_cmp expected out
'
test_expect_success 'teardown after ref completion' '
git branch -d matching-branch &&
git tag -d matching-tag &&
git remote remove other
'
test_expect_success '__git_get_config_variables' '
cat >expect <<-EOF &&
name-1
name-2
EOF
test_config interesting.name-1 good &&
test_config interesting.name-2 good &&
test_config subsection.interesting.name-3 bad &&
__git_get_config_variables interesting >actual &&
test_cmp expect actual
'
test_expect_success '__git_pretty_aliases' '
cat >expect <<-EOF &&
author
hash
EOF
test_config pretty.author "%an %ae" &&
test_config pretty.hash %H &&
__git_pretty_aliases >actual &&
test_cmp expect actual
'
test_expect_success '__git_aliases' '
cat >expect <<-EOF &&
ci
co
EOF
test_config alias.ci commit &&
test_config alias.co checkout &&
__git_aliases >actual &&
test_cmp expect actual
'
test_expect_success 'basic' '
run_completion "git " &&
# built-in
grep -q "^add \$" out &&
# script
grep -q "^filter-branch \$" out &&
# plumbing
! grep -q "^ls-files \$" out &&
run_completion "git f" &&
! grep -q -v "^f" out
'
test_expect_success 'double dash "git" itself' '
test_completion "git --" <<-\EOF
--paginate Z
--no-pager Z
--git-dir=
--bare Z
--version Z
--exec-path Z
--exec-path=
--html-path Z
--man-path Z
--info-path Z
--work-tree=
--namespace=
--no-replace-objects Z
--help Z
EOF
'
test_expect_success 'double dash "git checkout"' '
test_completion "git checkout --" <<-\EOF
--quiet Z
--detach Z
--track Z
--orphan=Z
--ours Z
--theirs Z
--merge Z
--conflict=Z
--patch Z
--ignore-skip-worktree-bits Z
--ignore-other-worktrees Z
--recurse-submodules Z
--progress Z
--no-track Z
--no-recurse-submodules Z
EOF
'
test_expect_success 'general options' '
test_completion "git --ver" "--version " &&
test_completion "git --hel" "--help " &&
test_completion "git --exe" <<-\EOF &&
--exec-path Z
--exec-path=
EOF
test_completion "git --htm" "--html-path " &&
test_completion "git --pag" "--paginate " &&
test_completion "git --no-p" "--no-pager " &&
test_completion "git --git" "--git-dir=" &&
test_completion "git --wor" "--work-tree=" &&
test_completion "git --nam" "--namespace=" &&
test_completion "git --bar" "--bare " &&
test_completion "git --inf" "--info-path " &&
test_completion "git --no-r" "--no-replace-objects "
'
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
test_expect_success 'general options plus command' '
test_completion "git --version check" "checkout " &&
test_completion "git --paginate check" "checkout " &&
test_completion "git --git-dir=foo check" "checkout " &&
test_completion "git --bare check" "checkout " &&
test_completion "git --exec-path=foo check" "checkout " &&
test_completion "git --html-path check" "checkout " &&
test_completion "git --no-pager check" "checkout " &&
test_completion "git --work-tree=foo check" "checkout " &&
test_completion "git --namespace=foo check" "checkout " &&
test_completion "git --paginate check" "checkout " &&
test_completion "git --info-path check" "checkout " &&
completion: fix completion after 'git -C <path>' The main completion function finds the name of the git command by iterating through all the words on the command line in search for the first non-option-looking word. As it is not aware of 'git -C's mandatory path argument, if the '-C <path>' option is present, 'path' will be the first such word and it will be mistaken for a git command. This breaks completion in various ways: - If 'path' happens to match one of the commands supported by the completion script, then options of that command will be offered. - If 'path' doesn't match a supported command and doesn't contain any characters not allowed in Bash identifier names, then the completion script does basically nothing and Bash in turn falls back to filename completion for all subsequent words. - Otherwise, if 'path' does contain such an unallowed character, then it leads to a more or less ugly error message in the middle of the command line. The standard '/' directory separator is such a character, and it happens to trigger one of the uglier errors: $ git -C some/path <TAB>sh.exe": declare: `_git_some/path': not a valid identifier error: invalid key: alias.some/path Fix this by skipping 'git -C's mandatory path argument while iterating over the words on the command line. Extend the relevant test with this case and, while at it, with cases that needed similar treatment in the past ('--git-dir', '-c', '--work-tree' and '--namespace'). Additionally, silence the standard error of the 'declare' builtins looking for the completion function associated with the git command and of the 'git config' query for the aliased command. So if git ever learns a new option with a mandatory argument in the future, then, though the completion script will again misbehave, at least the command line will not be utterly disrupted by those error messages. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-02-03 03:48:22 +01:00
test_completion "git --no-replace-objects check" "checkout " &&
test_completion "git --git-dir some/path check" "checkout " &&
test_completion "git -c conf.var=value check" "checkout " &&
test_completion "git -C some/path check" "checkout " &&
test_completion "git --work-tree some/path check" "checkout " &&
test_completion "git --namespace name/space check" "checkout "
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
'
test_expect_success 'git --help completion' '
test_completion "git --help ad" "add " &&
test_completion "git --help core" "core-tutorial "
'
test_expect_success 'setup for integration tests' '
echo content >file1 &&
echo more >file2 &&
git add file1 file2 &&
git commit -m one &&
git branch mybranch &&
git tag mytag
'
test_expect_success 'checkout completes ref names' '
test_completion "git checkout m" <<-\EOF
master Z
mybranch Z
mytag Z
EOF
'
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
test_expect_success 'git -C <path> checkout uses the right repo' '
test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
branch-in-other Z
EOF
'
test_expect_success 'show completes all refs' '
test_completion "git show m" <<-\EOF
master Z
mybranch Z
mytag Z
EOF
'
test_expect_success '<ref>: completes paths' '
test_completion "git show mytag:f" <<-\EOF
file1 Z
file2 Z
EOF
'
test_expect_success 'complete tree filename with spaces' '
echo content >"name with spaces" &&
git add "name with spaces" &&
git commit -m spaces &&
test_completion "git show HEAD:nam" <<-\EOF
name with spaces Z
EOF
'
test_expect_success 'complete tree filename with metacharacters' '
echo content >"name with \${meta}" &&
git add "name with \${meta}" &&
git commit -m meta &&
test_completion "git show HEAD:nam" <<-\EOF
name with ${meta} Z
name with spaces Z
EOF
'
test_expect_success 'send-email' '
test_completion "git send-email --cov" "--cover-letter " &&
test_completion "git send-email ma" "master "
'
test_expect_success 'complete files' '
git init tmp && cd tmp &&
test_when_finished "cd .. && rm -rf tmp" &&
echo "expected" > .gitignore &&
echo "out" >> .gitignore &&
t9902-completion: ignore COMPREPLY element order in some tests The order or possible completion words in the COMPREPLY array doesn't actually matter, as long as all the right words are in there, because Bash will sort them anyway. Yet, our tests looking at the elements of COMPREPLY always expect them to be in a specific order. Now, this hasn't been an issue before, but the next patch is about to optimize a bit more our git-aware path completion, and as a harmless side effect the order of elements in COMPREPLY will change. Worse, the order will be downright undefined, because after the next patch path components will come directly from iterating through an associative array in 'awk', and the order of iteration over the elements in those arrays is undefined, and indeed different 'awk' implementations produce different order. Consequently, we can't get away with simply adjusting the expected results in the affected tests. Modify the 'test_completion' helper function to sort both the expected and the actual results, i.e. the elements in COMPREPLY, before comparing them, so the tests using this helper function will work regardless of the order of elements. Note that this change still leaves a bunch of tests depending on the order of elements in COMPREPLY, tests that focus on a specific helper function and therefore don't use the 'test_completion' helper. I would rather deal with those later, when (if ever) the need actually arises, than create unnecessary code churn now. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-17 00:41:12 +02:00
echo "out_sorted" >> .gitignore &&
git add .gitignore &&
test_completion "git commit " ".gitignore" &&
git commit -m ignore &&
touch new &&
test_completion "git add " "new" &&
git add new &&
git commit -a -m new &&
test_completion "git add " "" &&
git mv new modified &&
echo modify > modified &&
test_completion "git add " "modified" &&
touch untracked &&
: TODO .gitignore should not be here &&
test_completion "git rm " <<-\EOF &&
.gitignore
modified
EOF
test_completion "git clean " "untracked" &&
: TODO .gitignore should not be here &&
test_completion "git mv " <<-\EOF &&
.gitignore
modified
EOF
mkdir dir &&
touch dir/file-in-dir &&
git add dir/file-in-dir &&
git commit -m dir &&
mkdir untracked-dir &&
: TODO .gitignore should not be here &&
test_completion "git mv modified " <<-\EOF &&
.gitignore
dir
modified
untracked
untracked-dir
EOF
test_completion "git commit " "modified" &&
: TODO .gitignore should not be here &&
test_completion "git ls-files " <<-\EOF &&
.gitignore
dir
modified
EOF
touch momified &&
test_completion "git add mom" "momified"
'
# The next tests only care about how the completion script deals with
# unusual characters in path names. By defining a custom completion
# function to list untracked files they won't be influenced by future
# changes of the completion functions of real git commands, and we
# don't have to bother with adding files to the index in these tests.
_git_test_path_comp ()
{
__git_complete_index_file --others
}
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
test_expect_success 'complete files - escaped characters on cmdline' '
test_when_finished "rm -rf \"New|Dir\"" &&
mkdir "New|Dir" &&
>"New|Dir/New&File.c" &&
test_completion "git test-path-comp N" \
"New|Dir" && # Bash will turn this into "New\|Dir/"
test_completion "git test-path-comp New\\|D" \
"New|Dir" &&
test_completion "git test-path-comp New\\|Dir/N" \
"New|Dir/New&File.c" && # Bash will turn this into
# "New\|Dir/New\&File.c "
test_completion "git test-path-comp New\\|Dir/New\\&F" \
"New|Dir/New&File.c"
'
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
test_expect_success 'complete files - quoted characters on cmdline' '
test_when_finished "rm -r \"New(Dir\"" &&
mkdir "New(Dir" &&
>"New(Dir/New)File.c" &&
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
# Testing with an opening but without a corresponding closing
# double quote is important.
test_completion "git test-path-comp \"New(D" "New(Dir" &&
test_completion "git test-path-comp \"New(Dir/New)F" \
"New(Dir/New)File.c"
'
test_expect_success 'complete files - UTF-8 in ls-files output' '
test_when_finished "rm -r árvíztűrő" &&
mkdir árvíztűrő &&
>"árvíztűrő/Сайн яваарай" &&
test_completion "git test-path-comp á" "árvíztűrő" &&
test_completion "git test-path-comp árvíztűrő/С" \
"árvíztűrő/Сайн яваарай"
'
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
# Testing with a path containing a backslash is important.
if test_have_prereq !MINGW &&
mkdir 'New\Dir' 2>/dev/null &&
touch 'New\Dir/New"File.c' 2>/dev/null
then
test_set_prereq FUNNYNAMES_BS_DQ
else
say "Your filesystem does not allow \\ and \" in filenames."
rm -rf 'New\Dir'
fi
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
test_expect_success FUNNYNAMES_BS_DQ \
'complete files - C-style escapes in ls-files output' '
test_when_finished "rm -r \"New\\\\Dir\"" &&
test_completion "git test-path-comp N" "New\\Dir" &&
test_completion "git test-path-comp New\\\\D" "New\\Dir" &&
test_completion "git test-path-comp New\\\\Dir/N" \
"New\\Dir/New\"File.c" &&
test_completion "git test-path-comp New\\\\Dir/New\\\"F" \
"New\\Dir/New\"File.c"
'
if test_have_prereq !MINGW &&
mkdir $'New\034Special\035Dir' 2>/dev/null &&
touch $'New\034Special\035Dir/New\036Special\037File' 2>/dev/null
then
test_set_prereq FUNNYNAMES_SEPARATORS
else
say 'Your filesystem does not allow special separator characters (FS, GS, RS, US) in filenames.'
rm -rf $'New\034Special\035Dir'
fi
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
test_expect_success FUNNYNAMES_SEPARATORS \
'complete files - \nnn-escaped control characters in ls-files output' '
test_when_finished "rm -r '$'New\034Special\035Dir''" &&
# Note: these will be literal separator characters on the cmdline.
test_completion "git test-path-comp N" "'$'New\034Special\035Dir''" &&
test_completion "git test-path-comp '$'New\034S''" \
"'$'New\034Special\035Dir''" &&
test_completion "git test-path-comp '$'New\034Special\035Dir/''" \
"'$'New\034Special\035Dir/New\036Special\037File''" &&
test_completion "git test-path-comp '$'New\034Special\035Dir/New\036S''" \
"'$'New\034Special\035Dir/New\036Special\037File''"
'
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
test_expect_success FUNNYNAMES_BS_DQ \
'complete files - removing repeated quoted path components' '
test_when_finished rm -rf NewDir &&
mkdir NewDir && # A dirname which in itself would not be quoted ...
>NewDir/0-file &&
>NewDir/1\"file && # ... but here the file makes the dirname quoted ...
>NewDir/2-file &&
>NewDir/3\"file && # ... and here, too.
# Still, we should only list it once.
test_completion "git test-path-comp New" "NewDir"
'
test_expect_success "completion uses <cmd> completion for alias: !sh -c 'git <cmd> ...'" '
test_config alias.co "!sh -c '"'"'git checkout ...'"'"'" &&
test_completion "git co m" <<-\EOF
master Z
mybranch Z
mytag Z
EOF
'
test_expect_success 'completion uses <cmd> completion for alias: !f () { VAR=val git <cmd> ... }' '
test_config alias.co "!f () { VAR=val git checkout ... ; } f" &&
test_completion "git co m" <<-\EOF
master Z
mybranch Z
mytag Z
EOF
'
test_expect_success 'completion used <cmd> completion for alias: !f() { : git <cmd> ; ... }' '
test_config alias.co "!f() { : git checkout ; if ... } f" &&
test_completion "git co m" <<-\EOF
master Z
mybranch Z
mytag Z
EOF
'
test_expect_success 'completion without explicit _git_xxx function' '
test_completion "git version --" <<-\EOF
--build-options Z
EOF
'
test_expect_failure 'complete with tilde expansion' '
git init tmp && cd tmp &&
test_when_finished "cd .. && rm -rf tmp" &&
touch ~/tmp/file &&
test_completion "git add ~/tmp/" "~/tmp/file"
'
test_expect_success 'setup other remote for remote reference completion' '
git remote add other otherrepo &&
git fetch other
'
for flag in -d --delete
do
test_expect_success "__git_complete_remote_or_refspec - push $flag other" '
sed -e "s/Z$//" >expected <<-EOF &&
master-in-other Z
EOF
(
words=(git push '$flag' other ma) &&
cword=${#words[@]} cur=${words[cword-1]} &&
__git_complete_remote_or_refspec &&
print_comp
) &&
test_cmp expected out
'
test_expect_failure "__git_complete_remote_or_refspec - push other $flag" '
sed -e "s/Z$//" >expected <<-EOF &&
master-in-other Z
EOF
(
words=(git push other '$flag' ma) &&
cword=${#words[@]} cur=${words[cword-1]} &&
__git_complete_remote_or_refspec &&
print_comp
) &&
test_cmp expected out
'
done
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
test_expect_success 'sourcing the completion script clears cached commands' '
__git_compute_all_commands &&
verbose test -n "$__git_all_commands" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
verbose test -z "$__git_all_commands"
'
test_expect_success 'sourcing the completion script clears cached porcelain commands' '
__git_compute_porcelain_commands &&
verbose test -n "$__git_porcelain_commands" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
verbose test -z "$__git_porcelain_commands"
'
test_expect_success !GETTEXT_POISON 'sourcing the completion script clears cached merge strategies' '
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
__git_compute_merge_strategies &&
verbose test -n "$__git_merge_strategies" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
verbose test -z "$__git_merge_strategies"
'
test_expect_success 'sourcing the completion script clears cached --options' '
__gitcomp_builtin checkout &&
verbose test -n "$__gitcomp_builtin_checkout" &&
__gitcomp_builtin notes_edit &&
verbose test -n "$__gitcomp_builtin_notes_edit" &&
. "$GIT_BUILD_DIR/contrib/completion/git-completion.bash" &&
verbose test -z "$__gitcomp_builtin_checkout" &&
verbose test -z "$__gitcomp_builtin_notes_edit"
'
test_done