git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH 4/6] Take --git-dir into consideration during bash completion.

From
Shawn O. Pearce <spearce@spearce.org>
Date
Nov 5, 2006, 11:21 UTC
Message-ID
<20061105112157.GD20495@spearce.org>

If the user has setup a command line of "git --git-dir=baz" then anything we complete must be performed within the scope of "baz" and not the current working directory.

This is useful with commands such as "git --git-dir=git.git log m" to complete out "master" and view the log for the master branch of the git.git repository. As a nice side effect this also works for aliases within the target repository, just as git would honor them.

Unfortunately because we still examine arguments by absolute position in most of the more complex commands (e.g. git push) using --git-dir with those commands will probably still cause completion to fail.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 contrib/completion/git-completion.bash |  123 ++++++++++++++++++--------------
 1 files changed, 70 insertions(+), 53 deletions(-)
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 5f1be46..f258f2f 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -19,15 +19,20 @@
 #        source ~/.git-completion.sh
 #
 
+__gitdir ()
+{
+	echo "${__git_dir:-$(git rev-parse --git-dir 2>/dev/null)}"
+}
+
 __git_refs ()
 {
-	local cmd i is_hash=y
-	if [ -d "$1" ]; then
+	local cmd i is_hash=y dir="${1:-$(__gitdir)}"
+	if [ -d "$dir" ]; then
 		cmd=git-peek-remote
 	else
 		cmd=git-ls-remote
 	fi
-	for i in $($cmd "$1" 2>/dev/null); do
+	for i in $($cmd "$dir" 2>/dev/null); do
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
@@ -40,13 +45,13 @@ __git_refs ()
 
 __git_refs2 ()
 {
-	local cmd i is_hash=y
-	if [ -d "$1" ]; then
+	local cmd i is_hash=y dir="${1:-$(__gitdir)}"
+	if [ -d "$dir" ]; then
 		cmd=git-peek-remote
 	else
 		cmd=git-ls-remote
 	fi
-	for i in $($cmd "$1" 2>/dev/null); do
+	for i in $($cmd "$dir" 2>/dev/null); do
 		case "$is_hash,$i" in
 		y,*) is_hash=n ;;
 		n,*^{}) is_hash=y ;;
@@ -59,14 +64,14 @@ __git_refs2 ()
 
 __git_remotes ()
 {
-	local i ngoff IFS=$'\n'
+	local i ngoff IFS=$'\n' d="$(__gitdir)"
 	shopt -q nullglob || ngoff=1
 	shopt -s nullglob
-	for i in .git/remotes/*; do
-		echo ${i#.git/remotes/}
+	for i in "$d/remotes"/*; do
+		echo ${i#$d/remotes/}
 	done
 	[ "$ngoff" ] && shopt -u nullglob
-	for i in $(git repo-config --list); do
+	for i in $(git --git-dir="$d" repo-config --list); do
 		case "$i" in
 		remote.*.url=*)
 			i="${i#remote.}"
@@ -95,7 +100,7 @@ __git_complete_file ()
 			;;
 	    esac
 		COMPREPLY=($(compgen -P "$pfx" \
-			-W "$(git-ls-tree "$ls" \
+			-W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \
 				| sed '/^100... blob /s,^.*	,,
 				       /^040000 tree /{
 				           s,^.*	,,
@@ -105,7 +110,7 @@ __git_complete_file ()
 			-- "$cur"))
 		;;
 	*)
-		COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+		COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 		;;
 	esac
 }
@@ -113,7 +118,7 @@ __git_complete_file ()
 __git_aliases ()
 {
 	local i IFS=$'\n'
-	for i in $(git repo-config --list); do
+	for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
 		case "$i" in
 		alias.*)
 			i="${i#alias.}"
@@ -125,7 +130,8 @@ __git_aliases ()
 
 __git_aliased_command ()
 {
-	local word cmdline=$(git repo-config --get "alias.$1")
+	local word cmdline=$(git --git-dir="$(__gitdir)" \
+		repo-config --get "alias.$1")
 	for word in $cmdline; do
 		if [ "${word##-*}" ]; then
 			echo $word
@@ -137,7 +143,7 @@ __git_aliased_command ()
 _git_branch ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
-	COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs .)" -- "$cur"))
+	COMPREPLY=($(compgen -W "-l -f -d -D $(__git_refs)" -- "$cur"))
 }
 
 _git_cat_file ()
@@ -159,7 +165,7 @@ _git_cat_file ()
 _git_checkout ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
-	COMPREPLY=($(compgen -W "-l -b $(__git_refs .)" -- "$cur"))
+	COMPREPLY=($(compgen -W "-l -b $(__git_refs)" -- "$cur"))
 }
 
 _git_diff ()
@@ -170,7 +176,7 @@ _git_diff ()
 _git_diff_tree ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
-	COMPREPLY=($(compgen -W "-r -p -M $(__git_refs .)" -- "$cur"))
+	COMPREPLY=($(compgen -W "-r -p -M $(__git_refs)" -- "$cur"))
 }
 
 _git_fetch ()
@@ -188,7 +194,7 @@ _git_fetch ()
 		case "$cur" in
 		*:*)
 	        cur=$(echo "$cur" | sed 's/^.*://')
-			COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+			COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 			;;
 		*)
 			local remote
@@ -221,10 +227,10 @@ _git_log ()
 	*..*)
 		local pfx=$(echo "$cur" | sed 's/\.\..*$/../')
 		cur=$(echo "$cur" | sed 's/^.*\.\.//')
-		COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs .)" -- "$cur"))
+		COMPREPLY=($(compgen -P "$pfx" -W "$(__git_refs)" -- "$cur"))
 		;;
 	*)
-		COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+		COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 		;;
 	esac
 }
@@ -232,7 +238,7 @@ _git_log ()
 _git_merge_base ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
-	COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+	COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 }
 
 _git_pull ()
@@ -280,7 +286,7 @@ _git_push ()
 			COMPREPLY=($(compgen -W "$(__git_refs "$remote")" -- "$cur"))
 			;;
 		*)
-			COMPREPLY=($(compgen -W "$(__git_refs2 .)" -- "$cur"))
+			COMPREPLY=($(compgen -W "$(__git_refs2)" -- "$cur"))
 			;;
 		esac
 		;;
@@ -291,56 +297,67 @@ _git_reset ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	local opt="--mixed --hard --soft"
-	COMPREPLY=($(compgen -W "$opt $(__git_refs .)" -- "$cur"))
+	COMPREPLY=($(compgen -W "$opt $(__git_refs)" -- "$cur"))
 }
 
 _git_show ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
-	COMPREPLY=($(compgen -W "$(__git_refs .)" -- "$cur"))
+	COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 }
 
 _git ()
 {
-	if [ $COMP_CWORD = 1 ]; then
+	local i c=1 command __git_dir
+
+	while [ $c -lt $COMP_CWORD ]; do
+		i="${COMP_WORDS[c]}"
+		case "$i" in
+		--git-dir=*) __git_dir="${i#--git-dir=}" ;;
+		--bare)      __git_dir="." ;;
+		--version|--help|-p|--paginate) ;;
+		*) command="$i"; break ;;
+		esac
+		c=$((++c))
+	done
+
+	if [ $c -eq $COMP_CWORD -a -z "$command" ]; then
 		COMPREPLY=($(compgen \
-			-W "--version $(git help -a|egrep '^ ') \
+			-W "--git-dir= --version \
+				$(git help -a|egrep '^ ') \
 			    $(__git_aliases)" \
 			-- "${COMP_WORDS[COMP_CWORD]}"))
-	else
-		local command="${COMP_WORDS[1]}"
-		local expansion=$(__git_aliased_command "$command")
+		return;
+	fi
 
-		if [ "$expansion" ]; then
-			command="$expansion"
-		fi
+	local expansion=$(__git_aliased_command "$command")
+	[ "$expansion" ] && command="$expansion"
 
-		case "$command" in
-		branch)      _git_branch ;;
-		cat-file)    _git_cat_file ;;
-		checkout)    _git_checkout ;;
-		diff)        _git_diff ;;
-		diff-tree)   _git_diff_tree ;;
-		fetch)       _git_fetch ;;
-		log)         _git_log ;;
-		ls-remote)   _git_ls_remote ;;
-		ls-tree)     _git_ls_tree ;;
-		merge-base)  _git_merge_base ;;
-		pull)        _git_pull ;;
-		push)        _git_push ;;
-		reset)       _git_reset ;;
-		show)        _git_show ;;
-		show-branch) _git_log ;;
-		whatchanged) _git_log ;;
-		*)           COMPREPLY=() ;;
-		esac
-	fi
+	case "$command" in
+	branch)      _git_branch ;;
+	cat-file)    _git_cat_file ;;
+	checkout)    _git_checkout ;;
+	diff)        _git_diff ;;
+	diff-tree)   _git_diff_tree ;;
+	fetch)       _git_fetch ;;
+	log)         _git_log ;;
+	ls-remote)   _git_ls_remote ;;
+	ls-tree)     _git_ls_tree ;;
+	merge-base)  _git_merge_base ;;
+	pull)        _git_pull ;;
+	push)        _git_push ;;
+	reset)       _git_reset ;;
+	show)        _git_show ;;
+	show-branch) _git_log ;;
+	whatchanged) _git_log ;;
+	*)           COMPREPLY=() ;;
+	esac
 }
 
 _gitk ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
-	COMPREPLY=($(compgen -W "--all $(__git_refs .)" -- "$cur"))
+	COMPREPLY=($(compgen -W "--all $(__git_refs)" -- "$cur"))
 }
 
 complete -o default -o nospace -F _git git
-- 
1.4.3.3.g9621
Message 1 of 1 in “Take --git-dir into consideration during bash completion.”
  1. 4/6 Take --git-dir into consideration during bash completion.Shawn O. Pearce, Nov 5, 2006

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.