git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: "SZEDER Gábor" <szeder@ira.uka.de>
To: Junio C Hamano <gitster@pobox.com>
Cc: "Jeff King" <peff@peff.net>,
	"Sebastian Schuberth" <sschuberth@gmail.com>,
	git@vger.kernel.org, "SZEDER Gábor" <szeder@ira.uka.de>
Subject: [PATCH 16/21] completion: respect 'git -C <path>'
Date: Thu, 25 Feb 2016 23:50:45 +0100	[thread overview]
Message-ID: <1456440650-32623-17-git-send-email-szeder@ira.uka.de> (raw)
In-Reply-To: <1456440650-32623-1-git-send-email-szeder@ira.uka.de>

'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 <szeder@ira.uka.de>
---
 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

  parent reply	other threads:[~2016-02-25 22:53 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-25 22:50 [PATCH 00/21] completion: __gitdir()-related improvements SZEDER Gábor
2016-02-25 22:50 ` [PATCH 01/21] completion: improve __git_refs()'s in-code documentation SZEDER Gábor
2016-02-25 22:50 ` [PATCH 02/21] completion tests: don't add test cruft to the test repository SZEDER Gábor
2016-02-25 22:50 ` [PATCH 03/21] completion tests: make the $cur variable local to the test helper functions SZEDER Gábor
2016-02-25 22:50 ` [PATCH 04/21] completion tests: consolidate getting path of current working directory SZEDER Gábor
2016-02-25 22:50 ` [PATCH 05/21] completion tests: check __gitdir()'s output in the error cases SZEDER Gábor
2016-02-25 22:50 ` [PATCH 06/21] completion tests: add tests for the __git_refs() helper function SZEDER Gábor
2016-02-25 22:50 ` [PATCH 07/21] completion: ensure that the repository path given on the command line exists SZEDER Gábor
2016-02-25 22:50 ` [PATCH 08/21] completion: fix most spots not respecting 'git --git-dir=<path>' SZEDER Gábor
2016-02-25 22:50 ` [PATCH 09/21] completion: respect 'git --git-dir=<path>' when listing remote refs SZEDER Gábor
2016-02-25 22:50 ` [PATCH 10/21] completion: list refs from remote when remote's name matches a directory SZEDER Gábor
2016-02-25 22:50 ` [PATCH 11/21] completion: don't list 'HEAD' when trying refs completion outside of a repo SZEDER Gábor
2016-02-25 22:50 ` [PATCH 12/21] completion: list short refs from a remote given as a URL SZEDER Gábor
2016-02-25 22:50 ` [PATCH 13/21] rev-parse: add '--absolute-git-dir' option SZEDER Gábor
2016-04-26  2:33   ` Mike Rappazzo
2016-04-26  5:35     ` Jeff King
2016-05-18 16:58     ` SZEDER Gábor
2016-02-25 22:50 ` [PATCH 14/21] completion: don't offer commands when 'git --opt' needs an argument SZEDER Gábor
2016-02-25 22:50 ` [PATCH 15/21] completion: fix completion after 'git -C <path>' SZEDER Gábor
2016-02-25 22:50 ` SZEDER Gábor [this message]
2016-02-25 22:50 ` [PATCH 17/21] completion: don't use __gitdir() for git commands SZEDER Gábor
2016-02-25 22:50 ` [PATCH 18/21] completion: consolidate silencing errors from " SZEDER Gábor
2016-02-25 22:50 ` [PATCH 19/21] completion: don't guard git executions with __gitdir() SZEDER Gábor
2016-02-25 22:50 ` [PATCH 20/21] completion: extract repository discovery from __gitdir() SZEDER Gábor
2016-02-25 22:50 ` [PATCH 21/21] completion: cache the path to the repository SZEDER Gábor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1456440650-32623-17-git-send-email-szeder@ira.uka.de \
    --to=szeder@ira.uka.de \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=peff@peff.net \
    --cc=sschuberth@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).