'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,
and
- a few git commands executed in the completion script do actually
care about from which directory they are executed from.
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 <[email protected]>
---
contrib/completion/git-completion.bash | 19 ++++++--
t/t9902-completion.sh | 87 ++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+), 5 deletions(-)
diff --git a/contrib/completion/git-completion.bash
b/contrib/completion/git-completion.bash
index 5e5437d7a5c2..9ffea9580ff7 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -39,7 +39,11 @@ esac
__gitdir ()
{
if [ -z "${1-}" ]; then
- if [ -n "${__git_dir-}" ]; then
+ if [ -n "${__git_C_args-}" ]; then
+ git "${__git_C_args[@]}" \
+ ${__git_dir:+--git-dir="$__git_dir"} \
+ rev-parse --absolute-git-dir 2>/dev/null
+ elif [ -n "${__git_dir-}" ]; then
test -d "$__git_dir" || return 1
echo "$__git_dir"
elif [ -n "${GIT_DIR-}" ]; then
@@ -286,10 +290,10 @@ __git_ls_files_helper ()
local dir="$(__gitdir)"
if [ "$2" == "--committable" ]; then
- git --git-dir="$dir" -C "$1" diff-index --name-only --relative
HEAD
+ git ${__git_C_args:+"${__git_C_args[@]}"} --git-dir="$dir" -C
"$1" diff-index --name-only --relative HEAD
else
# NOTE: $2 is not quoted in order to support multiple options
- git --git-dir="$dir" -C "$1" ls-files --exclude-standard $2
+ git ${__git_C_args:+"${__git_C_args[@]}"} --git-dir="$dir" -C
"$1" ls-files --exclude-standard $2
fi 2>/dev/null
}
@@ -521,7 +525,7 @@ __git_complete_revlist_file ()
*) pfx="$ref:$pfx" ;;
esac
- __gitcomp_nl "$(git --git-dir="$(__gitdir)" ls-tree "$ls"
2>/dev/null \
+ __gitcomp_nl "$(git ${__git_C_args:+"${__git_C_args[@]}"}
--git-dir="$(__gitdir)" ls-tree "$ls" 2>/dev/null \
| sed '/^100... blob /{
s,^.* ,,
s,$, ,
@@ -2650,6 +2654,7 @@ _git_whatchanged ()
__git_main ()
{
local i c=1 command __git_dir
+ local __git_C_args C_args_count=0
while [ $c -lt $cword ]; do
i="${words[c]}"
@@ -2658,7 +2663,11 @@ __git_main ()
--git-dir) ((c++)) ; __git_dir="${words[c]}" ;;
--bare) __git_dir="." ;;
--help) command="help"; break ;;
- -c|-C|--work-tree|--namespace) ((c++)) ;;
+ -c|--work-tree|--namespace) ((c++)) ;;
+ -C) __git_C_args[C_args_count++]=-C
+ ((c++))
+ __git_C_args[C_args_count++]="${words[c]}"
+ ;;
-*) ;;
*) command="$i"; break ;;
esac
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index d172199ed256..f68b3383caa3 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -211,6 +211,87 @@ test_expect_success '__gitdir - $GIT_DIR set while .git
directory in parent' '
test_cmp expected "$actual"
'
+test_expect_success '__gitdir - from command line while "git -C"' '
+ echo "$ROOT/.git" >expected &&
+ (
+ __git_dir="$ROOT/.git" &&
+ __git_C_args=(-C otherrepo) &&
+ __gitdir >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - relative dir from command line and "git -C"' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ cd subdir &&
+ __git_dir="otherrepo/.git" &&
+ __git_C_args=(-C ..) &&
+ __gitdir >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - $GIT_DIR set while "git -C"' '
+ echo "$ROOT/.git" >expected &&
+ (
+ GIT_DIR="$ROOT/.git" &&
+ export GIT_DIR &&
+ __git_C_args=(-C otherrepo) &&
+ __gitdir >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - relative dir in $GIT_DIR and "git -C"' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ cd subdir &&
+ GIT_DIR="otherrepo/.git" &&
+ export GIT_DIR &&
+ __git_C_args=(-C ..) &&
+ __gitdir >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - "git -C" while .git directory in cwd' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ __git_C_args=(-C otherrepo) &&
+ __gitdir >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - "git -C" while cwd is a .git directory' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ cd .git &&
+ __git_C_args=(-C .. -C otherrepo) &&
+ __gitdir >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - "git -C" while .git directory in parent' '
+ echo "$ROOT/otherrepo/.git" >expected &&
+ (
+ cd subdir &&
+ __git_C_args=(-C .. -C otherrepo) &&
+ __gitdir >"$actual"
+ ) &&
+ test_cmp expected "$actual"
+'
+
+test_expect_success '__gitdir - non-existing path in "git -C"' '
+ (
+ __git_C_args=(-C non-existing) &&
+ test_must_fail __gitdir >"$actual"
+ ) &&
+ test_must_be_empty "$actual"
+'
+
test_expect_success '__gitdir - non-existing path in $__git_dir' '
(
__git_dir="non-existing" &&
@@ -775,6 +856,12 @@ test_expect_success 'checkout completes ref names' '
EOF
'
+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 Z
+ EOF
+'
+
test_expect_success 'show completes all refs' '
test_completion "git show m" <<-\EOF
master Z
--
2.7.2.410.g92cb358
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html