Merge branch 'sg/completion-refs-speedup'

The refs completion for large number of refs has been sped up,
partly by giving up disambiguating ambiguous refs and partly by
eliminating most of the shell processing between 'git for-each-ref'
and 'ls-remote' and Bash's completion facility.

* sg/completion-refs-speedup:
  completion: speed up branch and tag completion
  completion: fill COMPREPLY directly when completing fetch refspecs
  completion: fill COMPREPLY directly when completing refs
  completion: let 'for-each-ref' sort remote branches for 'checkout' DWIMery
  completion: let 'for-each-ref' filter remote branches for 'checkout' DWIMery
  completion: let 'for-each-ref' strip the remote name from remote branches
  completion: let 'for-each-ref' and 'ls-remote' filter matching refs
  completion: don't disambiguate short refs
  completion: don't disambiguate tags and branches
  completion: support excluding full refs
  completion: support completing fully qualified non-fast-forward refspecs
  completion: support completing full refs after '--option=refs/<TAB>'
  completion: wrap __git_refs() for better option parsing
  completion: remove redundant __gitcomp_nl() options from _git_commit()
This commit is contained in:
Junio C Hamano
2017-03-30 14:07:14 -07:00
3 changed files with 577 additions and 71 deletions

View File

@ -213,6 +213,20 @@ _get_comp_words_by_ref ()
} }
fi fi
# Fills the COMPREPLY array with prefiltered words without any additional
# processing.
# Callers must take care of providing only words that match the current word
# to be completed and adding any prefix and/or suffix (trailing space!), if
# necessary.
# 1: List of newline-separated matching completion words, complete with
# prefix and suffix.
__gitcomp_direct ()
{
local IFS=$'\n'
COMPREPLY=($1)
}
__gitcompappend () __gitcompappend ()
{ {
local x i=${#COMPREPLY[@]} local x i=${#COMPREPLY[@]}
@ -338,14 +352,27 @@ __git_index_files ()
done | sort | uniq done | sort | uniq
} }
# Lists branches from the local repository.
# 1: A prefix to be added to each listed branch (optional).
# 2: List only branches matching this word (optional; list all branches if
# unset or empty).
# 3: A suffix to be appended to each listed branch (optional).
__git_heads () __git_heads ()
{ {
__git for-each-ref --format='%(refname:short)' refs/heads local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
"refs/heads/$cur_*" "refs/heads/$cur_*/**"
} }
# Lists tags from the local repository.
# Accepts the same positional parameters as __git_heads() above.
__git_tags () __git_tags ()
{ {
__git for-each-ref --format='%(refname:short)' refs/tags local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
"refs/tags/$cur_*" "refs/tags/$cur_*/**"
} }
# Lists refs from the local (by default) or from a remote repository. # Lists refs from the local (by default) or from a remote repository.
@ -354,11 +381,21 @@ __git_tags ()
# Can be the name of a configured remote, a path, or a URL. # Can be the name of a configured remote, a path, or a URL.
# 2: In addition to local refs, list unique branches from refs/remotes/ for # 2: In addition to local refs, list unique branches from refs/remotes/ for
# 'git checkout's tracking DWIMery (optional; ignored, if set but empty). # 'git checkout's tracking DWIMery (optional; ignored, if set but empty).
# 3: A prefix to be added to each listed ref (optional).
# 4: List only refs matching this word (optional; list all refs if unset or
# empty).
# 5: A suffix to be appended to each listed ref (optional; ignored, if set
# but empty).
#
# Use __git_complete_refs() instead.
__git_refs () __git_refs ()
{ {
local i hash dir track="${2-}" local i hash dir track="${2-}"
local list_refs_from=path remote="${1-}" local list_refs_from=path remote="${1-}"
local format refs pfx local format refs
local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
local match="${4-}"
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
__git_find_repo_path __git_find_repo_path
dir="$__git_repo_path" dir="$__git_repo_path"
@ -382,63 +419,78 @@ __git_refs ()
fi fi
if [ "$list_refs_from" = path ]; then if [ "$list_refs_from" = path ]; then
case "$cur" in if [[ "$cur_" == ^* ]]; then
pfx="$pfx^"
fer_pfx="$fer_pfx^"
cur_=${cur_#^}
match=${match#^}
fi
case "$cur_" in
refs|refs/*) refs|refs/*)
format="refname" format="refname"
refs="${cur%/*}" refs=("$match*" "$match*/**")
track="" track=""
;; ;;
*) *)
[[ "$cur" == ^* ]] && pfx="^"
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do
if [ -e "$dir/$i" ]; then echo $pfx$i; fi case "$i" in
$match*)
if [ -e "$dir/$i" ]; then
echo "$pfx$i$sfx"
fi
;;
esac
done done
format="refname:short" format="refname:strip=2"
refs="refs/tags refs/heads refs/remotes" refs=("refs/tags/$match*" "refs/tags/$match*/**"
"refs/heads/$match*" "refs/heads/$match*/**"
"refs/remotes/$match*" "refs/remotes/$match*/**")
;; ;;
esac esac
__git_dir="$dir" __git for-each-ref --format="$pfx%($format)" \ __git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
$refs "${refs[@]}"
if [ -n "$track" ]; then if [ -n "$track" ]; then
# employ the heuristic used by git checkout # employ the heuristic used by git checkout
# Try to find a remote branch that matches the completion word # Try to find a remote branch that matches the completion word
# but only output if the branch name is unique # but only output if the branch name is unique
local ref entry __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
__git for-each-ref --shell --format="ref=%(refname:short)" \ --sort="refname:strip=3" \
"refs/remotes/" | \ "refs/remotes/*/$match*" "refs/remotes/*/$match*/**" | \
while read -r entry; do uniq -u
eval "$entry"
ref="${ref#*/}"
if [[ "$ref" == "$cur"* ]]; then
echo "$ref"
fi
done | sort | uniq -u
fi fi
return return
fi fi
case "$cur" in case "$cur_" in
refs|refs/*) refs|refs/*)
__git ls-remote "$remote" "$cur*" | \ __git ls-remote "$remote" "$match*" | \
while read -r hash i; do while read -r hash i; do
case "$i" in case "$i" in
*^{}) ;; *^{}) ;;
*) echo "$i" ;; *) echo "$pfx$i$sfx" ;;
esac esac
done done
;; ;;
*) *)
if [ "$list_refs_from" = remote ]; then if [ "$list_refs_from" = remote ]; then
echo "HEAD" case "HEAD" in
__git for-each-ref --format="%(refname:short)" \ $match*) echo "${pfx}HEAD$sfx" ;;
"refs/remotes/$remote/" | sed -e "s#^$remote/##" esac
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
"refs/remotes/$remote/$match*" \
"refs/remotes/$remote/$match*/**"
else else
__git ls-remote "$remote" HEAD \ local query_symref
"refs/tags/*" "refs/heads/*" "refs/remotes/*" | case "HEAD" in
$match*) query_symref="HEAD" ;;
esac
__git ls-remote "$remote" $query_symref \
"refs/tags/$match*" "refs/heads/$match*" \
"refs/remotes/$match*" |
while read -r hash i; do while read -r hash i; do
case "$i" in case "$i" in
*^{}) ;; *^{}) ;;
refs/*) echo "${i#refs/*/}" ;; refs/*) echo "$pfx${i#refs/*/}$sfx" ;;
*) echo "$i" ;; # symbolic refs *) echo "$pfx$i$sfx" ;; # symbolic refs
esac esac
done done
fi fi
@ -446,7 +498,38 @@ __git_refs ()
esac esac
} }
# Completes refs, short and long, local and remote, symbolic and pseudo.
#
# Usage: __git_complete_refs [<option>]...
# --remote=<remote>: The remote to list refs from, can be the name of a
# configured remote, a path, or a URL.
# --track: List unique remote branches for 'git checkout's tracking DWIMery.
# --pfx=<prefix>: A prefix to be added to each ref.
# --cur=<word>: The current ref to be completed. Defaults to the current
# word to be completed.
# --sfx=<suffix>: A suffix to be appended to each ref instead of the default
# space.
__git_complete_refs ()
{
local remote track pfx cur_="$cur" sfx=" "
while test $# != 0; do
case "$1" in
--remote=*) remote="${1##--remote=}" ;;
--track) track="yes" ;;
--pfx=*) pfx="${1##--pfx=}" ;;
--cur=*) cur_="${1##--cur=}" ;;
--sfx=*) sfx="${1##--sfx=}" ;;
*) return 1 ;;
esac
shift
done
__gitcomp_direct "$(__git_refs "$remote" "$track" "$pfx" "$cur_" "$sfx")"
}
# __git_refs2 requires 1 argument (to pass to __git_refs) # __git_refs2 requires 1 argument (to pass to __git_refs)
# Deprecated: use __git_complete_fetch_refspecs() instead.
__git_refs2 () __git_refs2 ()
{ {
local i local i
@ -455,6 +538,24 @@ __git_refs2 ()
done done
} }
# Completes refspecs for fetching from a remote repository.
# 1: The remote repository.
# 2: A prefix to be added to each listed refspec (optional).
# 3: The ref to be completed as a refspec instead of the current word to be
# completed (optional)
# 4: A suffix to be appended to each listed refspec instead of the default
# space (optional).
__git_complete_fetch_refspecs ()
{
local i remote="$1" pfx="${2-}" cur_="${3-$cur}" sfx="${4- }"
__gitcomp_direct "$(
for i in $(__git_refs "$remote" "" "" "$cur_") ; do
echo "$pfx$i:$i$sfx"
done
)"
}
# __git_refs_remotes requires 1 argument (to pass to ls-remote) # __git_refs_remotes requires 1 argument (to pass to ls-remote)
__git_refs_remotes () __git_refs_remotes ()
{ {
@ -554,15 +655,15 @@ __git_complete_revlist_file ()
*...*) *...*)
pfx="${cur_%...*}..." pfx="${cur_%...*}..."
cur_="${cur_#*...}" cur_="${cur_#*...}"
__gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" __git_complete_refs --pfx="$pfx" --cur="$cur_"
;; ;;
*..*) *..*)
pfx="${cur_%..*}.." pfx="${cur_%..*}.."
cur_="${cur_#*..}" cur_="${cur_#*..}"
__gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" __git_complete_refs --pfx="$pfx" --cur="$cur_"
;; ;;
*) *)
__gitcomp_nl "$(__git_refs)" __git_complete_refs
;; ;;
esac esac
} }
@ -647,23 +748,23 @@ __git_complete_remote_or_refspec ()
case "$cmd" in case "$cmd" in
fetch) fetch)
if [ $lhs = 1 ]; then if [ $lhs = 1 ]; then
__gitcomp_nl "$(__git_refs2 "$remote")" "$pfx" "$cur_" __git_complete_fetch_refspecs "$remote" "$pfx" "$cur_"
else else
__gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" __git_complete_refs --pfx="$pfx" --cur="$cur_"
fi fi
;; ;;
pull|remote) pull|remote)
if [ $lhs = 1 ]; then if [ $lhs = 1 ]; then
__gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" __git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_"
else else
__gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" __git_complete_refs --pfx="$pfx" --cur="$cur_"
fi fi
;; ;;
push) push)
if [ $lhs = 1 ]; then if [ $lhs = 1 ]; then
__gitcomp_nl "$(__git_refs)" "$pfx" "$cur_" __git_complete_refs --pfx="$pfx" --cur="$cur_"
else else
__gitcomp_nl "$(__git_refs "$remote")" "$pfx" "$cur_" __git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_"
fi fi
;; ;;
esac esac
@ -1066,7 +1167,7 @@ _git_bisect ()
case "$subcommand" in case "$subcommand" in
bad|good|reset|skip|start) bad|good|reset|skip|start)
__gitcomp_nl "$(__git_refs)" __git_complete_refs
;; ;;
*) *)
;; ;;
@ -1088,7 +1189,7 @@ _git_branch ()
case "$cur" in case "$cur" in
--set-upstream-to=*) --set-upstream-to=*)
__gitcomp_nl "$(__git_refs)" "" "${cur##--set-upstream-to=}" __git_complete_refs --cur="${cur##--set-upstream-to=}"
;; ;;
--*) --*)
__gitcomp " __gitcomp "
@ -1101,9 +1202,9 @@ _git_branch ()
;; ;;
*) *)
if [ $only_local_ref = "y" -a $has_r = "n" ]; then if [ $only_local_ref = "y" -a $has_r = "n" ]; then
__gitcomp_nl "$(__git_heads)" __gitcomp_direct "$(__git_heads "" "$cur" " ")"
else else
__gitcomp_nl "$(__git_refs)" __git_complete_refs
fi fi
;; ;;
esac esac
@ -1146,18 +1247,18 @@ _git_checkout ()
*) *)
# check if --track, --no-track, or --no-guess was specified # check if --track, --no-track, or --no-guess was specified
# if so, disable DWIM mode # if so, disable DWIM mode
local flags="--track --no-track --no-guess" track=1 local flags="--track --no-track --no-guess" track_opt="--track"
if [ -n "$(__git_find_on_cmdline "$flags")" ]; then if [ -n "$(__git_find_on_cmdline "$flags")" ]; then
track='' track_opt=''
fi fi
__gitcomp_nl "$(__git_refs '' $track)" __git_complete_refs $track_opt
;; ;;
esac esac
} }
_git_cherry () _git_cherry ()
{ {
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_cherry_pick () _git_cherry_pick ()
@ -1172,7 +1273,7 @@ _git_cherry_pick ()
__gitcomp "--edit --no-commit --signoff --strategy= --mainline" __gitcomp "--edit --no-commit --signoff --strategy= --mainline"
;; ;;
*) *)
__gitcomp_nl "$(__git_refs)" __git_complete_refs
;; ;;
esac esac
} }
@ -1224,7 +1325,7 @@ _git_commit ()
{ {
case "$prev" in case "$prev" in
-c|-C) -c|-C)
__gitcomp_nl "$(__git_refs)" "" "${cur}" __git_complete_refs
return return
;; ;;
esac esac
@ -1237,7 +1338,7 @@ _git_commit ()
;; ;;
--reuse-message=*|--reedit-message=*|\ --reuse-message=*|--reedit-message=*|\
--fixup=*|--squash=*) --fixup=*|--squash=*)
__gitcomp_nl "$(__git_refs)" "" "${cur#*=}" __git_complete_refs --cur="${cur#*=}"
return return
;; ;;
--untracked-files=*) --untracked-files=*)
@ -1277,7 +1378,7 @@ _git_describe ()
" "
return return
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
__git_diff_algorithms="myers minimal patience histogram" __git_diff_algorithms="myers minimal patience histogram"
@ -1466,7 +1567,7 @@ _git_grep ()
;; ;;
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_help () _git_help ()
@ -1640,7 +1741,7 @@ _git_merge ()
--rerere-autoupdate --no-rerere-autoupdate --abort --continue" --rerere-autoupdate --no-rerere-autoupdate --abort --continue"
return return
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_mergetool () _git_mergetool ()
@ -1665,7 +1766,7 @@ _git_merge_base ()
return return
;; ;;
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_mv () _git_mv ()
@ -1703,7 +1804,7 @@ _git_notes ()
,*) ,*)
case "$prev" in case "$prev" in
--ref) --ref)
__gitcomp_nl "$(__git_refs)" __git_complete_refs
;; ;;
*) *)
__gitcomp "$subcommands --ref" __gitcomp "$subcommands --ref"
@ -1712,7 +1813,7 @@ _git_notes ()
;; ;;
add,--reuse-message=*|append,--reuse-message=*|\ add,--reuse-message=*|append,--reuse-message=*|\
add,--reedit-message=*|append,--reedit-message=*) add,--reedit-message=*|append,--reedit-message=*)
__gitcomp_nl "$(__git_refs)" "" "${cur#*=}" __git_complete_refs --cur="${cur#*=}"
;; ;;
add,--*|append,--*) add,--*|append,--*)
__gitcomp '--file= --message= --reedit-message= __gitcomp '--file= --message= --reedit-message=
@ -1731,7 +1832,7 @@ _git_notes ()
-m|-F) -m|-F)
;; ;;
*) *)
__gitcomp_nl "$(__git_refs)" __git_complete_refs
;; ;;
esac esac
;; ;;
@ -1769,10 +1870,10 @@ __git_complete_force_with_lease ()
--*=) --*=)
;; ;;
*:*) *:*)
__gitcomp_nl "$(__git_refs)" "" "${cur_#*:}" __git_complete_refs --cur="${cur_#*:}"
;; ;;
*) *)
__gitcomp_nl "$(__git_refs)" "" "$cur_" __git_complete_refs --cur="$cur_"
;; ;;
esac esac
} }
@ -1848,7 +1949,7 @@ _git_rebase ()
return return
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_reflog () _git_reflog ()
@ -1859,7 +1960,7 @@ _git_reflog ()
if [ -z "$subcommand" ]; then if [ -z "$subcommand" ]; then
__gitcomp "$subcommands" __gitcomp "$subcommands"
else else
__gitcomp_nl "$(__git_refs)" __git_complete_refs
fi fi
} }
@ -2005,7 +2106,7 @@ _git_config ()
return return
;; ;;
branch.*.merge) branch.*.merge)
__gitcomp_nl "$(__git_refs)" __git_complete_refs
return return
;; ;;
branch.*.rebase) branch.*.rebase)
@ -2109,7 +2210,7 @@ _git_config ()
;; ;;
branch.*) branch.*)
local pfx="${cur%.*}." cur_="${cur#*.}" local pfx="${cur%.*}." cur_="${cur#*.}"
__gitcomp_nl "$(__git_heads)" "$pfx" "$cur_" "." __gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")"
__gitcomp_nl_append $'autosetupmerge\nautosetuprebase\n' "$pfx" "$cur_" __gitcomp_nl_append $'autosetupmerge\nautosetuprebase\n' "$pfx" "$cur_"
return return
;; ;;
@ -2516,7 +2617,7 @@ _git_replace ()
return return
;; ;;
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_rerere () _git_rerere ()
@ -2540,7 +2641,7 @@ _git_reset ()
return return
;; ;;
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_revert () _git_revert ()
@ -2559,7 +2660,7 @@ _git_revert ()
return return
;; ;;
esac esac
__gitcomp_nl "$(__git_refs)" __git_complete_refs
} }
_git_rm () _git_rm ()
@ -2667,7 +2768,7 @@ _git_stash ()
;; ;;
branch,*) branch,*)
if [ $cword -eq 3 ]; then if [ $cword -eq 3 ]; then
__gitcomp_nl "$(__git_refs)"; __git_complete_refs
else else
__gitcomp_nl "$(__git stash list \ __gitcomp_nl "$(__git stash list \
| sed -n -e 's/:.*//p')" | sed -n -e 's/:.*//p')"
@ -2834,7 +2935,7 @@ _git_tag ()
i="${words[c]}" i="${words[c]}"
case "$i" in case "$i" in
-d|-v) -d|-v)
__gitcomp_nl "$(__git_tags)" __gitcomp_direct "$(__git_tags "" "$cur" " ")"
return return
;; ;;
-f) -f)
@ -2849,11 +2950,11 @@ _git_tag ()
;; ;;
-*|tag) -*|tag)
if [ $f = 1 ]; then if [ $f = 1 ]; then
__gitcomp_nl "$(__git_tags)" __gitcomp_direct "$(__git_tags "" "$cur" " ")"
fi fi
;; ;;
*) *)
__gitcomp_nl "$(__git_refs)" __git_complete_refs
;; ;;
esac esac
@ -3024,6 +3125,15 @@ if [[ -n ${ZSH_VERSION-} ]]; then
esac esac
} }
__gitcomp_direct ()
{
emulate -L zsh
local IFS=$'\n'
compset -P '*[=:]'
compadd -Q -- ${=1} && _ret=0
}
__gitcomp_nl () __gitcomp_nl ()
{ {
emulate -L zsh emulate -L zsh

View File

@ -67,6 +67,15 @@ __gitcomp ()
esac esac
} }
__gitcomp_direct ()
{
emulate -L zsh
local IFS=$'\n'
compset -P '*[=:]'
compadd -Q -- ${=1} && _ret=0
}
__gitcomp_nl () __gitcomp_nl ()
{ {
emulate -L zsh emulate -L zsh

View File

@ -400,6 +400,22 @@ test_expect_success '__gitdir - remote as argument' '
test_cmp expected "$actual" test_cmp expected "$actual"
' '
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_expect_success '__gitcomp - trailing space - options' '
test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message= test_gitcomp "--re" "--dry-run --reuse-message= --reedit-message=
--reset-author" <<-EOF --reset-author" <<-EOF
@ -555,6 +571,9 @@ test_expect_success '__git_refs - full refs' '
cat >expected <<-EOF && cat >expected <<-EOF &&
refs/heads/master refs/heads/master
refs/heads/matching-branch refs/heads/matching-branch
refs/remotes/other/branch-in-other
refs/remotes/other/master-in-other
refs/tags/matching-tag
EOF EOF
( (
cur=refs/heads/ && cur=refs/heads/ &&
@ -620,6 +639,7 @@ test_expect_success '__git_refs - configured remote' '
test_expect_success '__git_refs - configured remote - full refs' ' test_expect_success '__git_refs - configured remote - full refs' '
cat >expected <<-EOF && cat >expected <<-EOF &&
HEAD
refs/heads/branch-in-other refs/heads/branch-in-other
refs/heads/master-in-other refs/heads/master-in-other
refs/tags/tag-in-other refs/tags/tag-in-other
@ -648,6 +668,7 @@ test_expect_success '__git_refs - configured remote - repo given on the command
test_expect_success '__git_refs - configured remote - full refs - repo given on the command line' ' test_expect_success '__git_refs - configured remote - full refs - repo given on the command line' '
cat >expected <<-EOF && cat >expected <<-EOF &&
HEAD
refs/heads/branch-in-other refs/heads/branch-in-other
refs/heads/master-in-other refs/heads/master-in-other
refs/tags/tag-in-other refs/tags/tag-in-other
@ -692,6 +713,7 @@ test_expect_success '__git_refs - URL remote' '
test_expect_success '__git_refs - URL remote - full refs' ' test_expect_success '__git_refs - URL remote - full refs' '
cat >expected <<-EOF && cat >expected <<-EOF &&
HEAD
refs/heads/branch-in-other refs/heads/branch-in-other
refs/heads/master-in-other refs/heads/master-in-other
refs/tags/tag-in-other refs/tags/tag-in-other
@ -775,6 +797,371 @@ test_expect_success '__git_refs - unique remote branches for git checkout DWIMer
test_cmp expected "$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"
'
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
'
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"
'
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
'
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' ' test_expect_success 'teardown after ref completion' '
git branch -d matching-branch && git branch -d matching-branch &&
git tag -d matching-tag && git tag -d matching-tag &&