├── .github └── workflows │ └── ci.yml ├── Makefile ├── README.adoc ├── git-completion.plugin.zsh ├── src ├── _git ├── git-completion.bash └── git-prompt.sh ├── t ├── .gitignore ├── Makefile ├── completion-zsh.t ├── completion.t ├── lib-bash.sh ├── prompt.t ├── sharness.sh ├── test-lib.sh └── zsh │ ├── .gitignore │ └── .zshrc └── tools ├── converts.json ├── transplant └── update /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | test: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v4 11 | - name: Install zsh 12 | run: sudo apt-get install -y zsh 13 | - run: make test 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | completionsdir := $(HOME)/.local/share/bash-completion/completions 2 | sharedir := $(HOME)/.local/share/git-completion 3 | zshfuncdir := $(sharedir)/zsh 4 | 5 | all: 6 | 7 | test: 8 | $(MAKE) -C t 9 | 10 | D = $(DESTDIR) 11 | 12 | install: 13 | install -d -m 755 $(D)$(zshfuncdir) 14 | install -m 644 src/_git $(D)$(zshfuncdir)/_git 15 | install -d -m 755 $(D)$(completionsdir) 16 | install -m 644 src/git-completion.bash $(D)$(completionsdir)/git 17 | install -d -m 755 $(D)$(sharedir) 18 | install -m 644 src/git-prompt.sh $(D)$(sharedir)/prompt.sh 19 | 20 | .PHONY: all test install 21 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | This project is a friendly fork of the official Git completion 2 | (`contrib/completion`) and prompt scripts for Bash, Zsh, and possibly other 3 | shells. 4 | 5 | Most Git developers use the Bash shell, for which the completion scripts work 6 | rather well, however, Zsh is typically neglected. I've sent many patches to fix 7 | the issues, many have been merged, but many have been ignored, thus the need for 8 | a canonical location of a good, working Zsh completion. 9 | 10 | There are advantages for Bash users too. Currently the scripts under `contrib` are tied to the 11 | specific Git version, for example the completion scripts of version v2.40 12 | (https://git.kernel.org/pub/scm/git/git.git/plain/contrib/completion/git-completion.bash?h=v2.40.0[git-completion.bash]) 13 | have issues with older versions of Git (e.g. v2.33); the ones in 14 | this project don't. 15 | 16 | With `git-completion` you can be sure you are using the latest completion that 17 | works in both shells, and any Git version. 18 | 19 | This is a sister project of the 20 | https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/gitfast[Oh My Zsh 21 | gitfast] plugin (that I also maintain), which has similar needs. 22 | 23 | == Installation == 24 | 25 | * https://github.com/felipec/git-completion/wiki/Bash[Bash instructions] 26 | * https://github.com/felipec/git-completion/wiki/Zsh[Zsh instructions] 27 | 28 | == Improvements from upstream == 29 | 30 | This is a short list of the benefits you get: 31 | 32 | * Easier installation 33 | * Tons of bug fixes 34 | * Works with older versions of git 35 | * Zsh: much more options 36 | * Zsh: quoting works properly 37 | * Zsh: automatic suffix removal 38 | 39 | For a full list of all the patches on top of upstream git check 40 | https://github.com/felipec/git-completion/wiki/Patches[Patches]. 41 | -------------------------------------------------------------------------------- /git-completion.plugin.zsh: -------------------------------------------------------------------------------- 1 | 0="${${ZERO:-${0:#$ZSH_ARGZERO}}:-${(%):-%N}}" 2 | 0="${${(M)0:#/*}:-$PWD/$0}" 3 | 4 | fpath=("${0:A:h}/src" $fpath) 5 | source "${0:A:h}/src/git-prompt.sh" 6 | -------------------------------------------------------------------------------- /src/_git: -------------------------------------------------------------------------------- 1 | #compdef git gitk 2 | 3 | # zsh completion wrapper for git 4 | # 5 | # Copyright (c) 2012-2024 Felipe Contreras 6 | # 7 | # The recommended way to use this script is to prepend its location to your $fpath: 8 | # 9 | # fpath=($git_completion_srcdir $fpath) 10 | # 11 | 12 | zstyle -T ':completion:*:*:git:*' tag-order && \ 13 | zstyle ':completion:*:*:git:*' tag-order 'common-commands' 14 | 15 | zstyle -s ":completion:*:*:git:*" script script 16 | if [ -z "$script" ]; then 17 | local -a locations 18 | local e bash_completion 19 | 20 | bash_completion=$(pkg-config --variable=completionsdir bash-completion 2>/dev/null) || 21 | bash_completion='/usr/share/bash-completion/completions/' 22 | 23 | locations=( 24 | "${${funcsourcetrace[1]%:*}:A:h}"/git-completion.bash 25 | "$HOME/.local/share/bash-completion/completions/git" 26 | '/usr/local/share/bash-completion/completions/git' 27 | "$bash_completion/git" 28 | '/etc/bash_completion.d/git' # old debian 29 | ) 30 | for e in $locations; do 31 | test -f $e && script="$e" && break 32 | done 33 | fi 34 | 35 | local old_complete="$functions[complete]" 36 | functions[complete]=: 37 | COMP_WORDBREAKS=':' 38 | GIT_SOURCING_ZSH_COMPLETION=y . "$script" 39 | functions[complete]="$old_complete" 40 | 41 | __gitcompadd () 42 | { 43 | compadd -p "${2-}" -S "${3- }" -q -- ${=1} && _ret=0 44 | } 45 | 46 | __gitcomp () 47 | { 48 | emulate -L zsh 49 | 50 | IFS=$' \t\n' __gitcompadd "$1" "${2-}" "${4- }" 51 | } 52 | 53 | __gitcomp_opts () 54 | { 55 | emulate -L zsh 56 | 57 | local cur_="${3-$cur}" 58 | 59 | [[ "$cur_" == *= ]] && return 60 | 61 | local c IFS=$' \t\n' sfx 62 | for c in ${=1}; do 63 | if [[ $c == "--" ]]; then 64 | [[ "$cur_" == --no-* ]] && continue 65 | __gitcompadd "--no-..." 66 | break 67 | fi 68 | 69 | if [[ -z "${4+set}" ]]; then 70 | case $c in 71 | *=) c="${c%=}"; sfx="=" ;; 72 | *.) sfx="" ;; 73 | *) sfx=" " ;; 74 | esac 75 | else 76 | sfx="$4" 77 | fi 78 | __gitcompadd "$c" "${2-}" "$sfx" 79 | done 80 | } 81 | 82 | __gitcomp_nl () 83 | { 84 | emulate -L zsh 85 | 86 | # words that don't end up in space 87 | compadd -p "${2-}" -S "${4- }" -q -- ${${(f)1}:#*\ } && _ret=0 88 | # words that end in space 89 | compadd -p "${2-}" -S " ${4- }" -q -- ${${(M)${(f)1}:#*\ }% } && _ret=0 90 | } 91 | 92 | __gitcomp_file () 93 | { 94 | emulate -L zsh 95 | 96 | compadd -f -p "${2-}" -- ${(f)1} && _ret=0 97 | } 98 | 99 | __gitcomp_direct () 100 | { 101 | __gitcomp_nl "$1" "" "" "" 102 | } 103 | 104 | __gitcomp_file_direct () 105 | { 106 | __gitcomp_file "$1" "" 107 | } 108 | 109 | __git_complete_command () 110 | { 111 | emulate -L zsh 112 | 113 | compset -P '*[=:]' 114 | 115 | local command="$1" 116 | local completion_func="_git_${command//-/_}" 117 | if (( $+functions[$completion_func] )); then 118 | emulate ksh -c $completion_func 119 | return 0 120 | elif emulate ksh -c "__git_support_parseopt_helper $command"; then 121 | emulate ksh -c "__git_complete_common $command" 122 | return 0 123 | else 124 | return 1 125 | fi 126 | } 127 | 128 | __git_zsh_bash_func () 129 | { 130 | emulate -L ksh 131 | 132 | local command=$1 133 | 134 | __git_complete_command "$command" && return 135 | 136 | local expansion=$(__git_aliased_command "$command") 137 | if [ -n "$expansion" ]; then 138 | words[1]=$expansion 139 | __git_complete_command "$expansion" 140 | fi 141 | } 142 | 143 | __git_zsh_cmd_common () 144 | { 145 | local -a list 146 | list=( 147 | add:'add file contents to the index' 148 | bisect:'find by binary search the change that introduced a bug' 149 | branch:'list, create, or delete branches' 150 | checkout:'checkout a branch or paths to the working tree' 151 | clone:'clone a repository into a new directory' 152 | commit:'record changes to the repository' 153 | diff:'show changes between commits, commit and working tree, etc' 154 | fetch:'download objects and refs from another repository' 155 | grep:'print lines matching a pattern' 156 | init:'create an empty Git repository or reinitialize an existing one' 157 | log:'show commit logs' 158 | merge:'join two or more development histories together' 159 | mv:'move or rename a file, a directory, or a symlink' 160 | pull:'fetch from and merge with another repository or a local branch' 161 | push:'update remote refs along with associated objects' 162 | rebase:'forward-port local commits to the updated upstream head' 163 | reset:'reset current HEAD to the specified state' 164 | restore:'restore working tree files' 165 | rm:'remove files from the working tree and from the index' 166 | show:'show various types of objects' 167 | status:'show the working tree status' 168 | switch:'switch branches' 169 | tag:'create, list, delete or verify a tag object signed with GPG') 170 | _describe -t common-commands 'common commands' list && _ret=0 171 | } 172 | 173 | __git_zsh_cmd_alias () 174 | { 175 | local -a list 176 | list=(${${(0)"$(git config -z --get-regexp '^alias\.*')"}#alias.}) 177 | list=(${(f)"$(printf "%s:alias for '%s'\n" ${(f@)list})"}) 178 | _describe -t alias-commands 'aliases' list && _ret=0 179 | } 180 | 181 | __git_zsh_cmd_all () 182 | { 183 | local -a list 184 | emulate ksh -c __git_compute_all_commands 185 | list=( ${=__git_all_commands} ) 186 | _describe -t all-commands 'all commands' list && _ret=0 187 | } 188 | 189 | __git_zsh_main () 190 | { 191 | local curcontext="$curcontext" state state_descr line 192 | typeset -A opt_args 193 | local -a __git_C_args 194 | 195 | _arguments -C \ 196 | '(-p --paginate -P --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \ 197 | '(-p --paginate -P --no-pager)'{-P,--no-pager}'[do not pipe git output into a pager]' \ 198 | '(--bare)--git-dir=[set the path to the repository]: :_directories' \ 199 | '(--git-dir)--bare[treat the repository as a bare repository]' \ 200 | '(- :)--version[prints the git suite version]' \ 201 | '--exec-path=[path to where your core git programs are installed]: :_directories' \ 202 | '(- :)--exec-path[print the path where your core git programs are installed]' \ 203 | '(- :)--html-path[print the path where git''s HTML documentation is installed]' \ 204 | '(- :)--info-path[print the path where the Info files are installed]' \ 205 | '(- :)--man-path[print the manpath (see `man(1)`) for the man pages]' \ 206 | '--work-tree=[set the path to the working tree]: :_directories' \ 207 | '--namespace=[set the git namespace]:' \ 208 | '--no-replace-objects[do not use replacement refs to replace git objects]' \ 209 | '(- :)--help[prints the synopsis and a list of the most commonly used commands]: :->arg' \ 210 | '*-C[run as if git was started in the given path]: :_directories' \ 211 | '*-c[pass a configuration parameter to the command]: :->config' \ 212 | '(-): :->command' \ 213 | '(-)*:: :->arg' && return 214 | 215 | case $state in 216 | (command) 217 | _tags common-commands alias-commands all-commands 218 | while _tags; do 219 | _requested common-commands && __git_zsh_cmd_common 220 | _requested alias-commands && __git_zsh_cmd_alias 221 | _requested all-commands && __git_zsh_cmd_all 222 | let _ret || break 223 | done 224 | ;; 225 | (config) 226 | compset -P '*[=:]' 227 | emulate ksh -c __git_complete_config_variable_name_and_value 228 | ;; 229 | (arg) 230 | local command="${words[1]}" __git_dir __git_cmd_idx=1 231 | 232 | if (( $+opt_args[--bare] )); then 233 | __git_dir='.' 234 | else 235 | __git_dir=${~opt_args[--git-dir]} 236 | fi 237 | 238 | for x in ${(s.:.)opt_args[-C]}; do 239 | __git_C_args+=('-C' ${~x}) 240 | done 241 | 242 | (( $+opt_args[--help] )) && command='help' 243 | 244 | words=( git ${words[@]} ) 245 | 246 | __git_zsh_bash_func $command 247 | ;; 248 | esac 249 | } 250 | 251 | _git () 252 | { 253 | local _ret=1 254 | local cur cword prev __git_cmd_idx=0 255 | 256 | cur=${words[CURRENT]} 257 | prev=${words[CURRENT-1]} 258 | let cword=CURRENT-1 259 | 260 | if (( $+functions[__${service}_zsh_main] )); then 261 | __${service}_zsh_main 262 | elif (( $+functions[__${service}_main] )); then 263 | emulate ksh -c __${service}_main 264 | elif (( $+functions[_${service}] )); then 265 | emulate ksh -c _${service} 266 | elif (( $+functions[_${service//-/_}] )); then 267 | emulate ksh -c _${service//-/_} 268 | fi 269 | 270 | let _ret && _default && _ret=0 271 | return _ret 272 | } 273 | 274 | _git 275 | -------------------------------------------------------------------------------- /src/git-prompt.sh: -------------------------------------------------------------------------------- 1 | # bash/zsh git prompt support 2 | # 3 | # Copyright (C) 2006,2007 Shawn O. Pearce 4 | # Distributed under the GNU General Public License, version 2.0. 5 | # 6 | # This script allows you to see repository status in your prompt. 7 | # 8 | # To enable: 9 | # 10 | # 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh). 11 | # 2) Add the following line to your .bashrc/.zshrc: 12 | # source ~/.git-prompt.sh 13 | # 3a) Change your PS1 to call __git_ps1 as 14 | # command-substitution: 15 | # Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' 16 | # ZSH: setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ ' 17 | # the optional argument will be used as format string. 18 | # 3b) Alternatively, for a slightly faster prompt, __git_ps1 can 19 | # be used for PROMPT_COMMAND in Bash or for precmd() in Zsh 20 | # with two parameters,
 and , which are strings
 21 | #        you would put in $PS1 before and after the status string
 22 | #        generated by the git-prompt machinery.  e.g.
 23 | #        Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "'
 24 | #          will show username, at-sign, host, colon, cwd, then
 25 | #          various status string, followed by dollar and SP, as
 26 | #          your prompt.
 27 | #        ZSH:  precmd () { __git_ps1 "%n" ":%~$ " "|%s" }
 28 | #          will show username, pipe, then various status string,
 29 | #          followed by colon, cwd, dollar and SP, as your prompt.
 30 | #        Optionally, you can supply a third argument with a printf
 31 | #        format string to finetune the output of the branch status
 32 | #
 33 | # The repository status will be displayed only if you are currently in a
 34 | # git repository. The %s token is the placeholder for the shown status.
 35 | #
 36 | # The prompt status always includes the current branch name.
 37 | #
 38 | # In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value,
 39 | # unstaged (*) and staged (+) changes will be shown next to the branch
 40 | # name.  You can configure this per-repository with the
 41 | # bash.showDirtyState variable, which defaults to true once
 42 | # GIT_PS1_SHOWDIRTYSTATE is enabled.
 43 | #
 44 | # You can also see if currently something is stashed, by setting
 45 | # GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed,
 46 | # then a '$' will be shown next to the branch name.
 47 | #
 48 | # If you would like to see if there're untracked files, then you can set
 49 | # GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked
 50 | # files, then a '%' will be shown next to the branch name.  You can
 51 | # configure this per-repository with the bash.showUntrackedFiles
 52 | # variable, which defaults to true once GIT_PS1_SHOWUNTRACKEDFILES is
 53 | # enabled.
 54 | #
 55 | # If you would like to see the difference between HEAD and its upstream,
 56 | # set GIT_PS1_SHOWUPSTREAM="auto".  A "<" indicates you are behind, ">"
 57 | # indicates you are ahead, "<>" indicates you have diverged and "="
 58 | # indicates that there is no difference. You can further control
 59 | # behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list
 60 | # of values:
 61 | #
 62 | #     verbose       show number of commits ahead/behind (+/-) upstream
 63 | #     name          if verbose, then also show the upstream abbrev name
 64 | #     legacy        don't use the '--count' option available in recent
 65 | #                   versions of git-rev-list
 66 | #     git           always compare HEAD to @{upstream}
 67 | #     svn           always compare HEAD to your SVN upstream
 68 | #
 69 | # By default, __git_ps1 will compare HEAD to your SVN upstream if it can
 70 | # find one, or @{upstream} otherwise.  Once you have set
 71 | # GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by
 72 | # setting the bash.showUpstream config variable.
 73 | #
 74 | # You can change the separator between the branch name and the above
 75 | # state symbols by setting GIT_PS1_STATESEPARATOR. The default separator
 76 | # is SP.
 77 | #
 78 | # When there is an in-progress operation such as a merge, rebase,
 79 | # revert, cherry-pick, or bisect, the prompt will include information
 80 | # related to the operation, often in the form "|".
 81 | #
 82 | # When the repository has a sparse-checkout, a notification of the form
 83 | # "|SPARSE" will be included in the prompt.  This can be shortened to a
 84 | # single '?' character by setting GIT_PS1_COMPRESSSPARSESTATE, or omitted
 85 | # by setting GIT_PS1_OMITSPARSESTATE.
 86 | #
 87 | # If you would like to see a notification on the prompt when there are
 88 | # unresolved conflicts, set GIT_PS1_SHOWCONFLICTSTATE to "yes". The
 89 | # prompt will include "|CONFLICT".
 90 | #
 91 | # If you would like to see more information about the identity of
 92 | # commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE
 93 | # to one of these values:
 94 | #
 95 | #     contains      relative to newer annotated tag (v1.6.3.2~35)
 96 | #     branch        relative to newer tag or branch (master~4)
 97 | #     describe      relative to older annotated tag (v1.6.3.1-13-gdd42c2f)
 98 | #     tag           relative to any older tag (v1.6.3.1-13-gdd42c2f)
 99 | #     default       exactly matching tag
100 | #
101 | # If you would like a colored hint about the current dirty state, set
102 | # GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on
103 | # the colored output of "git status -sb".
104 | #
105 | # If you would like __git_ps1 to do nothing in the case when the current
106 | # directory is set up to be ignored by git, then set
107 | # GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the
108 | # repository level by setting bash.hideIfPwdIgnored to "false".
109 | 
110 | # check whether printf supports -v
111 | __git_printf_supports_v=
112 | printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1
113 | 
114 | # stores the divergence from upstream in $p
115 | # used by GIT_PS1_SHOWUPSTREAM
116 | __git_ps1_show_upstream ()
117 | {
118 | 	local key value
119 | 	local svn_remote svn_url_pattern count n
120 | 	local upstream_type=git legacy="" verbose="" name=""
121 | 
122 | 	svn_remote=()
123 | 	# get some config options from git-config
124 | 	local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')"
125 | 	while read -r key value; do
126 | 		case "$key" in
127 | 		bash.showupstream)
128 | 			GIT_PS1_SHOWUPSTREAM="$value"
129 | 			if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then
130 | 				p=""
131 | 				return
132 | 			fi
133 | 			;;
134 | 		svn-remote.*.url)
135 | 			svn_remote[$((${#svn_remote[@]} + 1))]="$value"
136 | 			svn_url_pattern="$svn_url_pattern\\|$value"
137 | 			upstream_type=svn+git # default upstream type is SVN if available, else git
138 | 			;;
139 | 		esac
140 | 	done <<< "$output"
141 | 
142 | 	# parse configuration values
143 | 	local option
144 | 	for option in ${GIT_PS1_SHOWUPSTREAM}; do
145 | 		case "$option" in
146 | 		git|svn) upstream_type="$option" ;;
147 | 		verbose) verbose=1 ;;
148 | 		legacy)  legacy=1  ;;
149 | 		name)    name=1 ;;
150 | 		esac
151 | 	done
152 | 
153 | 	# Find our upstream type
154 | 	case "$upstream_type" in
155 | 	git)    upstream_type="@{upstream}" ;;
156 | 	svn*)
157 | 		# get the upstream from the "git-svn-id: ..." in a commit message
158 | 		# (git-svn uses essentially the same procedure internally)
159 | 		local -a svn_upstream
160 | 		svn_upstream=($(git log --first-parent -1 \
161 | 					--grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null))
162 | 		if [[ 0 -ne ${#svn_upstream[@]} ]]; then
163 | 			svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]}
164 | 			svn_upstream=${svn_upstream%@*}
165 | 			local n_stop="${#svn_remote[@]}"
166 | 			for ((n=1; n <= n_stop; n++)); do
167 | 				svn_upstream=${svn_upstream#${svn_remote[$n]}}
168 | 			done
169 | 
170 | 			if [[ -z "$svn_upstream" ]]; then
171 | 				# default branch name for checkouts with no layout:
172 | 				upstream_type=${GIT_SVN_ID:-git-svn}
173 | 			else
174 | 				upstream_type=${svn_upstream#/}
175 | 			fi
176 | 		elif [[ "svn+git" = "$upstream_type" ]]; then
177 | 			upstream_type="@{upstream}"
178 | 		fi
179 | 		;;
180 | 	esac
181 | 
182 | 	# Find how many commits we are ahead/behind our upstream
183 | 	if [[ -z "$legacy" ]]; then
184 | 		count="$(git rev-list --count --left-right \
185 | 				"$upstream_type"...HEAD 2>/dev/null)"
186 | 	else
187 | 		# produce equivalent output to --count for older versions of git
188 | 		local commits
189 | 		if commits="$(git rev-list --left-right "$upstream_type"...HEAD 2>/dev/null)"
190 | 		then
191 | 			local commit behind=0 ahead=0
192 | 			for commit in $commits
193 | 			do
194 | 				case "$commit" in
195 | 				"<"*) ((behind++)) ;;
196 | 				*)    ((ahead++))  ;;
197 | 				esac
198 | 			done
199 | 			count="$behind	$ahead"
200 | 		else
201 | 			count=""
202 | 		fi
203 | 	fi
204 | 
205 | 	# calculate the result
206 | 	if [[ -z "$verbose" ]]; then
207 | 		case "$count" in
208 | 		"") # no upstream
209 | 			p="" ;;
210 | 		"0	0") # equal to upstream
211 | 			p="=" ;;
212 | 		"0	"*) # ahead of upstream
213 | 			p=">" ;;
214 | 		*"	0") # behind upstream
215 | 			p="<" ;;
216 | 		*)	    # diverged from upstream
217 | 			p="<>" ;;
218 | 		esac
219 | 	else # verbose, set upstream instead of p
220 | 		case "$count" in
221 | 		"") # no upstream
222 | 			upstream="" ;;
223 | 		"0	0") # equal to upstream
224 | 			upstream="|u=" ;;
225 | 		"0	"*) # ahead of upstream
226 | 			upstream="|u+${count#0	}" ;;
227 | 		*"	0") # behind upstream
228 | 			upstream="|u-${count%	0}" ;;
229 | 		*)	    # diverged from upstream
230 | 			upstream="|u+${count#*	}-${count%	*}" ;;
231 | 		esac
232 | 		if [[ -n "$count" && -n "$name" ]]; then
233 | 			__git_ps1_upstream_name=$(git rev-parse \
234 | 				--abbrev-ref "$upstream_type" 2>/dev/null)
235 | 			if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
236 | 				upstream="$upstream \${__git_ps1_upstream_name}"
237 | 			else
238 | 				upstream="$upstream ${__git_ps1_upstream_name}"
239 | 				# not needed anymore; keep user's
240 | 				# environment clean
241 | 				unset __git_ps1_upstream_name
242 | 			fi
243 | 		fi
244 | 	fi
245 | 
246 | }
247 | 
248 | # Helper function that is meant to be called from __git_ps1.  It
249 | # injects color codes into the appropriate gitstring variables used
250 | # to build a gitstring. Colored variables are responsible for clearing
251 | # their own color.
252 | __git_ps1_colorize_gitstring ()
253 | {
254 | 	if [[ -n ${ZSH_VERSION-} ]]; then
255 | 		local c_red='%F{red}'
256 | 		local c_green='%F{green}'
257 | 		local c_lblue='%F{blue}'
258 | 		local c_clear='%f'
259 | 	else
260 | 		# Using \001 and \002 around colors is necessary to prevent
261 | 		# issues with command line editing/browsing/completion!
262 | 		local c_red=$'\001\e[31m\002'
263 | 		local c_green=$'\001\e[32m\002'
264 | 		local c_lblue=$'\001\e[1;34m\002'
265 | 		local c_clear=$'\001\e[0m\002'
266 | 	fi
267 | 	local bad_color=$c_red
268 | 	local ok_color=$c_green
269 | 	local flags_color="$c_lblue"
270 | 
271 | 	local branch_color=""
272 | 	if [ $detached = no ]; then
273 | 		branch_color="$ok_color"
274 | 	else
275 | 		branch_color="$bad_color"
276 | 	fi
277 | 	if [ -n "$c" ]; then
278 | 		c="$branch_color$c$c_clear"
279 | 	fi
280 | 	b="$branch_color$b$c_clear"
281 | 
282 | 	if [ -n "$w" ]; then
283 | 		w="$bad_color$w$c_clear"
284 | 	fi
285 | 	if [ -n "$i" ]; then
286 | 		i="$ok_color$i$c_clear"
287 | 	fi
288 | 	if [ -n "$s" ]; then
289 | 		s="$flags_color$s$c_clear"
290 | 	fi
291 | 	if [ -n "$u" ]; then
292 | 		u="$bad_color$u$c_clear"
293 | 	fi
294 | }
295 | 
296 | # Helper function to read the first line of a file into a variable.
297 | # __git_eread requires 2 arguments, the file path and the name of the
298 | # variable, in that order.
299 | __git_eread ()
300 | {
301 | 	test -r "$1" && IFS=$'\r\n' read "$2" <"$1"
302 | }
303 | 
304 | # see if a cherry-pick or revert is in progress, if the user has committed a
305 | # conflict resolution with 'git commit' in the middle of a sequence of picks or
306 | # reverts then CHERRY_PICK_HEAD/REVERT_HEAD will not exist so we have to read
307 | # the todo file.
308 | __git_sequencer_status ()
309 | {
310 | 	local todo
311 | 	if test -f "$g/CHERRY_PICK_HEAD"
312 | 	then
313 | 		r="|CHERRY-PICKING"
314 | 		return 0;
315 | 	elif test -f "$g/REVERT_HEAD"
316 | 	then
317 | 		r="|REVERTING"
318 | 		return 0;
319 | 	elif __git_eread "$g/sequencer/todo" todo
320 | 	then
321 | 		case "$todo" in
322 | 		p[\ \	]|pick[\ \	]*)
323 | 			r="|CHERRY-PICKING"
324 | 			return 0
325 | 		;;
326 | 		revert[\ \	]*)
327 | 			r="|REVERTING"
328 | 			return 0
329 | 		;;
330 | 		esac
331 | 	fi
332 | 	return 1
333 | }
334 | 
335 | # __git_ps1 accepts 0 or 1 arguments (i.e., format string)
336 | # when called from PS1 using command substitution
337 | # in this mode it prints text to add to bash PS1 prompt (includes branch name)
338 | #
339 | # __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc)
340 | # in that case it _sets_ PS1. The arguments are parts of a PS1 string.
341 | # when two arguments are given, the first is prepended and the second appended
342 | # to the state string when assigned to PS1.
343 | # The optional third parameter will be used as printf format string to further
344 | # customize the output of the git-status string.
345 | # In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true
346 | __git_ps1 ()
347 | {
348 | 	# preserve exit status
349 | 	local exit=$?
350 | 	local pcmode=no
351 | 	local detached=no
352 | 	local ps1pc_start='\u@\h:\w '
353 | 	local ps1pc_end='\$ '
354 | 	local printf_format=' (%s)'
355 | 
356 | 	case "$#" in
357 | 		2|3)	pcmode=yes
358 | 			ps1pc_start="$1"
359 | 			ps1pc_end="$2"
360 | 			printf_format="${3:-$printf_format}"
361 | 			# set PS1 to a plain prompt so that we can
362 | 			# simply return early if the prompt should not
363 | 			# be decorated
364 | 			PS1="$ps1pc_start$ps1pc_end"
365 | 		;;
366 | 		0|1)	printf_format="${1:-$printf_format}"
367 | 		;;
368 | 		*)	return $exit
369 | 		;;
370 | 	esac
371 | 
372 | 	# ps1_expanded:  This variable is set to 'yes' if the shell
373 | 	# subjects the value of PS1 to parameter expansion:
374 | 	#
375 | 	#   * bash does unless the promptvars option is disabled
376 | 	#   * zsh does not unless the PROMPT_SUBST option is set
377 | 	#   * POSIX shells always do
378 | 	#
379 | 	# If the shell would expand the contents of PS1 when drawing
380 | 	# the prompt, a raw ref name must not be included in PS1.
381 | 	# This protects the user from arbitrary code execution via
382 | 	# specially crafted ref names.  For example, a ref named
383 | 	# 'refs/heads/$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' might cause the
384 | 	# shell to execute 'sudo rm -rf /' when the prompt is drawn.
385 | 	#
386 | 	# Instead, the ref name should be placed in a separate global
387 | 	# variable (in the __git_ps1_* namespace to avoid colliding
388 | 	# with the user's environment) and that variable should be
389 | 	# referenced from PS1.  For example:
390 | 	#
391 | 	#     __git_ps1_foo=$(do_something_to_get_ref_name)
392 | 	#     PS1="...stuff...\${__git_ps1_foo}...stuff..."
393 | 	#
394 | 	# If the shell does not expand the contents of PS1, the raw
395 | 	# ref name must be included in PS1.
396 | 	#
397 | 	# The value of this variable is only relevant when in pcmode.
398 | 	#
399 | 	# Assume that the shell follows the POSIX specification and
400 | 	# expands PS1 unless determined otherwise.  (This is more
401 | 	# likely to be correct if the user has a non-bash, non-zsh
402 | 	# shell and safer than the alternative if the assumption is
403 | 	# incorrect.)
404 | 	#
405 | 	local ps1_expanded=yes
406 | 	[ -z "${ZSH_VERSION-}" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no
407 | 	[ -z "${BASH_VERSION-}" ] || shopt -q promptvars || ps1_expanded=no
408 | 
409 | 	local repo_info rev_parse_exit_code
410 | 	repo_info="$(git rev-parse --git-dir --is-inside-git-dir \
411 | 		--is-bare-repository --is-inside-work-tree \
412 | 		--short HEAD 2>/dev/null)"
413 | 	rev_parse_exit_code="$?"
414 | 
415 | 	if [ -z "$repo_info" ]; then
416 | 		return $exit
417 | 	fi
418 | 
419 | 	local short_sha=""
420 | 	if [ "$rev_parse_exit_code" = "0" ]; then
421 | 		short_sha="${repo_info##*$'\n'}"
422 | 		repo_info="${repo_info%$'\n'*}"
423 | 	fi
424 | 	local inside_worktree="${repo_info##*$'\n'}"
425 | 	repo_info="${repo_info%$'\n'*}"
426 | 	local bare_repo="${repo_info##*$'\n'}"
427 | 	repo_info="${repo_info%$'\n'*}"
428 | 	local inside_gitdir="${repo_info##*$'\n'}"
429 | 	local g="${repo_info%$'\n'*}"
430 | 
431 | 	if [ "true" = "$inside_worktree" ] &&
432 | 	   [ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] &&
433 | 	   [ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] &&
434 | 	   git check-ignore -q .
435 | 	then
436 | 		return $exit
437 | 	fi
438 | 
439 | 	local sparse=""
440 | 	if [ -z "${GIT_PS1_COMPRESSSPARSESTATE-}" ] &&
441 | 	   [ -z "${GIT_PS1_OMITSPARSESTATE-}" ] &&
442 | 	   [ "$(git config --bool core.sparseCheckout)" = "true" ]; then
443 | 		sparse="|SPARSE"
444 | 	fi
445 | 
446 | 	local r=""
447 | 	local b=""
448 | 	local step=""
449 | 	local total=""
450 | 	if [ -d "$g/rebase-merge" ]; then
451 | 		__git_eread "$g/rebase-merge/head-name" b
452 | 		__git_eread "$g/rebase-merge/msgnum" step
453 | 		__git_eread "$g/rebase-merge/end" total
454 | 		r="|REBASE"
455 | 	else
456 | 		if [ -d "$g/rebase-apply" ]; then
457 | 			__git_eread "$g/rebase-apply/next" step
458 | 			__git_eread "$g/rebase-apply/last" total
459 | 			if [ -f "$g/rebase-apply/rebasing" ]; then
460 | 				__git_eread "$g/rebase-apply/head-name" b
461 | 				r="|REBASE"
462 | 			elif [ -f "$g/rebase-apply/applying" ]; then
463 | 				r="|AM"
464 | 			else
465 | 				r="|AM/REBASE"
466 | 			fi
467 | 		elif [ -f "$g/MERGE_HEAD" ]; then
468 | 			r="|MERGING"
469 | 		elif __git_sequencer_status; then
470 | 			:
471 | 		elif [ -f "$g/BISECT_LOG" ]; then
472 | 			r="|BISECTING"
473 | 		fi
474 | 
475 | 		if [ -n "$b" ]; then
476 | 			:
477 | 		elif [ -h "$g/HEAD" ]; then
478 | 			# symlink symbolic ref
479 | 			b="$(git symbolic-ref HEAD 2>/dev/null)"
480 | 		else
481 | 			local head=""
482 | 			if ! __git_eread "$g/HEAD" head; then
483 | 				return $exit
484 | 			fi
485 | 			# is it a symbolic ref?
486 | 			b="${head#ref: }"
487 | 			if [ "$head" = "$b" ]; then
488 | 				detached=yes
489 | 				b="$(
490 | 				case "${GIT_PS1_DESCRIBE_STYLE-}" in
491 | 				(contains)
492 | 					git describe --contains HEAD ;;
493 | 				(branch)
494 | 					git describe --contains --all HEAD ;;
495 | 				(tag)
496 | 					git describe --tags HEAD ;;
497 | 				(describe)
498 | 					git describe HEAD ;;
499 | 				(* | default)
500 | 					git describe --tags --exact-match HEAD ;;
501 | 				esac 2>/dev/null)" ||
502 | 
503 | 				b="$short_sha..."
504 | 				b="($b)"
505 | 			fi
506 | 		fi
507 | 	fi
508 | 
509 | 	if [ -n "$step" ] && [ -n "$total" ]; then
510 | 		r="$r $step/$total"
511 | 	fi
512 | 
513 | 	local conflict="" # state indicator for unresolved conflicts
514 | 	if [[ "${GIT_PS1_SHOWCONFLICTSTATE}" == "yes" ]] &&
515 | 	   [[ $(git ls-files --unmerged 2>/dev/null) ]]; then
516 | 		conflict="|CONFLICT"
517 | 	fi
518 | 
519 | 	local w=""
520 | 	local i=""
521 | 	local s=""
522 | 	local u=""
523 | 	local h=""
524 | 	local c=""
525 | 	local p="" # short version of upstream state indicator
526 | 	local upstream="" # verbose version of upstream state indicator
527 | 
528 | 	if [ "true" = "$inside_gitdir" ]; then
529 | 		if [ "true" = "$bare_repo" ]; then
530 | 			c="BARE:"
531 | 		else
532 | 			b="GIT_DIR!"
533 | 		fi
534 | 	elif [ "true" = "$inside_worktree" ]; then
535 | 		if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] &&
536 | 		   [ "$(git config --bool bash.showDirtyState)" != "false" ]
537 | 		then
538 | 			git diff --no-ext-diff --quiet || w="*"
539 | 			git diff --no-ext-diff --cached --quiet || i="+"
540 | 			if [ -z "$short_sha" ] && [ -z "$i" ]; then
541 | 				i="#"
542 | 			fi
543 | 		fi
544 | 		if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] &&
545 | 		   git rev-parse --verify --quiet refs/stash >/dev/null
546 | 		then
547 | 			s="$"
548 | 		fi
549 | 
550 | 		if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] &&
551 | 		   [ "$(git config --bool bash.showUntrackedFiles)" != "false" ] &&
552 | 		   git ls-files --others --exclude-standard --directory --no-empty-directory --error-unmatch -- ':/*' >/dev/null 2>/dev/null
553 | 		then
554 | 			u="%${ZSH_VERSION+%}"
555 | 		fi
556 | 
557 | 		if [ -n "${GIT_PS1_COMPRESSSPARSESTATE-}" ] &&
558 | 		   [ "$(git config --bool core.sparseCheckout)" = "true" ]; then
559 | 			h="?"
560 | 		fi
561 | 
562 | 		if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then
563 | 			__git_ps1_show_upstream
564 | 		fi
565 | 	fi
566 | 
567 | 	local z="${GIT_PS1_STATESEPARATOR-" "}"
568 | 
569 | 	b=${b##refs/heads/}
570 | 	if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then
571 | 		__git_ps1_branch_name=$b
572 | 		b="\${__git_ps1_branch_name}"
573 | 	fi
574 | 
575 | 	if [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then
576 | 		__git_ps1_colorize_gitstring
577 | 	fi
578 | 
579 | 	local f="$h$w$i$s$u$p"
580 | 	local gitstring="$c$b${f:+$z$f}${sparse}$r${upstream}${conflict}"
581 | 
582 | 	if [ $pcmode = yes ]; then
583 | 		if [ "${__git_printf_supports_v-}" != yes ]; then
584 | 			gitstring=$(printf -- "$printf_format" "$gitstring")
585 | 		else
586 | 			printf -v gitstring -- "$printf_format" "$gitstring"
587 | 		fi
588 | 		PS1="$ps1pc_start$gitstring$ps1pc_end"
589 | 	else
590 | 		printf -- "$printf_format" "$gitstring"
591 | 	fi
592 | 
593 | 	return $exit
594 | }
595 | 


--------------------------------------------------------------------------------
/t/.gitignore:
--------------------------------------------------------------------------------
1 | /test-results/
2 | /trash directory.*/
3 | /.prove
4 | 


--------------------------------------------------------------------------------
/t/Makefile:
--------------------------------------------------------------------------------
 1 | RM ?= rm -f
 2 | 
 3 | T = $(wildcard *.t)
 4 | 
 5 | all: test
 6 | 
 7 | test: $(T)
 8 | 	$(MAKE) clean
 9 | 
10 | $(T):
11 | 	$(SHELL) $@ $(TEST_OPTS)
12 | 
13 | prove:
14 | 	prove $(T) :: $(TEST_OPTS)
15 | 	$(MAKE) clean
16 | 
17 | clean:
18 | 	$(RM) -r 'trash directory'.* test-results
19 | 
20 | .PHONY: all test $(T) clean
21 | 


--------------------------------------------------------------------------------
/t/completion-zsh.t:
--------------------------------------------------------------------------------
   1 | #!/bin/sh
   2 | #
   3 | # Copyright (c) 2012-2023 Felipe Contreras
   4 | #
   5 | 
   6 | test_description='test zsh completion'
   7 | 
   8 | if test -n "$ZSH_VERSION"; then
   9 | 	true
  10 | elif command -v zsh > /dev/null 2>&1; then
  11 | 	exec zsh "$0" "$@"
  12 | else
  13 | 	echo '1..0 #SKIP skipping zsh completion tests: zsh not available'
  14 | 	exit 0
  15 | fi
  16 | 
  17 | export ZDOTDIR="${0:h:a}/zsh"
  18 | 
  19 | . "$(dirname "$0")"/test-lib.sh
  20 | 
  21 | version=$(git version)
  22 | if [[ "$version" == "git version "* ]]; then
  23 | 	printf "$version\ngit version 2.48\n" | sort -V -C || {
  24 | 		skip_all="git version with regression"
  25 | 		test_done
  26 | 	}
  27 | fi
  28 | 
  29 | emulate zsh
  30 | 
  31 | zmodload zsh/zpty
  32 | 
  33 | export SRC_DIR
  34 | 
  35 | run_completion ()
  36 | {
  37 | 	local log
  38 | 
  39 | 	# bug in zsh: reset the exit trap
  40 | 	zpty zsh "trap - EXIT; zsh -o NO_GLOBAL_RCS"
  41 | 	zpty -n -w zsh "$1"$'\t'
  42 | 	zpty -r zsh log '*'
  43 | 	zpty -d zsh
  44 | 
  45 | 	printf '%s\n' ${${${(M)${(Qf)log}:#*''*}#*''}%''*} > out
  46 | 
  47 | 	[[ -s out ]] || { echo > out ; }
  48 | }
  49 | 
  50 | # Test high-level completion
  51 | # Arguments are:
  52 | # 1: typed text so far (cur)
  53 | # 2: expected completion
  54 | test_completion ()
  55 | {
  56 | 	if test $# -gt 1
  57 | 	then
  58 | 		printf '%s\n' "$2" >expected
  59 | 	else
  60 | 		sed -e 's/Z$//' |sort >expected
  61 | 	fi &&
  62 | 	run_completion "$1" &&
  63 | 	sort -u out >out_sorted &&
  64 | 	test_cmp expected out_sorted
  65 | }
  66 | 
  67 | # Test __gitcomp_opts.
  68 | # The first argument is the typed text so far (cur); the rest are
  69 | # passed to __gitcomp_opts.  Expected output comes is read from the
  70 | # standard input, like test_completion().
  71 | test_gitcomp_opts ()
  72 | {
  73 | 	sed -e 's/Z$//' >expected &&
  74 | 	local cur="$1" &&
  75 | 	shift &&
  76 | 	run_completion "git func __gitcomp_opts $(printf "%q " "$@") $cur" &&
  77 | 	test_cmp expected out
  78 | }
  79 | 
  80 | # Test __gitcomp_nl
  81 | # Arguments are:
  82 | # 1: current word (cur)
  83 | # -: the rest are passed to __gitcomp_nl
  84 | test_gitcomp_nl ()
  85 | {
  86 | 	sed -e 's/Z$//' >expected &&
  87 | 	local cur="$1" &&
  88 | 	shift &&
  89 | 	run_completion "git func __gitcomp_nl $(printf "%q " "$@") $cur" &&
  90 | 	test_cmp expected out
  91 | }
  92 | 
  93 | actual="$TRASH_DIRECTORY/actual"
  94 | 
  95 | if test_have_prereq MINGW
  96 | then
  97 | 	ROOT="$(pwd -W)"
  98 | else
  99 | 	ROOT="$(pwd)"
 100 | fi
 101 | 
 102 | test_expect_success 'setup for __git_find_repo_path/__gitdir tests' '
 103 | 	mkdir -p subdir/subsubdir &&
 104 | 	mkdir -p non-repo &&
 105 | 	git init -b main otherrepo
 106 | '
 107 | 
 108 | test_expect_success '__gitcomp_opts - trailing space - options' '
 109 | 	test_gitcomp_opts "--re" "--dry-run --reuse-message= --reedit-message=
 110 | 		--reset-author" <<-EOF
 111 | 	--reuse-message=Z
 112 | 	--reedit-message=Z
 113 | 	--reset-author Z
 114 | 	EOF
 115 | '
 116 | 
 117 | test_expect_success '__gitcomp_opts - trailing space - config keys' '
 118 | 	test_gitcomp_opts "br" "branch. branch.autosetupmerge
 119 | 		branch.autosetuprebase browser." <<-\EOF
 120 | 	branch.Z
 121 | 	branch.autosetupmerge Z
 122 | 	branch.autosetuprebase Z
 123 | 	browser.Z
 124 | 	EOF
 125 | '
 126 | 
 127 | test_expect_success '__gitcomp_opts - option parameter' '
 128 | 	test_gitcomp_opts "--strategy=re" "octopus ours recursive resolve subtree" \
 129 | 		"" "re" <<-\EOF
 130 | 	recursive Z
 131 | 	resolve Z
 132 | 	EOF
 133 | '
 134 | 
 135 | test_expect_success '__gitcomp_opts - prefix' '
 136 | 	test_gitcomp_opts "branch.maint.me" "remote merge mergeoptions rebase" \
 137 | 		"branch.maint." "me" <<-\EOF
 138 | 	branch.maint.merge Z
 139 | 	branch.maint.mergeoptions Z
 140 | 	EOF
 141 | '
 142 | 
 143 | test_expect_success '__gitcomp_opts - suffix' '
 144 | 	test_gitcomp_opts "branch.ma" "master maint next seen" "branch." \
 145 | 		"ma" "." <<-\EOF
 146 | 	branch.master.Z
 147 | 	branch.maint.Z
 148 | 	EOF
 149 | '
 150 | 
 151 | test_expect_success '__gitcomp_opts - ignore optional negative options' '
 152 | 	test_gitcomp_opts "--" "--abc --def --no-one -- --no-two" <<-\EOF
 153 | 	--abc Z
 154 | 	--def Z
 155 | 	--no-one Z
 156 | 	--no-... Z
 157 | 	EOF
 158 | '
 159 | 
 160 | test_expect_success '__gitcomp_opts - ignore/narrow optional negative options' '
 161 | 	test_gitcomp_opts "--a" "--abc --abcdef --no-one -- --no-two" <<-\EOF
 162 | 	--abc Z
 163 | 	--abcdef Z
 164 | 	EOF
 165 | '
 166 | 
 167 | test_expect_success '__gitcomp_opts - ignore/narrow optional negative options' '
 168 | 	test_gitcomp_opts "--n" "--abc --def --no-one -- --no-two" <<-\EOF
 169 | 	--no-one Z
 170 | 	--no-... Z
 171 | 	EOF
 172 | '
 173 | 
 174 | test_expect_success '__gitcomp_opts - expand all negative options' '
 175 | 	test_gitcomp_opts "--no-" "--abc --def --no-one -- --no-two" <<-\EOF
 176 | 	--no-one Z
 177 | 	--no-two Z
 178 | 	EOF
 179 | '
 180 | 
 181 | test_expect_success '__gitcomp_opts - expand/narrow all negative options' '
 182 | 	test_gitcomp_opts "--no-o" "--abc --def --no-one -- --no-two" <<-\EOF
 183 | 	--no-one Z
 184 | 	EOF
 185 | '
 186 | 
 187 | test_expect_success '__gitcomp_opts - equal skip' '
 188 | 	test_gitcomp_opts "--option=" "--option=" <<-\EOF &&
 189 | 
 190 | 	EOF
 191 | 	test_gitcomp_opts "option=" "option=" <<-\EOF
 192 | 
 193 | 	EOF
 194 | '
 195 | 
 196 | read -r -d "" refs <<-\EOF
 197 | main
 198 | maint
 199 | next
 200 | seen
 201 | EOF
 202 | 
 203 | test_expect_success '__gitcomp_nl - trailing space' '
 204 | 	test_gitcomp_nl "m" "$refs" <<-EOF
 205 | 	main Z
 206 | 	maint Z
 207 | 	EOF
 208 | '
 209 | 
 210 | test_expect_success '__gitcomp_nl - prefix' '
 211 | 	test_gitcomp_nl "branch.m" "$refs" "branch." "m" <<-EOF
 212 | 	branch.main Z
 213 | 	branch.maint Z
 214 | 	EOF
 215 | '
 216 | 
 217 | test_expect_success '__gitcomp_nl - suffix' '
 218 | 	test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF
 219 | 	branch.main.Z
 220 | 	branch.maint.Z
 221 | 	EOF
 222 | '
 223 | 
 224 | test_expect_success '__gitcomp_nl - no suffix' '
 225 | 	test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF
 226 | 	mainZ
 227 | 	maintZ
 228 | 	EOF
 229 | '
 230 | 
 231 | test_expect_success 'setup for ref completion' '
 232 | 	git commit --allow-empty -m initial &&
 233 | 	git branch -M main &&
 234 | 	git branch matching-branch &&
 235 | 	git tag matching-tag &&
 236 | 	(
 237 | 		cd otherrepo &&
 238 | 		git commit --allow-empty -m initial &&
 239 | 		git branch -m main main-in-other &&
 240 | 		git branch branch-in-other &&
 241 | 		git tag tag-in-other
 242 | 	) &&
 243 | 	git remote add other "$ROOT/otherrepo/.git" &&
 244 | 	git fetch --no-tags other &&
 245 | 	rm -f .git/FETCH_HEAD &&
 246 | 	git init thirdrepo
 247 | '
 248 | 
 249 | test_expect_success 'git switch - with no options, complete local branches and unique remote branch names for DWIM logic' '
 250 | 	test_completion "git switch " <<-\EOF
 251 | 	branch-in-other Z
 252 | 	main Z
 253 | 	main-in-other Z
 254 | 	matching-branch Z
 255 | 	EOF
 256 | '
 257 | 
 258 | test_expect_success 'git checkout - completes refs and unique remote branches for DWIM' '
 259 | 	test_completion "git checkout " <<-\EOF
 260 | 	HEAD Z
 261 | 	branch-in-other Z
 262 | 	main Z
 263 | 	main-in-other Z
 264 | 	matching-branch Z
 265 | 	matching-tag Z
 266 | 	other/branch-in-other Z
 267 | 	other/main-in-other Z
 268 | 	EOF
 269 | '
 270 | 
 271 | test_expect_success 'git switch - with --no-guess, complete only local branches' '
 272 | 	test_completion "git switch --no-guess " <<-\EOF
 273 | 	main Z
 274 | 	matching-branch Z
 275 | 	EOF
 276 | '
 277 | 
 278 | test_expect_success 'git switch - with GIT_COMPLETION_CHECKOUT_NO_GUESS=1, complete only local branches' '
 279 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git switch " <<-\EOF
 280 | 	main Z
 281 | 	matching-branch Z
 282 | 	EOF
 283 | '
 284 | 
 285 | test_expect_success 'git switch - --guess overrides GIT_COMPLETION_CHECKOUT_NO_GUESS=1, complete local branches and unique remote names for DWIM logic' '
 286 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git switch --guess " <<-\EOF
 287 | 	branch-in-other Z
 288 | 	main Z
 289 | 	main-in-other Z
 290 | 	matching-branch Z
 291 | 	EOF
 292 | '
 293 | 
 294 | test_expect_success 'git switch - a later --guess overrides previous --no-guess, complete local and remote unique branches for DWIM' '
 295 | 	test_completion "git switch --no-guess --guess " <<-\EOF
 296 | 	branch-in-other Z
 297 | 	main Z
 298 | 	main-in-other Z
 299 | 	matching-branch Z
 300 | 	EOF
 301 | '
 302 | 
 303 | test_expect_success 'git switch - a later --no-guess overrides previous --guess, complete only local branches' '
 304 | 	test_completion "git switch --guess --no-guess " <<-\EOF
 305 | 	main Z
 306 | 	matching-branch Z
 307 | 	EOF
 308 | '
 309 | 
 310 | test_expect_success 'git checkout - with GIT_COMPLETION_NO_GUESS=1 only completes refs' '
 311 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git checkout " <<-\EOF
 312 | 	HEAD Z
 313 | 	main Z
 314 | 	matching-branch Z
 315 | 	matching-tag Z
 316 | 	other/branch-in-other Z
 317 | 	other/main-in-other Z
 318 | 	EOF
 319 | '
 320 | 
 321 | test_expect_success 'git checkout - --guess overrides GIT_COMPLETION_NO_GUESS=1, complete refs and unique remote branches for DWIM' '
 322 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git checkout --guess " <<-\EOF
 323 | 	HEAD Z
 324 | 	branch-in-other Z
 325 | 	main Z
 326 | 	main-in-other Z
 327 | 	matching-branch Z
 328 | 	matching-tag Z
 329 | 	other/branch-in-other Z
 330 | 	other/main-in-other Z
 331 | 	EOF
 332 | '
 333 | 
 334 | test_expect_success 'git checkout - with --no-guess, only completes refs' '
 335 | 	test_completion "git checkout --no-guess " <<-\EOF
 336 | 	HEAD Z
 337 | 	main Z
 338 | 	matching-branch Z
 339 | 	matching-tag Z
 340 | 	other/branch-in-other Z
 341 | 	other/main-in-other Z
 342 | 	EOF
 343 | '
 344 | 
 345 | test_expect_success 'git checkout - a later --guess overrides previous --no-guess, complete refs and unique remote branches for DWIM' '
 346 | 	test_completion "git checkout --no-guess --guess " <<-\EOF
 347 | 	HEAD Z
 348 | 	branch-in-other Z
 349 | 	main Z
 350 | 	main-in-other Z
 351 | 	matching-branch Z
 352 | 	matching-tag Z
 353 | 	other/branch-in-other Z
 354 | 	other/main-in-other Z
 355 | 	EOF
 356 | '
 357 | 
 358 | test_expect_success 'git checkout - a later --no-guess overrides previous --guess, complete only refs' '
 359 | 	test_completion "git checkout --guess --no-guess " <<-\EOF
 360 | 	HEAD Z
 361 | 	main Z
 362 | 	matching-branch Z
 363 | 	matching-tag Z
 364 | 	other/branch-in-other Z
 365 | 	other/main-in-other Z
 366 | 	EOF
 367 | '
 368 | 
 369 | test_expect_success 'git checkout - with checkout.guess = false, only completes refs' '
 370 | 	test_config checkout.guess false &&
 371 | 	test_completion "git checkout " <<-\EOF
 372 | 	HEAD Z
 373 | 	main Z
 374 | 	matching-branch Z
 375 | 	matching-tag Z
 376 | 	other/branch-in-other Z
 377 | 	other/main-in-other Z
 378 | 	EOF
 379 | '
 380 | 
 381 | test_expect_success 'git checkout - with checkout.guess = true, completes refs and unique remote branches for DWIM' '
 382 | 	test_config checkout.guess true &&
 383 | 	test_completion "git checkout " <<-\EOF
 384 | 	HEAD Z
 385 | 	branch-in-other Z
 386 | 	main Z
 387 | 	main-in-other Z
 388 | 	matching-branch Z
 389 | 	matching-tag Z
 390 | 	other/branch-in-other Z
 391 | 	other/main-in-other Z
 392 | 	EOF
 393 | '
 394 | 
 395 | test_expect_success 'git checkout - a later --guess overrides previous checkout.guess = false, complete refs and unique remote branches for DWIM' '
 396 | 	test_config checkout.guess false &&
 397 | 	test_completion "git checkout --guess " <<-\EOF
 398 | 	HEAD Z
 399 | 	branch-in-other Z
 400 | 	main Z
 401 | 	main-in-other Z
 402 | 	matching-branch Z
 403 | 	matching-tag Z
 404 | 	other/branch-in-other Z
 405 | 	other/main-in-other Z
 406 | 	EOF
 407 | '
 408 | 
 409 | test_expect_success 'git checkout - a later --no-guess overrides previous checkout.guess = true, complete only refs' '
 410 | 	test_config checkout.guess true &&
 411 | 	test_completion "git checkout --no-guess " <<-\EOF
 412 | 	HEAD Z
 413 | 	main Z
 414 | 	matching-branch Z
 415 | 	matching-tag Z
 416 | 	other/branch-in-other Z
 417 | 	other/main-in-other Z
 418 | 	EOF
 419 | '
 420 | 
 421 | test_expect_success 'git switch - with --detach, complete all references' '
 422 | 	test_completion "git switch --detach " <<-\EOF
 423 | 	HEAD Z
 424 | 	main Z
 425 | 	matching-branch Z
 426 | 	matching-tag Z
 427 | 	other/branch-in-other Z
 428 | 	other/main-in-other Z
 429 | 	EOF
 430 | '
 431 | 
 432 | test_expect_success 'git checkout - with --detach, complete only references' '
 433 | 	test_completion "git checkout --detach " <<-\EOF
 434 | 	HEAD Z
 435 | 	main Z
 436 | 	matching-branch Z
 437 | 	matching-tag Z
 438 | 	other/branch-in-other Z
 439 | 	other/main-in-other Z
 440 | 	EOF
 441 | '
 442 | 
 443 | test_expect_success 'git switch - with -d, complete all references' '
 444 | 	test_completion "git switch -d " <<-\EOF
 445 | 	HEAD Z
 446 | 	main Z
 447 | 	matching-branch Z
 448 | 	matching-tag Z
 449 | 	other/branch-in-other Z
 450 | 	other/main-in-other Z
 451 | 	EOF
 452 | '
 453 | 
 454 | test_expect_success 'git checkout - with -d, complete only references' '
 455 | 	test_completion "git checkout -d " <<-\EOF
 456 | 	HEAD Z
 457 | 	main Z
 458 | 	matching-branch Z
 459 | 	matching-tag Z
 460 | 	other/branch-in-other Z
 461 | 	other/main-in-other Z
 462 | 	EOF
 463 | '
 464 | 
 465 | test_expect_success 'git switch - with --track, complete only remote branches' '
 466 | 	test_completion "git switch --track " <<-\EOF
 467 | 	other/branch-in-other Z
 468 | 	other/main-in-other Z
 469 | 	EOF
 470 | '
 471 | 
 472 | test_expect_success 'git checkout - with --track, complete only remote branches' '
 473 | 	test_completion "git checkout --track " <<-\EOF
 474 | 	other/branch-in-other Z
 475 | 	other/main-in-other Z
 476 | 	EOF
 477 | '
 478 | 
 479 | test_expect_success 'git switch - with --no-track, complete only local branch names' '
 480 | 	test_completion "git switch --no-track " <<-\EOF
 481 | 	main Z
 482 | 	matching-branch Z
 483 | 	EOF
 484 | '
 485 | 
 486 | test_expect_success 'git checkout - with --no-track, complete only local references' '
 487 | 	test_completion "git checkout --no-track " <<-\EOF
 488 | 	HEAD Z
 489 | 	main Z
 490 | 	matching-branch Z
 491 | 	matching-tag Z
 492 | 	other/branch-in-other Z
 493 | 	other/main-in-other Z
 494 | 	EOF
 495 | '
 496 | 
 497 | test_expect_success 'git switch - with -c, complete all references' '
 498 | 	test_completion "git switch -c new-branch " <<-\EOF
 499 | 	HEAD Z
 500 | 	main Z
 501 | 	matching-branch Z
 502 | 	matching-tag Z
 503 | 	other/branch-in-other Z
 504 | 	other/main-in-other Z
 505 | 	EOF
 506 | '
 507 | 
 508 | test_expect_success 'git switch - with -C, complete all references' '
 509 | 	test_completion "git switch -C new-branch " <<-\EOF
 510 | 	HEAD Z
 511 | 	main Z
 512 | 	matching-branch Z
 513 | 	matching-tag Z
 514 | 	other/branch-in-other Z
 515 | 	other/main-in-other Z
 516 | 	EOF
 517 | '
 518 | 
 519 | test_expect_success 'git switch - with -c and --track, complete all references' '
 520 | 	test_completion "git switch -c new-branch --track " <<-EOF
 521 | 	HEAD Z
 522 | 	main Z
 523 | 	matching-branch Z
 524 | 	matching-tag Z
 525 | 	other/branch-in-other Z
 526 | 	other/main-in-other Z
 527 | 	EOF
 528 | '
 529 | 
 530 | test_expect_success 'git switch - with -C and --track, complete all references' '
 531 | 	test_completion "git switch -C new-branch --track " <<-EOF
 532 | 	HEAD Z
 533 | 	main Z
 534 | 	matching-branch Z
 535 | 	matching-tag Z
 536 | 	other/branch-in-other Z
 537 | 	other/main-in-other Z
 538 | 	EOF
 539 | '
 540 | 
 541 | test_expect_success 'git switch - with -c and --no-track, complete all references' '
 542 | 	test_completion "git switch -c new-branch --no-track " <<-\EOF
 543 | 	HEAD Z
 544 | 	main Z
 545 | 	matching-branch Z
 546 | 	matching-tag Z
 547 | 	other/branch-in-other Z
 548 | 	other/main-in-other Z
 549 | 	EOF
 550 | '
 551 | 
 552 | test_expect_success 'git switch - with -C and --no-track, complete all references' '
 553 | 	test_completion "git switch -C new-branch --no-track " <<-\EOF
 554 | 	HEAD Z
 555 | 	main Z
 556 | 	matching-branch Z
 557 | 	matching-tag Z
 558 | 	other/branch-in-other Z
 559 | 	other/main-in-other Z
 560 | 	EOF
 561 | '
 562 | 
 563 | test_expect_success 'git checkout - with -b, complete all references' '
 564 | 	test_completion "git checkout -b new-branch " <<-\EOF
 565 | 	HEAD Z
 566 | 	main Z
 567 | 	matching-branch Z
 568 | 	matching-tag Z
 569 | 	other/branch-in-other Z
 570 | 	other/main-in-other Z
 571 | 	EOF
 572 | '
 573 | 
 574 | test_expect_success 'git checkout - with -B, complete all references' '
 575 | 	test_completion "git checkout -B new-branch " <<-\EOF
 576 | 	HEAD Z
 577 | 	main Z
 578 | 	matching-branch Z
 579 | 	matching-tag Z
 580 | 	other/branch-in-other Z
 581 | 	other/main-in-other Z
 582 | 	EOF
 583 | '
 584 | 
 585 | test_expect_success 'git checkout - with -b and --track, complete all references' '
 586 | 	test_completion "git checkout -b new-branch --track " <<-EOF
 587 | 	HEAD Z
 588 | 	main Z
 589 | 	matching-branch Z
 590 | 	matching-tag Z
 591 | 	other/branch-in-other Z
 592 | 	other/main-in-other Z
 593 | 	EOF
 594 | '
 595 | 
 596 | test_expect_success 'git checkout - with -B and --track, complete all references' '
 597 | 	test_completion "git checkout -B new-branch --track " <<-EOF
 598 | 	HEAD Z
 599 | 	main Z
 600 | 	matching-branch Z
 601 | 	matching-tag Z
 602 | 	other/branch-in-other Z
 603 | 	other/main-in-other Z
 604 | 	EOF
 605 | '
 606 | 
 607 | test_expect_success 'git checkout - with -b and --no-track, complete all references' '
 608 | 	test_completion "git checkout -b new-branch --no-track " <<-\EOF
 609 | 	HEAD Z
 610 | 	main Z
 611 | 	matching-branch Z
 612 | 	matching-tag Z
 613 | 	other/branch-in-other Z
 614 | 	other/main-in-other Z
 615 | 	EOF
 616 | '
 617 | 
 618 | test_expect_success 'git checkout - with -B and --no-track, complete all references' '
 619 | 	test_completion "git checkout -B new-branch --no-track " <<-\EOF
 620 | 	HEAD Z
 621 | 	main Z
 622 | 	matching-branch Z
 623 | 	matching-tag Z
 624 | 	other/branch-in-other Z
 625 | 	other/main-in-other Z
 626 | 	EOF
 627 | '
 628 | 
 629 | test_expect_success 'git switch - for -c, complete local branches and unique remote branches' '
 630 | 	test_completion "git switch -c " <<-\EOF
 631 | 	branch-in-other Z
 632 | 	main Z
 633 | 	main-in-other Z
 634 | 	matching-branch Z
 635 | 	EOF
 636 | '
 637 | 
 638 | test_expect_success 'git switch - for -C, complete local branches and unique remote branches' '
 639 | 	test_completion "git switch -C " <<-\EOF
 640 | 	branch-in-other Z
 641 | 	main Z
 642 | 	main-in-other Z
 643 | 	matching-branch Z
 644 | 	EOF
 645 | '
 646 | 
 647 | test_expect_success 'git switch - for -c with --no-guess, complete local branches only' '
 648 | 	test_completion "git switch --no-guess -c " <<-\EOF
 649 | 	main Z
 650 | 	matching-branch Z
 651 | 	EOF
 652 | '
 653 | 
 654 | test_expect_success 'git switch - for -C with --no-guess, complete local branches only' '
 655 | 	test_completion "git switch --no-guess -C " <<-\EOF
 656 | 	main Z
 657 | 	matching-branch Z
 658 | 	EOF
 659 | '
 660 | 
 661 | test_expect_success 'git switch - for -c with --no-track, complete local branches only' '
 662 | 	test_completion "git switch --no-track -c " <<-\EOF
 663 | 	main Z
 664 | 	matching-branch Z
 665 | 	EOF
 666 | '
 667 | 
 668 | test_expect_success 'git switch - for -C with --no-track, complete local branches only' '
 669 | 	test_completion "git switch --no-track -C " <<-\EOF
 670 | 	main Z
 671 | 	matching-branch Z
 672 | 	EOF
 673 | '
 674 | 
 675 | test_expect_success 'git checkout - for -b, complete local branches and unique remote branches' '
 676 | 	test_completion "git checkout -b " <<-\EOF
 677 | 	branch-in-other Z
 678 | 	main Z
 679 | 	main-in-other Z
 680 | 	matching-branch Z
 681 | 	EOF
 682 | '
 683 | 
 684 | test_expect_success 'git checkout - for -B, complete local branches and unique remote branches' '
 685 | 	test_completion "git checkout -B " <<-\EOF
 686 | 	branch-in-other Z
 687 | 	main Z
 688 | 	main-in-other Z
 689 | 	matching-branch Z
 690 | 	EOF
 691 | '
 692 | 
 693 | test_expect_success 'git checkout - for -b with --no-guess, complete local branches only' '
 694 | 	test_completion "git checkout --no-guess -b " <<-\EOF
 695 | 	main Z
 696 | 	matching-branch Z
 697 | 	EOF
 698 | '
 699 | 
 700 | test_expect_success 'git checkout - for -B with --no-guess, complete local branches only' '
 701 | 	test_completion "git checkout --no-guess -B " <<-\EOF
 702 | 	main Z
 703 | 	matching-branch Z
 704 | 	EOF
 705 | '
 706 | 
 707 | test_expect_success 'git checkout - for -b with --no-track, complete local branches only' '
 708 | 	test_completion "git checkout --no-track -b " <<-\EOF
 709 | 	main Z
 710 | 	matching-branch Z
 711 | 	EOF
 712 | '
 713 | 
 714 | test_expect_success 'git checkout - for -B with --no-track, complete local branches only' '
 715 | 	test_completion "git checkout --no-track -B " <<-\EOF
 716 | 	main Z
 717 | 	matching-branch Z
 718 | 	EOF
 719 | '
 720 | 
 721 | test_expect_success 'git switch - with --orphan completes local branch names and unique remote branch names' '
 722 | 	test_completion "git switch --orphan " <<-\EOF
 723 | 	branch-in-other Z
 724 | 	main Z
 725 | 	main-in-other Z
 726 | 	matching-branch Z
 727 | 	EOF
 728 | '
 729 | 
 730 | test_expect_success 'git switch - --orphan with branch already provided completes nothing else' '
 731 | 	test_completion "git switch --orphan main " <<-\EOF
 732 | 
 733 | 	EOF
 734 | '
 735 | 
 736 | test_expect_success 'git checkout - with --orphan completes local branch names and unique remote branch names' '
 737 | 	test_completion "git checkout --orphan " <<-\EOF
 738 | 	branch-in-other Z
 739 | 	main Z
 740 | 	main-in-other Z
 741 | 	matching-branch Z
 742 | 	EOF
 743 | '
 744 | 
 745 | test_expect_success 'git checkout - --orphan with branch already provided completes local refs for a start-point' '
 746 | 	test_completion "git checkout --orphan main " <<-\EOF
 747 | 	HEAD Z
 748 | 	main Z
 749 | 	matching-branch Z
 750 | 	matching-tag Z
 751 | 	other/branch-in-other Z
 752 | 	other/main-in-other Z
 753 | 	EOF
 754 | '
 755 | 
 756 | test_expect_success 'teardown after ref completion' '
 757 | 	git branch -d matching-branch &&
 758 | 	git tag -d matching-tag &&
 759 | 	git remote remove other
 760 | '
 761 | 
 762 | test_expect_success 'basic' '
 763 | 	run_completion "git " &&
 764 | 	# built-in
 765 | 	grep -q "^add\$" out &&
 766 | 	# script
 767 | 	grep -q "^rebase\$" out &&
 768 | 	# plumbing
 769 | 	! grep -q "^ls-files\$" out &&
 770 | 
 771 | 	run_completion "git r" &&
 772 | 	! grep -q -v "^r" out
 773 | '
 774 | 
 775 | test_expect_success 'double dash "git" itself' '
 776 | 	test_completion "git --" <<-\EOF
 777 | 	--paginate
 778 | 	--no-pager
 779 | 	--git-dir
 780 | 	--bare
 781 | 	--version
 782 | 	--exec-path
 783 | 	--html-path
 784 | 	--man-path
 785 | 	--info-path
 786 | 	--work-tree
 787 | 	--namespace
 788 | 	--no-replace-objects
 789 | 	--help
 790 | 	EOF
 791 | '
 792 | 
 793 | test_expect_success 'double dash "git checkout"' '
 794 | 	test_completion "git checkout --" <<-\EOF
 795 | 	--quiet Z
 796 | 	--detach Z
 797 | 	--track Z
 798 | 	--orphan=Z
 799 | 	--ours Z
 800 | 	--theirs Z
 801 | 	--merge Z
 802 | 	--conflict=Z
 803 | 	--patch Z
 804 | 	--ignore-skip-worktree-bits Z
 805 | 	--ignore-other-worktrees Z
 806 | 	--recurse-submodules Z
 807 | 	--progress Z
 808 | 	--guess Z
 809 | 	--no-guess Z
 810 | 	--no-... Z
 811 | 	--overlay Z
 812 | 	--pathspec-file-nul Z
 813 | 	--pathspec-from-file=Z
 814 | 	EOF
 815 | '
 816 | 
 817 | test_expect_success 'general options' '
 818 | 	test_completion "git --ver" "--version" &&
 819 | 	test_completion "git --hel" "--help" &&
 820 | 	test_completion "git --exe" "--exec-path" &&
 821 | 	test_completion "git --htm" "--html-path" &&
 822 | 	test_completion "git --pag" "--paginate" &&
 823 | 	test_completion "git --no-p" "--no-pager" &&
 824 | 	test_completion "git --git" "--git-dir" &&
 825 | 	test_completion "git --wor" "--work-tree" &&
 826 | 	test_completion "git --nam" "--namespace" &&
 827 | 	test_completion "git --bar" "--bare" &&
 828 | 	test_completion "git --inf" "--info-path" &&
 829 | 	test_completion "git --no-r" "--no-replace-objects"
 830 | '
 831 | 
 832 | test_expect_success 'general options plus command' '
 833 | 	test_completion "git --version check" "" &&
 834 | 	test_completion "git --paginate check" "checkout" &&
 835 | 	test_completion "git --git-dir=foo check" "checkout" &&
 836 | 	test_completion "git --bare check" "checkout" &&
 837 | 	test_completion "git --exec-path=foo check" "checkout" &&
 838 | 	test_completion "git --html-path check" "" &&
 839 | 	test_completion "git --no-pager check" "checkout" &&
 840 | 	test_completion "git --work-tree=foo check" "checkout" &&
 841 | 	test_completion "git --namespace=foo check" "checkout" &&
 842 | 	test_completion "git --paginate check" "checkout" &&
 843 | 	test_completion "git --info-path check" "" &&
 844 | 	test_completion "git --no-replace-objects check" "checkout" &&
 845 | 	test_completion "git --git-dir some/path check" "checkout" &&
 846 | 	test_completion "git -c conf.var=value check" "checkout" &&
 847 | 	test_completion "git -C some/path check" "checkout" &&
 848 | 	test_completion "git --work-tree some/path check" "checkout" &&
 849 | 	test_completion "git --namespace name/space check" "checkout"
 850 | '
 851 | 
 852 | test_expect_success 'git --help completion' '
 853 | 	test_completion "git --help ad" "add " &&
 854 | 	test_completion "git --help core" "core-tutorial "
 855 | '
 856 | 
 857 | test_expect_success 'setup for integration tests' '
 858 | 	echo content >file1 &&
 859 | 	echo more >file2 &&
 860 | 	git add file1 file2 &&
 861 | 	git commit -m one &&
 862 | 	git branch mybranch &&
 863 | 	git tag mytag
 864 | '
 865 | 
 866 | test_expect_success 'checkout completes ref names' '
 867 | 	test_completion "git checkout m" <<-\EOF
 868 | 	main Z
 869 | 	mybranch Z
 870 | 	mytag Z
 871 | 	EOF
 872 | '
 873 | 
 874 | test_expect_success 'git -C  checkout uses the right repo' '
 875 | 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
 876 | 	branch-in-other Z
 877 | 	EOF
 878 | '
 879 | 
 880 | test_expect_success 'show completes all refs' '
 881 | 	test_completion "git show m" <<-\EOF
 882 | 	main Z
 883 | 	mybranch Z
 884 | 	mytag Z
 885 | 	EOF
 886 | '
 887 | 
 888 | test_expect_success ': completes paths' '
 889 | 	test_completion "git show mytag:f" <<-\EOF
 890 | 	file1Z
 891 | 	file2Z
 892 | 	EOF
 893 | '
 894 | 
 895 | test_expect_success 'complete tree filename with spaces' '
 896 | 	echo content >"name with spaces" &&
 897 | 	git add "name with spaces" &&
 898 | 	git commit -m spaces &&
 899 | 	test_completion "git show HEAD:nam" <<-\EOF
 900 | 	name with spacesZ
 901 | 	EOF
 902 | '
 903 | 
 904 | test_expect_success 'complete tree filename with metacharacters' '
 905 | 	echo content >"name with \${meta}" &&
 906 | 	git add "name with \${meta}" &&
 907 | 	git commit -m meta &&
 908 | 	test_completion "git show HEAD:nam" <<-\EOF
 909 | 	name with ${meta}Z
 910 | 	name with spacesZ
 911 | 	EOF
 912 | '
 913 | 
 914 | test_expect_success PERL 'send-email' '
 915 | 	test_completion "git send-email --cov" <<-\EOF &&
 916 | 	--cover-from-description=Z
 917 | 	--cover-letter Z
 918 | 	EOF
 919 | 	test_completion "git send-email --val" <<-\EOF &&
 920 | 	--validate Z
 921 | 	EOF
 922 | 	test_completion "git send-email ma" "main "
 923 | '
 924 | 
 925 | test_expect_success 'complete files' '
 926 | 	git init tmp && cd tmp &&
 927 | 	test_when_finished "cd .. && rm -rf tmp" &&
 928 | 
 929 | 	echo "expected" > .gitignore &&
 930 | 	echo "out" >> .gitignore &&
 931 | 	echo "out_sorted" >> .gitignore &&
 932 | 
 933 | 	git add .gitignore &&
 934 | 	test_completion "git commit " ".gitignore" &&
 935 | 
 936 | 	git commit -m ignore &&
 937 | 
 938 | 	touch new &&
 939 | 	test_completion "git add " "new" &&
 940 | 
 941 | 	git add new &&
 942 | 	git commit -a -m new &&
 943 | 	test_completion "git add " "" &&
 944 | 
 945 | 	git mv new modified &&
 946 | 	echo modify > modified &&
 947 | 	test_completion "git add " "modified" &&
 948 | 
 949 | 	mkdir -p some/deep &&
 950 | 	touch some/deep/path &&
 951 | 	test_completion "git add some/" "some/deep" &&
 952 | 	git clean -f some &&
 953 | 
 954 | 	touch untracked &&
 955 | 
 956 | 	: TODO .gitignore should not be here &&
 957 | 	test_completion "git rm " <<-\EOF &&
 958 | 	.gitignore
 959 | 	modified
 960 | 	EOF
 961 | 
 962 | 	test_completion "git clean " "untracked" &&
 963 | 
 964 | 	: TODO .gitignore should not be here &&
 965 | 	test_completion "git mv " <<-\EOF &&
 966 | 	.gitignore
 967 | 	modified
 968 | 	EOF
 969 | 
 970 | 	mkdir dir &&
 971 | 	touch dir/file-in-dir &&
 972 | 	git add dir/file-in-dir &&
 973 | 	git commit -m dir &&
 974 | 
 975 | 	mkdir untracked-dir &&
 976 | 
 977 | 	: TODO .gitignore should not be here &&
 978 | 	test_completion "git mv modified " <<-\EOF &&
 979 | 	.gitignore
 980 | 	dir
 981 | 	modified
 982 | 	untracked
 983 | 	untracked-dir
 984 | 	EOF
 985 | 
 986 | 	test_completion "git commit " "modified" &&
 987 | 
 988 | 	: TODO .gitignore should not be here &&
 989 | 	test_completion "git ls-files " <<-\EOF &&
 990 | 	.gitignore
 991 | 	dir
 992 | 	modified
 993 | 	EOF
 994 | 
 995 | 	touch momified &&
 996 | 	test_completion "git add mom" "momified"
 997 | '
 998 | 
 999 | test_expect_success "simple alias" '
1000 | 	test_config alias.co checkout &&
1001 | 	test_completion "git co m" <<-\EOF
1002 | 	main Z
1003 | 	mybranch Z
1004 | 	mytag Z
1005 | 	EOF
1006 | '
1007 | 
1008 | test_expect_success "recursive alias" '
1009 | 	test_config alias.co checkout &&
1010 | 	test_config alias.cod "co --detached" &&
1011 | 	test_completion "git cod m" <<-\EOF
1012 | 	main Z
1013 | 	mybranch Z
1014 | 	mytag Z
1015 | 	EOF
1016 | '
1017 | 
1018 | test_expect_success "completion uses  completion for alias: !sh -c 'git  ...'" '
1019 | 	test_config_global alias.co "!sh -c '"'"'git checkout ...'"'"'" &&
1020 | 	test_completion "git co m" <<-\EOF
1021 | 	main Z
1022 | 	mybranch Z
1023 | 	mytag Z
1024 | 	EOF
1025 | '
1026 | 
1027 | test_expect_success 'completion uses  completion for alias: !f () { VAR=val git  ... }' '
1028 | 	test_config_global alias.co "!f () { VAR=val git checkout ... ; } f" &&
1029 | 	test_completion "git co m" <<-\EOF
1030 | 	main Z
1031 | 	mybranch Z
1032 | 	mytag Z
1033 | 	EOF
1034 | '
1035 | 
1036 | test_expect_success 'completion used  completion for alias: !f() { : git  ; ... }' '
1037 | 	test_config_global alias.co "!f() { : git checkout ; if ... } f" &&
1038 | 	test_completion "git co m" <<-\EOF
1039 | 	main Z
1040 | 	mybranch Z
1041 | 	mytag Z
1042 | 	EOF
1043 | '
1044 | 
1045 | test_expect_success 'completion without explicit _git_xxx function' '
1046 | 	test_completion "git version --" <<-\EOF
1047 | 	--build-options Z
1048 | 	--no-build-options Z
1049 | 	EOF
1050 | '
1051 | 
1052 | test_expect_failure 'complete with tilde expansion' '
1053 | 	git init tmp && cd tmp &&
1054 | 	test_when_finished "cd .. && rm -rf tmp" &&
1055 | 
1056 | 	touch ~/tmp/file &&
1057 | 
1058 | 	test_completion "git add ~/tmp/" "~/tmp/file"
1059 | '
1060 | 
1061 | test_expect_success 'setup other remote for remote reference completion' '
1062 | 	git remote add other otherrepo &&
1063 | 	git fetch other
1064 | '
1065 | 
1066 | test_expect_success 'git config - section' '
1067 | 	test_completion "git config br" <<-\EOF
1068 | 	branch.Z
1069 | 	browser.Z
1070 | 	EOF
1071 | '
1072 | 
1073 | test_expect_unstable 'git config - section include, includeIf' '
1074 | 	test_completion "git config inclu" <<-\EOF
1075 | 	include.Z
1076 | 	includeIf.Z
1077 | 	EOF
1078 | '
1079 | 
1080 | test_expect_success 'git config - variable name' '
1081 | 	test_completion "git config log.d" <<-\EOF
1082 | 	log.date Z
1083 | 	log.decorate Z
1084 | 	log.diffMerges Z
1085 | 	EOF
1086 | '
1087 | 
1088 | test_expect_unstable 'git config - variable name include' '
1089 | 	test_completion "git config include.p" <<-\EOF
1090 | 	include.path Z
1091 | 	EOF
1092 | '
1093 | 
1094 | test_expect_success 'git config - value' '
1095 | 	test_completion "git config color.pager " <<-\EOF
1096 | 	false Z
1097 | 	true Z
1098 | 	EOF
1099 | '
1100 | 
1101 | test_expect_success 'git config - direct completions' '
1102 | 	test_completion "git config branch.autoSetup" <<-\EOF
1103 | 	branch.autoSetupMerge Z
1104 | 	branch.autoSetupRebase Z
1105 | 	EOF
1106 | '
1107 | 
1108 | test_expect_success 'git -c - section' '
1109 | 	test_completion "git -c br" <<-\EOF
1110 | 	branch.Z
1111 | 	browser.Z
1112 | 	EOF
1113 | '
1114 | 
1115 | test_expect_success 'git -c - variable name' '
1116 | 	test_completion "git -c log.d" <<-\EOF
1117 | 	log.date=Z
1118 | 	log.decorate=Z
1119 | 	log.diffMerges=Z
1120 | 	EOF
1121 | '
1122 | 
1123 | test_expect_success 'git -c - value' '
1124 | 	test_completion "git -c color.pager=" <<-\EOF
1125 | 	false Z
1126 | 	true Z
1127 | 	EOF
1128 | '
1129 | 
1130 | test_expect_success 'git clone --config= - section' '
1131 | 	test_completion "git clone --config=br" <<-\EOF
1132 | 	branch.Z
1133 | 	browser.Z
1134 | 	EOF
1135 | '
1136 | 
1137 | test_expect_success 'git clone --config= - variable name' '
1138 | 	test_completion "git clone --config=log.d" <<-\EOF
1139 | 	log.date=Z
1140 | 	log.decorate=Z
1141 | 	log.diffMerges=Z
1142 | 	EOF
1143 | '
1144 | 
1145 | test_expect_success 'git clone --config= - value' '
1146 | 	test_completion "git clone --config=color.pager=" <<-\EOF
1147 | 	false Z
1148 | 	true Z
1149 | 	EOF
1150 | '
1151 | 
1152 | test_expect_success 'options with value' '
1153 | 	test_completion "git merge -X diff-algorithm=" <<-\EOF
1154 | 
1155 | 	EOF
1156 | '
1157 | 
1158 | test_expect_success 'main sets correct __git_cmd_idx' '
1159 | 	echo modified > file1 &&
1160 | 	touch file3 &&
1161 | 	test_completion "compdef _git ga=git_add${LF}ga --update f" "file1"
1162 | '
1163 | 
1164 | test_done
1165 | 


--------------------------------------------------------------------------------
/t/completion.t:
--------------------------------------------------------------------------------
   1 | #!/bin/sh
   2 | #
   3 | # Copyright (c) 2012-2020 Felipe Contreras
   4 | #
   5 | 
   6 | test_description='test bash completion'
   7 | 
   8 | . "$(dirname "$0")"/lib-bash.sh
   9 | 
  10 | version=$(git version)
  11 | if [[ "$version" == "git version "* ]]; then
  12 | 	printf "$version\ngit version 2.48\n" | sort -V -C || {
  13 | 		skip_all="git version with regression"
  14 | 		test_done
  15 | 	}
  16 | fi
  17 | 
  18 | complete ()
  19 | {
  20 | 	# do nothing
  21 | 	return 0
  22 | }
  23 | 
  24 | # Be careful when updating these lists:
  25 | #
  26 | # (1) The build tree may have build artifact from different branch, or
  27 | #     the user's $PATH may have a random executable that may begin
  28 | #     with "git-check" that are not part of the subcommands this build
  29 | #     will ship, e.g.  "check-ignore".  The tests for completion for
  30 | #     subcommand names tests how "check" is expanded; we limit the
  31 | #     possible candidates to "checkout" and "check-attr" to make sure
  32 | #     "check-attr", which is known by the filter function as a
  33 | #     subcommand to be thrown out, while excluding other random files
  34 | #     that happen to begin with "check" to avoid letting them get in
  35 | #     the way.
  36 | #
  37 | # (2) A test makes sure that common subcommands are included in the
  38 | #     completion for "git ", and a plumbing is excluded.  "add",
  39 | #     "rebase" and "ls-files" are listed for this.
  40 | 
  41 | GIT_TESTING_ALL_COMMAND_LIST='add checkout check-attr rebase ls-files'
  42 | GIT_TESTING_PORCELAIN_COMMAND_LIST='add checkout rebase'
  43 | 
  44 | . "$SRC_DIR/git-completion.bash"
  45 | 
  46 | # We don't need this function to actually join words or do anything special.
  47 | # Also, it's cleaner to avoid touching bash's internal completion variables.
  48 | # So let's override it with a minimal version for testing purposes.
  49 | __git_get_comp_words_by_ref ()
  50 | {
  51 | 	cword=$_cword
  52 | 	cur=${_words[cword]}
  53 | 	prev=${_words[cword-1]}
  54 | 	words=("${_words[@]}")
  55 | }
  56 | 
  57 | print_comp ()
  58 | {
  59 | 	local IFS=$'\n'
  60 | 	echo "${COMPREPLY[*]}" > out
  61 | }
  62 | 
  63 | run_completion ()
  64 | {
  65 | 	local -a COMPREPLY _words
  66 | 	local _cword
  67 | 	_words=( $1 )
  68 | 	test "${1: -1}" = ' ' && _words[${#_words[@]}+1]=''
  69 | 	(( _cword = ${#_words[@]} - 1 ))
  70 | 	__git_wrap__git_main && print_comp
  71 | }
  72 | 
  73 | run_func ()
  74 | {
  75 | 	local -a COMPREPLY &&
  76 | 	"$@" && print_comp
  77 | }
  78 | 
  79 | # Test high-level completion
  80 | # Arguments are:
  81 | # 1: typed text so far (cur)
  82 | # 2: expected completion
  83 | test_completion ()
  84 | {
  85 | 	if test $# -gt 1
  86 | 	then
  87 | 		printf '%s\n' "$2" >expected
  88 | 	else
  89 | 		sed -e 's/Z$//' |sort >expected
  90 | 	fi &&
  91 | 	run_completion "$1" &&
  92 | 	sort out >out_sorted &&
  93 | 	test_cmp expected out_sorted
  94 | }
  95 | 
  96 | # Test __gitcomp_opts.
  97 | # The first argument is the typed text so far (cur); the rest are
  98 | # passed to __gitcomp_opts.  Expected output comes is read from the
  99 | # standard input, like test_completion().
 100 | test_gitcomp_opts ()
 101 | {
 102 | 	local -a COMPREPLY &&
 103 | 	sed -e 's/Z$//' >expected &&
 104 | 	local cur="$1" &&
 105 | 	shift &&
 106 | 	__gitcomp_opts "$@" &&
 107 | 	print_comp &&
 108 | 	test_cmp expected out
 109 | }
 110 | 
 111 | # Test __gitcomp_nl
 112 | # Arguments are:
 113 | # 1: current word (cur)
 114 | # -: the rest are passed to __gitcomp_nl
 115 | test_gitcomp_nl ()
 116 | {
 117 | 	local -a COMPREPLY &&
 118 | 	sed -e 's/Z$//' >expected &&
 119 | 	local cur="$1" &&
 120 | 	shift &&
 121 | 	__gitcomp_nl "$@" &&
 122 | 	print_comp &&
 123 | 	test_cmp expected out
 124 | }
 125 | 
 126 | invalid_variable_name='${foo.bar}'
 127 | 
 128 | actual="$TRASH_DIRECTORY/actual"
 129 | 
 130 | if test_have_prereq MINGW
 131 | then
 132 | 	ROOT="$(pwd -W)"
 133 | else
 134 | 	ROOT="$(pwd)"
 135 | fi
 136 | 
 137 | test_expect_success 'setup for __git_find_repo_path/__gitdir tests' '
 138 | 	mkdir -p subdir/subsubdir &&
 139 | 	mkdir -p non-repo &&
 140 | 	git init -b main otherrepo
 141 | '
 142 | 
 143 | test_expect_success '__git_find_repo_path - from command line (through $__git_dir)' '
 144 | 	echo "$ROOT/otherrepo/.git" >expected &&
 145 | 	(
 146 | 		__git_dir="$ROOT/otherrepo/.git" &&
 147 | 		__git_find_repo_path &&
 148 | 		echo "$__git_repo_path" >"$actual"
 149 | 	) &&
 150 | 	test_cmp expected "$actual"
 151 | '
 152 | 
 153 | test_expect_success '__git_find_repo_path - .git directory in cwd' '
 154 | 	echo ".git" >expected &&
 155 | 	(
 156 | 		__git_find_repo_path &&
 157 | 		echo "$__git_repo_path" >"$actual"
 158 | 	) &&
 159 | 	test_cmp expected "$actual"
 160 | '
 161 | 
 162 | test_expect_success '__git_find_repo_path - .git directory in parent' '
 163 | 	echo "$ROOT/.git" >expected &&
 164 | 	(
 165 | 		cd subdir/subsubdir &&
 166 | 		__git_find_repo_path &&
 167 | 		echo "$__git_repo_path" >"$actual"
 168 | 	) &&
 169 | 	test_cmp expected "$actual"
 170 | '
 171 | 
 172 | test_expect_success '__git_find_repo_path - cwd is a .git directory' '
 173 | 	echo "." >expected &&
 174 | 	(
 175 | 		cd .git &&
 176 | 		__git_find_repo_path &&
 177 | 		echo "$__git_repo_path" >"$actual"
 178 | 	) &&
 179 | 	test_cmp expected "$actual"
 180 | '
 181 | 
 182 | test_expect_success '__git_find_repo_path - parent is a .git directory' '
 183 | 	echo "$ROOT/.git" >expected &&
 184 | 	(
 185 | 		cd .git/objects &&
 186 | 		__git_find_repo_path &&
 187 | 		echo "$__git_repo_path" >"$actual"
 188 | 	) &&
 189 | 	test_cmp expected "$actual"
 190 | '
 191 | 
 192 | test_expect_success '__git_find_repo_path - $GIT_DIR set while .git directory in cwd' '
 193 | 	echo "$ROOT/otherrepo/.git" >expected &&
 194 | 	(
 195 | 		GIT_DIR="$ROOT/otherrepo/.git" &&
 196 | 		export GIT_DIR &&
 197 | 		__git_find_repo_path &&
 198 | 		echo "$__git_repo_path" >"$actual"
 199 | 	) &&
 200 | 	test_cmp expected "$actual"
 201 | '
 202 | 
 203 | test_expect_success '__git_find_repo_path - $GIT_DIR set while .git directory in parent' '
 204 | 	echo "$ROOT/otherrepo/.git" >expected &&
 205 | 	(
 206 | 		GIT_DIR="$ROOT/otherrepo/.git" &&
 207 | 		export GIT_DIR &&
 208 | 		cd subdir &&
 209 | 		__git_find_repo_path &&
 210 | 		echo "$__git_repo_path" >"$actual"
 211 | 	) &&
 212 | 	test_cmp expected "$actual"
 213 | '
 214 | 
 215 | test_expect_success '__git_find_repo_path - from command line while "git -C"' '
 216 | 	echo "$ROOT/.git" >expected &&
 217 | 	(
 218 | 		__git_dir="$ROOT/.git" &&
 219 | 		__git_C_args=(-C otherrepo) &&
 220 | 		__git_find_repo_path &&
 221 | 		echo "$__git_repo_path" >"$actual"
 222 | 	) &&
 223 | 	test_cmp expected "$actual"
 224 | '
 225 | 
 226 | test_expect_success '__git_find_repo_path - relative dir from command line and "git -C"' '
 227 | 	echo "$ROOT/otherrepo/.git" >expected &&
 228 | 	(
 229 | 		cd subdir &&
 230 | 		__git_dir="otherrepo/.git" &&
 231 | 		__git_C_args=(-C ..) &&
 232 | 		__git_find_repo_path &&
 233 | 		echo "$__git_repo_path" >"$actual"
 234 | 	) &&
 235 | 	test_cmp expected "$actual"
 236 | '
 237 | 
 238 | test_expect_success '__git_find_repo_path - $GIT_DIR set while "git -C"' '
 239 | 	echo "$ROOT/.git" >expected &&
 240 | 	(
 241 | 		GIT_DIR="$ROOT/.git" &&
 242 | 		export GIT_DIR &&
 243 | 		__git_C_args=(-C otherrepo) &&
 244 | 		__git_find_repo_path &&
 245 | 		echo "$__git_repo_path" >"$actual"
 246 | 	) &&
 247 | 	test_cmp expected "$actual"
 248 | '
 249 | 
 250 | test_expect_success '__git_find_repo_path - relative dir in $GIT_DIR and "git -C"' '
 251 | 	echo "$ROOT/otherrepo/.git" >expected &&
 252 | 	(
 253 | 		cd subdir &&
 254 | 		GIT_DIR="otherrepo/.git" &&
 255 | 		export GIT_DIR &&
 256 | 		__git_C_args=(-C ..) &&
 257 | 		__git_find_repo_path &&
 258 | 		echo "$__git_repo_path" >"$actual"
 259 | 	) &&
 260 | 	test_cmp expected "$actual"
 261 | '
 262 | 
 263 | test_expect_success '__git_find_repo_path - "git -C" while .git directory in cwd' '
 264 | 	echo "$ROOT/otherrepo/.git" >expected &&
 265 | 	(
 266 | 		__git_C_args=(-C otherrepo) &&
 267 | 		__git_find_repo_path &&
 268 | 		echo "$__git_repo_path" >"$actual"
 269 | 	) &&
 270 | 	test_cmp expected "$actual"
 271 | '
 272 | 
 273 | test_expect_success '__git_find_repo_path - "git -C" while cwd is a .git directory' '
 274 | 	echo "$ROOT/otherrepo/.git" >expected &&
 275 | 	(
 276 | 		cd .git &&
 277 | 		__git_C_args=(-C .. -C otherrepo) &&
 278 | 		__git_find_repo_path &&
 279 | 		echo "$__git_repo_path" >"$actual"
 280 | 	) &&
 281 | 	test_cmp expected "$actual"
 282 | '
 283 | 
 284 | test_expect_success '__git_find_repo_path - "git -C" while .git directory in parent' '
 285 | 	echo "$ROOT/otherrepo/.git" >expected &&
 286 | 	(
 287 | 		cd subdir &&
 288 | 		__git_C_args=(-C .. -C otherrepo) &&
 289 | 		__git_find_repo_path &&
 290 | 		echo "$__git_repo_path" >"$actual"
 291 | 	) &&
 292 | 	test_cmp expected "$actual"
 293 | '
 294 | 
 295 | test_expect_success '__git_find_repo_path - non-existing path in "git -C"' '
 296 | 	(
 297 | 		__git_C_args=(-C non-existing) &&
 298 | 		test_must_fail __git_find_repo_path &&
 299 | 		printf "$__git_repo_path" >"$actual"
 300 | 	) &&
 301 | 	test_must_be_empty "$actual"
 302 | '
 303 | 
 304 | test_expect_success '__git_find_repo_path - non-existing path in $__git_dir' '
 305 | 	(
 306 | 		__git_dir="non-existing" &&
 307 | 		test_must_fail __git_find_repo_path &&
 308 | 		printf "$__git_repo_path" >"$actual"
 309 | 	) &&
 310 | 	test_must_be_empty "$actual"
 311 | '
 312 | 
 313 | test_expect_success '__git_find_repo_path - non-existing $GIT_DIR' '
 314 | 	(
 315 | 		GIT_DIR="$ROOT/non-existing" &&
 316 | 		export GIT_DIR &&
 317 | 		test_must_fail __git_find_repo_path &&
 318 | 		printf "$__git_repo_path" >"$actual"
 319 | 	) &&
 320 | 	test_must_be_empty "$actual"
 321 | '
 322 | 
 323 | test_expect_success '__git_find_repo_path - gitfile in cwd' '
 324 | 	echo "$ROOT/otherrepo/.git" >expected &&
 325 | 	echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
 326 | 	test_when_finished "rm -f subdir/.git" &&
 327 | 	(
 328 | 		cd subdir &&
 329 | 		__git_find_repo_path &&
 330 | 		echo "$__git_repo_path" >"$actual"
 331 | 	) &&
 332 | 	test_cmp expected "$actual"
 333 | '
 334 | 
 335 | test_expect_success '__git_find_repo_path - gitfile in parent' '
 336 | 	echo "$ROOT/otherrepo/.git" >expected &&
 337 | 	echo "gitdir: $ROOT/otherrepo/.git" >subdir/.git &&
 338 | 	test_when_finished "rm -f subdir/.git" &&
 339 | 	(
 340 | 		cd subdir/subsubdir &&
 341 | 		__git_find_repo_path &&
 342 | 		echo "$__git_repo_path" >"$actual"
 343 | 	) &&
 344 | 	test_cmp expected "$actual"
 345 | '
 346 | 
 347 | test_expect_success SYMLINKS '__git_find_repo_path - resulting path avoids symlinks' '
 348 | 	echo "$ROOT/otherrepo/.git" >expected &&
 349 | 	mkdir otherrepo/dir &&
 350 | 	test_when_finished "rm -rf otherrepo/dir" &&
 351 | 	ln -s otherrepo/dir link &&
 352 | 	test_when_finished "rm -f link" &&
 353 | 	(
 354 | 		cd link &&
 355 | 		__git_find_repo_path &&
 356 | 		echo "$__git_repo_path" >"$actual"
 357 | 	) &&
 358 | 	test_cmp expected "$actual"
 359 | '
 360 | 
 361 | test_expect_success '__git_find_repo_path - not a git repository' '
 362 | 	(
 363 | 		cd non-repo &&
 364 | 		GIT_CEILING_DIRECTORIES="$ROOT" &&
 365 | 		export GIT_CEILING_DIRECTORIES &&
 366 | 		test_must_fail __git_find_repo_path &&
 367 | 		printf "$__git_repo_path" >"$actual"
 368 | 	) &&
 369 | 	test_must_be_empty "$actual"
 370 | '
 371 | 
 372 | test_expect_success '__gitdir - finds repo' '
 373 | 	echo "$ROOT/.git" >expected &&
 374 | 	(
 375 | 		cd subdir/subsubdir &&
 376 | 		__gitdir >"$actual"
 377 | 	) &&
 378 | 	test_cmp expected "$actual"
 379 | '
 380 | 
 381 | 
 382 | test_expect_success '__gitdir - returns error when cannot find repo' '
 383 | 	(
 384 | 		__git_dir="non-existing" &&
 385 | 		test_must_fail __gitdir >"$actual"
 386 | 	) &&
 387 | 	test_must_be_empty "$actual"
 388 | '
 389 | 
 390 | test_expect_success '__gitdir - repo as argument' '
 391 | 	echo "otherrepo/.git" >expected &&
 392 | 	(
 393 | 		__gitdir "otherrepo" >"$actual"
 394 | 	) &&
 395 | 	test_cmp expected "$actual"
 396 | '
 397 | 
 398 | test_expect_success '__gitdir - remote as argument' '
 399 | 	echo "remote" >expected &&
 400 | 	(
 401 | 		__gitdir "remote" >"$actual"
 402 | 	) &&
 403 | 	test_cmp expected "$actual"
 404 | '
 405 | 
 406 | 
 407 | test_expect_success '__git_dequote - plain unquoted word' '
 408 | 	__git_dequote unquoted-word &&
 409 | 	verbose test unquoted-word = "$dequoted_word"
 410 | '
 411 | 
 412 | # input:    b\a\c\k\'\\\"s\l\a\s\h\es
 413 | # expected: back'\"slashes
 414 | test_expect_success '__git_dequote - backslash escaped' '
 415 | 	__git_dequote "b\a\c\k\\'\''\\\\\\\"s\l\a\s\h\es" &&
 416 | 	verbose test "back'\''\\\"slashes" = "$dequoted_word"
 417 | '
 418 | 
 419 | # input:    sin'gle\' '"quo'ted
 420 | # expected: single\ "quoted
 421 | test_expect_success '__git_dequote - single quoted' '
 422 | 	__git_dequote "'"sin'gle\\\\' '\\\"quo'ted"'" &&
 423 | 	verbose test '\''single\ "quoted'\'' = "$dequoted_word"
 424 | '
 425 | 
 426 | # input:    dou"ble\\" "\"\quot"ed
 427 | # expected: double\ "\quoted
 428 | test_expect_success '__git_dequote - double quoted' '
 429 | 	__git_dequote '\''dou"ble\\" "\"\quot"ed'\'' &&
 430 | 	verbose test '\''double\ "\quoted'\'' = "$dequoted_word"
 431 | '
 432 | 
 433 | # input: 'open single quote
 434 | test_expect_success '__git_dequote - open single quote' '
 435 | 	__git_dequote "'\''open single quote" &&
 436 | 	verbose test "open single quote" = "$dequoted_word"
 437 | '
 438 | 
 439 | # input: "open double quote
 440 | test_expect_success '__git_dequote - open double quote' '
 441 | 	__git_dequote "\"open double quote" &&
 442 | 	verbose test "open double quote" = "$dequoted_word"
 443 | '
 444 | 
 445 | 
 446 | test_expect_success '__gitcomp_direct - puts everything into COMPREPLY as-is' '
 447 | 	sed -e "s/Z$//g" >expected <<-EOF &&
 448 | 	with-trailing-space Z
 449 | 	without-trailing-spaceZ
 450 | 	--option Z
 451 | 	--option=Z
 452 | 	$invalid_variable_name Z
 453 | 	EOF
 454 | 	(
 455 | 		cur=should_be_ignored &&
 456 | 		run_func __gitcomp_direct "$(cat expected)"
 457 | 	) &&
 458 | 	test_cmp expected out
 459 | '
 460 | 
 461 | test_expect_success '__gitcomp_opts - trailing space - options' '
 462 | 	test_gitcomp_opts "--re" "--dry-run --reuse-message= --reedit-message=
 463 | 		--reset-author" <<-EOF
 464 | 	--reuse-message=Z
 465 | 	--reedit-message=Z
 466 | 	--reset-author Z
 467 | 	EOF
 468 | '
 469 | 
 470 | test_expect_success '__gitcomp_opts - trailing space - config keys' '
 471 | 	test_gitcomp_opts "br" "branch. branch.autosetupmerge
 472 | 		branch.autosetuprebase browser." <<-\EOF
 473 | 	branch.Z
 474 | 	branch.autosetupmerge Z
 475 | 	branch.autosetuprebase Z
 476 | 	browser.Z
 477 | 	EOF
 478 | '
 479 | 
 480 | test_expect_success '__gitcomp_opts - option parameter' '
 481 | 	test_gitcomp_opts "--strategy=re" "octopus ours recursive resolve subtree" \
 482 | 		"" "re" <<-\EOF
 483 | 	recursive Z
 484 | 	resolve Z
 485 | 	EOF
 486 | '
 487 | 
 488 | test_expect_success '__gitcomp_opts - prefix' '
 489 | 	test_gitcomp_opts "branch.maint.me" "remote merge mergeoptions rebase" \
 490 | 		"branch.maint." "me" <<-\EOF
 491 | 	branch.maint.merge Z
 492 | 	branch.maint.mergeoptions Z
 493 | 	EOF
 494 | '
 495 | 
 496 | test_expect_success '__gitcomp_opts - suffix' '
 497 | 	test_gitcomp_opts "branch.ma" "master maint next seen" "branch." \
 498 | 		"ma" "." <<-\EOF
 499 | 	branch.master.Z
 500 | 	branch.maint.Z
 501 | 	EOF
 502 | '
 503 | 
 504 | test_expect_success '__gitcomp_opts - ignore optional negative options' '
 505 | 	test_gitcomp_opts "--" "--abc --def --no-one -- --no-two" <<-\EOF
 506 | 	--abc Z
 507 | 	--def Z
 508 | 	--no-one Z
 509 | 	--no-... Z
 510 | 	EOF
 511 | '
 512 | 
 513 | test_expect_success '__gitcomp_opts - ignore/narrow optional negative options' '
 514 | 	test_gitcomp_opts "--a" "--abc --abcdef --no-one -- --no-two" <<-\EOF
 515 | 	--abc Z
 516 | 	--abcdef Z
 517 | 	EOF
 518 | '
 519 | 
 520 | test_expect_success '__gitcomp_opts - ignore/narrow optional negative options' '
 521 | 	test_gitcomp_opts "--n" "--abc --def --no-one -- --no-two" <<-\EOF
 522 | 	--no-one Z
 523 | 	--no-... Z
 524 | 	EOF
 525 | '
 526 | 
 527 | test_expect_success '__gitcomp_opts - expand all negative options' '
 528 | 	test_gitcomp_opts "--no-" "--abc --def --no-one -- --no-two" <<-\EOF
 529 | 	--no-one Z
 530 | 	--no-two Z
 531 | 	EOF
 532 | '
 533 | 
 534 | test_expect_success '__gitcomp_opts - expand/narrow all negative options' '
 535 | 	test_gitcomp_opts "--no-o" "--abc --def --no-one -- --no-two" <<-\EOF
 536 | 	--no-one Z
 537 | 	EOF
 538 | '
 539 | 
 540 | test_expect_success '__gitcomp_opts - equal skip' '
 541 | 	test_gitcomp_opts "--option=" "--option=" <<-\EOF &&
 542 | 
 543 | 	EOF
 544 | 	test_gitcomp_opts "option=" "option=" <<-\EOF
 545 | 
 546 | 	EOF
 547 | '
 548 | 
 549 | test_expect_success '__gitcomp_opts - doesnt fail because of invalid variable name' '
 550 | 	run_func __gitcomp_opts "$invalid_variable_name"
 551 | '
 552 | 
 553 | read -r -d "" refs <<-\EOF
 554 | main
 555 | maint
 556 | next
 557 | seen
 558 | EOF
 559 | 
 560 | test_expect_success '__gitcomp_nl - trailing space' '
 561 | 	test_gitcomp_nl "m" "$refs" <<-EOF
 562 | 	main Z
 563 | 	maint Z
 564 | 	EOF
 565 | '
 566 | 
 567 | test_expect_success '__gitcomp_nl - prefix' '
 568 | 	test_gitcomp_nl "branch.m" "$refs" "branch." "m" <<-EOF
 569 | 	branch.main Z
 570 | 	branch.maint Z
 571 | 	EOF
 572 | '
 573 | 
 574 | test_expect_success '__gitcomp_nl - suffix' '
 575 | 	test_gitcomp_nl "branch.ma" "$refs" "branch." "ma" "." <<-\EOF
 576 | 	branch.main.Z
 577 | 	branch.maint.Z
 578 | 	EOF
 579 | '
 580 | 
 581 | test_expect_success '__gitcomp_nl - no suffix' '
 582 | 	test_gitcomp_nl "ma" "$refs" "" "ma" "" <<-\EOF
 583 | 	mainZ
 584 | 	maintZ
 585 | 	EOF
 586 | '
 587 | 
 588 | test_expect_success '__gitcomp_nl - doesnt fail because of invalid variable name' '
 589 | 	run_func __gitcomp_nl "$invalid_variable_name"
 590 | '
 591 | 
 592 | test_expect_success '__git_remotes - list remotes from $GIT_DIR/remotes and from config file' '
 593 | 	cat >expect <<-EOF &&
 594 | 	remote_from_file_1
 595 | 	remote_from_file_2
 596 | 	remote_in_config_1
 597 | 	remote_in_config_2
 598 | 	EOF
 599 | 	test_when_finished "rm -rf .git/remotes" &&
 600 | 	mkdir -p .git/remotes &&
 601 | 	>.git/remotes/remote_from_file_1 &&
 602 | 	>.git/remotes/remote_from_file_2 &&
 603 | 	test_when_finished "git remote remove remote_in_config_1" &&
 604 | 	git remote add remote_in_config_1 git://remote_1 &&
 605 | 	test_when_finished "git remote remove remote_in_config_2" &&
 606 | 	git remote add remote_in_config_2 git://remote_2 &&
 607 | 	(
 608 | 		__git_remotes >actual
 609 | 	) &&
 610 | 	test_cmp expect actual
 611 | '
 612 | 
 613 | test_expect_success '__git_is_configured_remote' '
 614 | 	test_when_finished "git remote remove remote_1" &&
 615 | 	git remote add remote_1 git://remote_1 &&
 616 | 	test_when_finished "git remote remove remote_2" &&
 617 | 	git remote add remote_2 git://remote_2 &&
 618 | 	(
 619 | 		verbose __git_is_configured_remote remote_2 &&
 620 | 		test_must_fail __git_is_configured_remote non-existent
 621 | 	)
 622 | '
 623 | 
 624 | test_expect_success 'setup for ref completion' '
 625 | 	git commit --allow-empty -m initial &&
 626 | 	git branch -M main &&
 627 | 	git branch matching-branch &&
 628 | 	git tag matching-tag &&
 629 | 	(
 630 | 		cd otherrepo &&
 631 | 		git commit --allow-empty -m initial &&
 632 | 		git branch -m main main-in-other &&
 633 | 		git branch branch-in-other &&
 634 | 		git tag tag-in-other
 635 | 	) &&
 636 | 	git remote add other "$ROOT/otherrepo/.git" &&
 637 | 	git fetch --no-tags other &&
 638 | 	rm -f .git/FETCH_HEAD &&
 639 | 	git init thirdrepo
 640 | '
 641 | 
 642 | test_expect_success '__git_refs - simple' '
 643 | 	cat >expected <<-EOF &&
 644 | 	HEAD
 645 | 	main
 646 | 	matching-branch
 647 | 	other/branch-in-other
 648 | 	other/main-in-other
 649 | 	matching-tag
 650 | 	EOF
 651 | 	(
 652 | 		cur= &&
 653 | 		__git_refs >"$actual"
 654 | 	) &&
 655 | 	test_cmp expected "$actual"
 656 | '
 657 | 
 658 | test_expect_success '__git_refs - full refs' '
 659 | 	cat >expected <<-EOF &&
 660 | 	refs/heads/main
 661 | 	refs/heads/matching-branch
 662 | 	refs/remotes/other/branch-in-other
 663 | 	refs/remotes/other/main-in-other
 664 | 	refs/tags/matching-tag
 665 | 	EOF
 666 | 	(
 667 | 		cur=refs/heads/ &&
 668 | 		__git_refs >"$actual"
 669 | 	) &&
 670 | 	test_cmp expected "$actual"
 671 | '
 672 | 
 673 | test_expect_success '__git_refs - repo given on the command line' '
 674 | 	cat >expected <<-EOF &&
 675 | 	HEAD
 676 | 	branch-in-other
 677 | 	main-in-other
 678 | 	tag-in-other
 679 | 	EOF
 680 | 	(
 681 | 		__git_dir="$ROOT/otherrepo/.git" &&
 682 | 		cur= &&
 683 | 		__git_refs >"$actual"
 684 | 	) &&
 685 | 	test_cmp expected "$actual"
 686 | '
 687 | 
 688 | test_expect_success '__git_refs - remote on local file system' '
 689 | 	cat >expected <<-EOF &&
 690 | 	HEAD
 691 | 	branch-in-other
 692 | 	main-in-other
 693 | 	tag-in-other
 694 | 	EOF
 695 | 	(
 696 | 		cur= &&
 697 | 		__git_refs otherrepo >"$actual"
 698 | 	) &&
 699 | 	test_cmp expected "$actual"
 700 | '
 701 | 
 702 | test_expect_success '__git_refs - remote on local file system - full refs' '
 703 | 	cat >expected <<-EOF &&
 704 | 	refs/heads/branch-in-other
 705 | 	refs/heads/main-in-other
 706 | 	refs/tags/tag-in-other
 707 | 	EOF
 708 | 	(
 709 | 		cur=refs/ &&
 710 | 		__git_refs otherrepo >"$actual"
 711 | 	) &&
 712 | 	test_cmp expected "$actual"
 713 | '
 714 | 
 715 | test_expect_success '__git_refs - configured remote' '
 716 | 	cat >expected <<-EOF &&
 717 | 	HEAD
 718 | 	branch-in-other
 719 | 	main-in-other
 720 | 	EOF
 721 | 	(
 722 | 		cur= &&
 723 | 		__git_refs other >"$actual"
 724 | 	) &&
 725 | 	test_cmp expected "$actual"
 726 | '
 727 | 
 728 | test_expect_success '__git_refs - configured remote - full refs' '
 729 | 	cat >expected <<-EOF &&
 730 | 	HEAD
 731 | 	refs/heads/branch-in-other
 732 | 	refs/heads/main-in-other
 733 | 	refs/tags/tag-in-other
 734 | 	EOF
 735 | 	(
 736 | 		cur=refs/ &&
 737 | 		__git_refs other >"$actual"
 738 | 	) &&
 739 | 	test_cmp expected "$actual"
 740 | '
 741 | 
 742 | test_expect_success '__git_refs - configured remote - repo given on the command line' '
 743 | 	cat >expected <<-EOF &&
 744 | 	HEAD
 745 | 	branch-in-other
 746 | 	main-in-other
 747 | 	EOF
 748 | 	(
 749 | 		cd thirdrepo &&
 750 | 		__git_dir="$ROOT/.git" &&
 751 | 		cur= &&
 752 | 		__git_refs other >"$actual"
 753 | 	) &&
 754 | 	test_cmp expected "$actual"
 755 | '
 756 | 
 757 | test_expect_success '__git_refs - configured remote - full refs - repo given on the command line' '
 758 | 	cat >expected <<-EOF &&
 759 | 	HEAD
 760 | 	refs/heads/branch-in-other
 761 | 	refs/heads/main-in-other
 762 | 	refs/tags/tag-in-other
 763 | 	EOF
 764 | 	(
 765 | 		cd thirdrepo &&
 766 | 		__git_dir="$ROOT/.git" &&
 767 | 		cur=refs/ &&
 768 | 		__git_refs other >"$actual"
 769 | 	) &&
 770 | 	test_cmp expected "$actual"
 771 | '
 772 | 
 773 | test_expect_success '__git_refs - configured remote - remote name matches a directory' '
 774 | 	cat >expected <<-EOF &&
 775 | 	HEAD
 776 | 	branch-in-other
 777 | 	main-in-other
 778 | 	EOF
 779 | 	mkdir other &&
 780 | 	test_when_finished "rm -rf other" &&
 781 | 	(
 782 | 		cur= &&
 783 | 		__git_refs other >"$actual"
 784 | 	) &&
 785 | 	test_cmp expected "$actual"
 786 | '
 787 | 
 788 | test_expect_success '__git_refs - URL remote' '
 789 | 	cat >expected <<-EOF &&
 790 | 	HEAD
 791 | 	branch-in-other
 792 | 	main-in-other
 793 | 	tag-in-other
 794 | 	EOF
 795 | 	(
 796 | 		cur= &&
 797 | 		__git_refs "file://$ROOT/otherrepo/.git" >"$actual"
 798 | 	) &&
 799 | 	test_cmp expected "$actual"
 800 | '
 801 | 
 802 | test_expect_success '__git_refs - URL remote - full refs' '
 803 | 	cat >expected <<-EOF &&
 804 | 	HEAD
 805 | 	refs/heads/branch-in-other
 806 | 	refs/heads/main-in-other
 807 | 	refs/tags/tag-in-other
 808 | 	EOF
 809 | 	(
 810 | 		cur=refs/ &&
 811 | 		__git_refs "file://$ROOT/otherrepo/.git" >"$actual"
 812 | 	) &&
 813 | 	test_cmp expected "$actual"
 814 | '
 815 | 
 816 | test_expect_success '__git_refs - non-existing remote' '
 817 | 	(
 818 | 		cur= &&
 819 | 		__git_refs non-existing >"$actual"
 820 | 	) &&
 821 | 	test_must_be_empty "$actual"
 822 | '
 823 | 
 824 | test_expect_success '__git_refs - non-existing remote - full refs' '
 825 | 	(
 826 | 		cur=refs/ &&
 827 | 		__git_refs non-existing >"$actual"
 828 | 	) &&
 829 | 	test_must_be_empty "$actual"
 830 | '
 831 | 
 832 | test_expect_success '__git_refs - non-existing URL remote' '
 833 | 	(
 834 | 		cur= &&
 835 | 		__git_refs "file://$ROOT/non-existing" >"$actual"
 836 | 	) &&
 837 | 	test_must_be_empty "$actual"
 838 | '
 839 | 
 840 | test_expect_success '__git_refs - non-existing URL remote - full refs' '
 841 | 	(
 842 | 		cur=refs/ &&
 843 | 		__git_refs "file://$ROOT/non-existing" >"$actual"
 844 | 	) &&
 845 | 	test_must_be_empty "$actual"
 846 | '
 847 | 
 848 | test_expect_success '__git_refs - not in a git repository' '
 849 | 	(
 850 | 		GIT_CEILING_DIRECTORIES="$ROOT" &&
 851 | 		export GIT_CEILING_DIRECTORIES &&
 852 | 		cd subdir &&
 853 | 		cur= &&
 854 | 		__git_refs >"$actual"
 855 | 	) &&
 856 | 	test_must_be_empty "$actual"
 857 | '
 858 | 
 859 | test_expect_success '__git_refs - unique remote branches for git checkout DWIMery' '
 860 | 	cat >expected <<-EOF &&
 861 | 	HEAD
 862 | 	main
 863 | 	matching-branch
 864 | 	other/ambiguous
 865 | 	other/branch-in-other
 866 | 	other/main-in-other
 867 | 	remote/ambiguous
 868 | 	remote/branch-in-remote
 869 | 	matching-tag
 870 | 	branch-in-other
 871 | 	branch-in-remote
 872 | 	main-in-other
 873 | 	EOF
 874 | 	for remote_ref in refs/remotes/other/ambiguous \
 875 | 		refs/remotes/remote/ambiguous \
 876 | 		refs/remotes/remote/branch-in-remote
 877 | 	do
 878 | 		git update-ref $remote_ref main &&
 879 | 		test_when_finished "git update-ref -d $remote_ref" || return 1
 880 | 	done &&
 881 | 	(
 882 | 		cur= &&
 883 | 		__git_refs "" 1 >"$actual"
 884 | 	) &&
 885 | 	test_cmp expected "$actual"
 886 | '
 887 | 
 888 | test_expect_success '__git_refs - after --opt=' '
 889 | 	cat >expected <<-EOF &&
 890 | 	HEAD
 891 | 	main
 892 | 	matching-branch
 893 | 	other/branch-in-other
 894 | 	other/main-in-other
 895 | 	matching-tag
 896 | 	EOF
 897 | 	(
 898 | 		cur="--opt=" &&
 899 | 		__git_refs "" "" "" "" >"$actual"
 900 | 	) &&
 901 | 	test_cmp expected "$actual"
 902 | '
 903 | 
 904 | test_expect_success '__git_refs - after --opt= - full refs' '
 905 | 	cat >expected <<-EOF &&
 906 | 	refs/heads/main
 907 | 	refs/heads/matching-branch
 908 | 	refs/remotes/other/branch-in-other
 909 | 	refs/remotes/other/main-in-other
 910 | 	refs/tags/matching-tag
 911 | 	EOF
 912 | 	(
 913 | 		cur="--opt=refs/" &&
 914 | 		__git_refs "" "" "" refs/ >"$actual"
 915 | 	) &&
 916 | 	test_cmp expected "$actual"
 917 | '
 918 | 
 919 | test_expect_success '__git refs - excluding refs' '
 920 | 	cat >expected <<-EOF &&
 921 | 	^HEAD
 922 | 	^main
 923 | 	^matching-branch
 924 | 	^other/branch-in-other
 925 | 	^other/main-in-other
 926 | 	^matching-tag
 927 | 	EOF
 928 | 	(
 929 | 		cur=^ &&
 930 | 		__git_refs >"$actual"
 931 | 	) &&
 932 | 	test_cmp expected "$actual"
 933 | '
 934 | 
 935 | test_expect_success '__git refs - excluding full refs' '
 936 | 	cat >expected <<-EOF &&
 937 | 	^refs/heads/main
 938 | 	^refs/heads/matching-branch
 939 | 	^refs/remotes/other/branch-in-other
 940 | 	^refs/remotes/other/main-in-other
 941 | 	^refs/tags/matching-tag
 942 | 	EOF
 943 | 	(
 944 | 		cur=^refs/ &&
 945 | 		__git_refs >"$actual"
 946 | 	) &&
 947 | 	test_cmp expected "$actual"
 948 | '
 949 | 
 950 | test_expect_success 'setup for filtering matching refs' '
 951 | 	git branch matching/branch &&
 952 | 	git tag matching/tag &&
 953 | 	git -C otherrepo branch matching/branch-in-other &&
 954 | 	git fetch --no-tags other &&
 955 | 	rm -f .git/FETCH_HEAD
 956 | '
 957 | 
 958 | test_expect_success '__git_refs - do not filter refs unless told so' '
 959 | 	cat >expected <<-EOF &&
 960 | 	HEAD
 961 | 	main
 962 | 	matching-branch
 963 | 	matching/branch
 964 | 	other/branch-in-other
 965 | 	other/main-in-other
 966 | 	other/matching/branch-in-other
 967 | 	matching-tag
 968 | 	matching/tag
 969 | 	EOF
 970 | 	(
 971 | 		cur=main &&
 972 | 		__git_refs >"$actual"
 973 | 	) &&
 974 | 	test_cmp expected "$actual"
 975 | '
 976 | 
 977 | test_expect_success '__git_refs - only matching refs' '
 978 | 	cat >expected <<-EOF &&
 979 | 	matching-branch
 980 | 	matching/branch
 981 | 	matching-tag
 982 | 	matching/tag
 983 | 	EOF
 984 | 	(
 985 | 		cur=mat &&
 986 | 		__git_refs "" "" "" "$cur" >"$actual"
 987 | 	) &&
 988 | 	test_cmp expected "$actual"
 989 | '
 990 | 
 991 | test_expect_success '__git_refs - only matching refs - full refs' '
 992 | 	cat >expected <<-EOF &&
 993 | 	refs/heads/matching-branch
 994 | 	refs/heads/matching/branch
 995 | 	EOF
 996 | 	(
 997 | 		cur=refs/heads/mat &&
 998 | 		__git_refs "" "" "" "$cur" >"$actual"
 999 | 	) &&
1000 | 	test_cmp expected "$actual"
1001 | '
1002 | 
1003 | test_expect_success '__git_refs - only matching refs - remote on local file system' '
1004 | 	cat >expected <<-EOF &&
1005 | 	main-in-other
1006 | 	matching/branch-in-other
1007 | 	EOF
1008 | 	(
1009 | 		cur=ma &&
1010 | 		__git_refs otherrepo "" "" "$cur" >"$actual"
1011 | 	) &&
1012 | 	test_cmp expected "$actual"
1013 | '
1014 | 
1015 | test_expect_success '__git_refs - only matching refs - configured remote' '
1016 | 	cat >expected <<-EOF &&
1017 | 	main-in-other
1018 | 	matching/branch-in-other
1019 | 	EOF
1020 | 	(
1021 | 		cur=ma &&
1022 | 		__git_refs other "" "" "$cur" >"$actual"
1023 | 	) &&
1024 | 	test_cmp expected "$actual"
1025 | '
1026 | 
1027 | test_expect_success '__git_refs - only matching refs - remote - full refs' '
1028 | 	cat >expected <<-EOF &&
1029 | 	refs/heads/main-in-other
1030 | 	refs/heads/matching/branch-in-other
1031 | 	EOF
1032 | 	(
1033 | 		cur=refs/heads/ma &&
1034 | 		__git_refs other "" "" "$cur" >"$actual"
1035 | 	) &&
1036 | 	test_cmp expected "$actual"
1037 | '
1038 | 
1039 | test_expect_success '__git_refs - only matching refs - checkout DWIMery' '
1040 | 	cat >expected <<-EOF &&
1041 | 	matching-branch
1042 | 	matching/branch
1043 | 	matching-tag
1044 | 	matching/tag
1045 | 	matching/branch-in-other
1046 | 	EOF
1047 | 	for remote_ref in refs/remotes/other/ambiguous \
1048 | 		refs/remotes/remote/ambiguous \
1049 | 		refs/remotes/remote/branch-in-remote
1050 | 	do
1051 | 		git update-ref $remote_ref main &&
1052 | 		test_when_finished "git update-ref -d $remote_ref" || return 1
1053 | 	done &&
1054 | 	(
1055 | 		cur=mat &&
1056 | 		__git_refs "" 1 "" "$cur" >"$actual"
1057 | 	) &&
1058 | 	test_cmp expected "$actual"
1059 | '
1060 | 
1061 | test_expect_success 'teardown after filtering matching refs' '
1062 | 	git branch -d matching/branch &&
1063 | 	git tag -d matching/tag &&
1064 | 	git update-ref -d refs/remotes/other/matching/branch-in-other &&
1065 | 	git -C otherrepo branch -D matching/branch-in-other
1066 | '
1067 | 
1068 | test_expect_success '__git_refs - for-each-ref format specifiers in prefix' '
1069 | 	cat >expected <<-EOF &&
1070 | 	evil-%%-%42-%(refname)..main
1071 | 	EOF
1072 | 	(
1073 | 		cur="evil-%%-%42-%(refname)..mai" &&
1074 | 		__git_refs "" "" "evil-%%-%42-%(refname).." mai >"$actual"
1075 | 	) &&
1076 | 	test_cmp expected "$actual"
1077 | '
1078 | 
1079 | test_expect_success '__git_complete_refs - simple' '
1080 | 	sed -e "s/Z$//" >expected <<-EOF &&
1081 | 	HEAD Z
1082 | 	main Z
1083 | 	matching-branch Z
1084 | 	other/branch-in-other Z
1085 | 	other/main-in-other Z
1086 | 	matching-tag Z
1087 | 	EOF
1088 | 	(
1089 | 		cur= &&
1090 | 		run_func __git_complete_refs
1091 | 	) &&
1092 | 	test_cmp expected out
1093 | '
1094 | 
1095 | test_expect_success '__git_complete_refs - matching' '
1096 | 	sed -e "s/Z$//" >expected <<-EOF &&
1097 | 	matching-branch Z
1098 | 	matching-tag Z
1099 | 	EOF
1100 | 	(
1101 | 		cur=mat &&
1102 | 		run_func __git_complete_refs
1103 | 	) &&
1104 | 	test_cmp expected out
1105 | '
1106 | 
1107 | test_expect_success '__git_complete_refs - remote' '
1108 | 	sed -e "s/Z$//" >expected <<-EOF &&
1109 | 	HEAD Z
1110 | 	branch-in-other Z
1111 | 	main-in-other Z
1112 | 	EOF
1113 | 	(
1114 | 		cur= &&
1115 | 		run_func __git_complete_refs --remote=other
1116 | 	) &&
1117 | 	test_cmp expected out
1118 | '
1119 | 
1120 | test_expect_success '__git_complete_refs - track' '
1121 | 	sed -e "s/Z$//" >expected <<-EOF &&
1122 | 	HEAD Z
1123 | 	main Z
1124 | 	matching-branch Z
1125 | 	other/branch-in-other Z
1126 | 	other/main-in-other Z
1127 | 	matching-tag Z
1128 | 	branch-in-other Z
1129 | 	main-in-other Z
1130 | 	EOF
1131 | 	(
1132 | 		cur= &&
1133 | 		run_func __git_complete_refs --track
1134 | 	) &&
1135 | 	test_cmp expected out
1136 | '
1137 | 
1138 | test_expect_success '__git_complete_refs - current word' '
1139 | 	sed -e "s/Z$//" >expected <<-EOF &&
1140 | 	matching-branch Z
1141 | 	matching-tag Z
1142 | 	EOF
1143 | 	(
1144 | 		cur="--option=mat" &&
1145 | 		run_func __git_complete_refs --cur="${cur#*=}"
1146 | 	) &&
1147 | 	test_cmp expected out
1148 | '
1149 | 
1150 | test_expect_success '__git_complete_refs - prefix' '
1151 | 	sed -e "s/Z$//" >expected <<-EOF &&
1152 | 	v1.0..matching-branch Z
1153 | 	v1.0..matching-tag Z
1154 | 	EOF
1155 | 	(
1156 | 		cur=v1.0..mat &&
1157 | 		run_func __git_complete_refs --pfx=v1.0.. --cur=mat
1158 | 	) &&
1159 | 	test_cmp expected out
1160 | '
1161 | 
1162 | test_expect_success '__git_complete_refs - suffix' '
1163 | 	cat >expected <<-EOF &&
1164 | 	HEAD.
1165 | 	main.
1166 | 	matching-branch.
1167 | 	other/branch-in-other.
1168 | 	other/main-in-other.
1169 | 	matching-tag.
1170 | 	EOF
1171 | 	(
1172 | 		cur= &&
1173 | 		run_func __git_complete_refs --sfx=.
1174 | 	) &&
1175 | 	test_cmp expected out
1176 | '
1177 | 
1178 | test_expect_success '__git_complete_fetch_refspecs - simple' '
1179 | 	sed -e "s/Z$//" >expected <<-EOF &&
1180 | 	HEAD:HEAD Z
1181 | 	branch-in-other:branch-in-other Z
1182 | 	main-in-other:main-in-other Z
1183 | 	EOF
1184 | 	(
1185 | 		cur= &&
1186 | 		run_func __git_complete_fetch_refspecs other
1187 | 	) &&
1188 | 	test_cmp expected out
1189 | '
1190 | 
1191 | test_expect_success '__git_complete_fetch_refspecs - matching' '
1192 | 	sed -e "s/Z$//" >expected <<-EOF &&
1193 | 	branch-in-other:branch-in-other Z
1194 | 	EOF
1195 | 	(
1196 | 		cur=br &&
1197 | 		run_func __git_complete_fetch_refspecs other "" br
1198 | 	) &&
1199 | 	test_cmp expected out
1200 | '
1201 | 
1202 | test_expect_success '__git_complete_fetch_refspecs - prefix' '
1203 | 	sed -e "s/Z$//" >expected <<-EOF &&
1204 | 	+HEAD:HEAD Z
1205 | 	+branch-in-other:branch-in-other Z
1206 | 	+main-in-other:main-in-other Z
1207 | 	EOF
1208 | 	(
1209 | 		cur="+" &&
1210 | 		run_func __git_complete_fetch_refspecs other "+" ""
1211 | 	) &&
1212 | 	test_cmp expected out
1213 | '
1214 | 
1215 | test_expect_success '__git_complete_fetch_refspecs - fully qualified' '
1216 | 	sed -e "s/Z$//" >expected <<-EOF &&
1217 | 	refs/heads/branch-in-other:refs/heads/branch-in-other Z
1218 | 	refs/heads/main-in-other:refs/heads/main-in-other Z
1219 | 	refs/tags/tag-in-other:refs/tags/tag-in-other Z
1220 | 	EOF
1221 | 	(
1222 | 		cur=refs/ &&
1223 | 		run_func __git_complete_fetch_refspecs other "" refs/
1224 | 	) &&
1225 | 	test_cmp expected out
1226 | '
1227 | 
1228 | test_expect_success '__git_complete_fetch_refspecs - fully qualified & prefix' '
1229 | 	sed -e "s/Z$//" >expected <<-EOF &&
1230 | 	+refs/heads/branch-in-other:refs/heads/branch-in-other Z
1231 | 	+refs/heads/main-in-other:refs/heads/main-in-other Z
1232 | 	+refs/tags/tag-in-other:refs/tags/tag-in-other Z
1233 | 	EOF
1234 | 	(
1235 | 		cur=+refs/ &&
1236 | 		run_func __git_complete_fetch_refspecs other + refs/
1237 | 	) &&
1238 | 	test_cmp expected out
1239 | '
1240 | 
1241 | test_expect_success 'git switch - with no options, complete local branches and unique remote branch names for DWIM logic' '
1242 | 	test_completion "git switch " <<-\EOF
1243 | 	branch-in-other Z
1244 | 	main Z
1245 | 	main-in-other Z
1246 | 	matching-branch Z
1247 | 	EOF
1248 | '
1249 | 
1250 | test_expect_success 'git checkout - completes refs and unique remote branches for DWIM' '
1251 | 	test_completion "git checkout " <<-\EOF
1252 | 	HEAD Z
1253 | 	branch-in-other Z
1254 | 	main Z
1255 | 	main-in-other Z
1256 | 	matching-branch Z
1257 | 	matching-tag Z
1258 | 	other/branch-in-other Z
1259 | 	other/main-in-other Z
1260 | 	EOF
1261 | '
1262 | 
1263 | test_expect_success 'git switch - with --no-guess, complete only local branches' '
1264 | 	test_completion "git switch --no-guess " <<-\EOF
1265 | 	main Z
1266 | 	matching-branch Z
1267 | 	EOF
1268 | '
1269 | 
1270 | test_expect_success 'git switch - with GIT_COMPLETION_CHECKOUT_NO_GUESS=1, complete only local branches' '
1271 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git switch " <<-\EOF
1272 | 	main Z
1273 | 	matching-branch Z
1274 | 	EOF
1275 | '
1276 | 
1277 | test_expect_success 'git switch - --guess overrides GIT_COMPLETION_CHECKOUT_NO_GUESS=1, complete local branches and unique remote names for DWIM logic' '
1278 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git switch --guess " <<-\EOF
1279 | 	branch-in-other Z
1280 | 	main Z
1281 | 	main-in-other Z
1282 | 	matching-branch Z
1283 | 	EOF
1284 | '
1285 | 
1286 | test_expect_success 'git switch - a later --guess overrides previous --no-guess, complete local and remote unique branches for DWIM' '
1287 | 	test_completion "git switch --no-guess --guess " <<-\EOF
1288 | 	branch-in-other Z
1289 | 	main Z
1290 | 	main-in-other Z
1291 | 	matching-branch Z
1292 | 	EOF
1293 | '
1294 | 
1295 | test_expect_success 'git switch - a later --no-guess overrides previous --guess, complete only local branches' '
1296 | 	test_completion "git switch --guess --no-guess " <<-\EOF
1297 | 	main Z
1298 | 	matching-branch Z
1299 | 	EOF
1300 | '
1301 | 
1302 | test_expect_success 'git checkout - with GIT_COMPLETION_NO_GUESS=1 only completes refs' '
1303 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git checkout " <<-\EOF
1304 | 	HEAD Z
1305 | 	main Z
1306 | 	matching-branch Z
1307 | 	matching-tag Z
1308 | 	other/branch-in-other Z
1309 | 	other/main-in-other Z
1310 | 	EOF
1311 | '
1312 | 
1313 | test_expect_success 'git checkout - --guess overrides GIT_COMPLETION_NO_GUESS=1, complete refs and unique remote branches for DWIM' '
1314 | 	GIT_COMPLETION_CHECKOUT_NO_GUESS=1 test_completion "git checkout --guess " <<-\EOF
1315 | 	HEAD Z
1316 | 	branch-in-other Z
1317 | 	main Z
1318 | 	main-in-other Z
1319 | 	matching-branch Z
1320 | 	matching-tag Z
1321 | 	other/branch-in-other Z
1322 | 	other/main-in-other Z
1323 | 	EOF
1324 | '
1325 | 
1326 | test_expect_success 'git checkout - with --no-guess, only completes refs' '
1327 | 	test_completion "git checkout --no-guess " <<-\EOF
1328 | 	HEAD Z
1329 | 	main Z
1330 | 	matching-branch Z
1331 | 	matching-tag Z
1332 | 	other/branch-in-other Z
1333 | 	other/main-in-other Z
1334 | 	EOF
1335 | '
1336 | 
1337 | test_expect_success 'git checkout - a later --guess overrides previous --no-guess, complete refs and unique remote branches for DWIM' '
1338 | 	test_completion "git checkout --no-guess --guess " <<-\EOF
1339 | 	HEAD Z
1340 | 	branch-in-other Z
1341 | 	main Z
1342 | 	main-in-other Z
1343 | 	matching-branch Z
1344 | 	matching-tag Z
1345 | 	other/branch-in-other Z
1346 | 	other/main-in-other Z
1347 | 	EOF
1348 | '
1349 | 
1350 | test_expect_success 'git checkout - a later --no-guess overrides previous --guess, complete only refs' '
1351 | 	test_completion "git checkout --guess --no-guess " <<-\EOF
1352 | 	HEAD Z
1353 | 	main Z
1354 | 	matching-branch Z
1355 | 	matching-tag Z
1356 | 	other/branch-in-other Z
1357 | 	other/main-in-other Z
1358 | 	EOF
1359 | '
1360 | 
1361 | test_expect_success 'git checkout - with checkout.guess = false, only completes refs' '
1362 | 	test_config checkout.guess false &&
1363 | 	test_completion "git checkout " <<-\EOF
1364 | 	HEAD Z
1365 | 	main Z
1366 | 	matching-branch Z
1367 | 	matching-tag Z
1368 | 	other/branch-in-other Z
1369 | 	other/main-in-other Z
1370 | 	EOF
1371 | '
1372 | 
1373 | test_expect_success 'git checkout - with checkout.guess = true, completes refs and unique remote branches for DWIM' '
1374 | 	test_config checkout.guess true &&
1375 | 	test_completion "git checkout " <<-\EOF
1376 | 	HEAD Z
1377 | 	branch-in-other Z
1378 | 	main Z
1379 | 	main-in-other Z
1380 | 	matching-branch Z
1381 | 	matching-tag Z
1382 | 	other/branch-in-other Z
1383 | 	other/main-in-other Z
1384 | 	EOF
1385 | '
1386 | 
1387 | test_expect_success 'git checkout - a later --guess overrides previous checkout.guess = false, complete refs and unique remote branches for DWIM' '
1388 | 	test_config checkout.guess false &&
1389 | 	test_completion "git checkout --guess " <<-\EOF
1390 | 	HEAD Z
1391 | 	branch-in-other Z
1392 | 	main Z
1393 | 	main-in-other Z
1394 | 	matching-branch Z
1395 | 	matching-tag Z
1396 | 	other/branch-in-other Z
1397 | 	other/main-in-other Z
1398 | 	EOF
1399 | '
1400 | 
1401 | test_expect_success 'git checkout - a later --no-guess overrides previous checkout.guess = true, complete only refs' '
1402 | 	test_config checkout.guess true &&
1403 | 	test_completion "git checkout --no-guess " <<-\EOF
1404 | 	HEAD Z
1405 | 	main Z
1406 | 	matching-branch Z
1407 | 	matching-tag Z
1408 | 	other/branch-in-other Z
1409 | 	other/main-in-other Z
1410 | 	EOF
1411 | '
1412 | 
1413 | test_expect_success 'git switch - with --detach, complete all references' '
1414 | 	test_completion "git switch --detach " <<-\EOF
1415 | 	HEAD Z
1416 | 	main Z
1417 | 	matching-branch Z
1418 | 	matching-tag Z
1419 | 	other/branch-in-other Z
1420 | 	other/main-in-other Z
1421 | 	EOF
1422 | '
1423 | 
1424 | test_expect_success 'git checkout - with --detach, complete only references' '
1425 | 	test_completion "git checkout --detach " <<-\EOF
1426 | 	HEAD Z
1427 | 	main Z
1428 | 	matching-branch Z
1429 | 	matching-tag Z
1430 | 	other/branch-in-other Z
1431 | 	other/main-in-other Z
1432 | 	EOF
1433 | '
1434 | 
1435 | test_expect_success 'setup sparse-checkout tests' '
1436 | 	# set up sparse-checkout repo
1437 | 	git init sparse-checkout &&
1438 | 	(
1439 | 		cd sparse-checkout &&
1440 | 		mkdir -p folder1/0/1 folder2/0 folder3 &&
1441 | 		touch folder1/0/1/t.txt &&
1442 | 		touch folder2/0/t.txt &&
1443 | 		touch folder3/t.txt &&
1444 | 		git add . &&
1445 | 		git commit -am "Initial commit"
1446 | 	)
1447 | '
1448 | 
1449 | test_expect_success 'sparse-checkout completes subcommands' '
1450 | 	test_completion "git sparse-checkout " <<-\EOF
1451 | 	list Z
1452 | 	init Z
1453 | 	set Z
1454 | 	add Z
1455 | 	reapply Z
1456 | 	disable Z
1457 | 	EOF
1458 | '
1459 | 
1460 | test_expect_success 'cone mode sparse-checkout completes directory names' '
1461 | 	# initialize sparse-checkout definitions
1462 | 	git -C sparse-checkout sparse-checkout set --cone folder1/0 folder3 &&
1463 | 
1464 | 	# test tab completion
1465 | 	(
1466 | 		cd sparse-checkout &&
1467 | 		test_completion "git sparse-checkout set f" <<-\EOF
1468 | 		folder1/
1469 | 		folder2/
1470 | 		folder3/
1471 | 		EOF
1472 | 	) &&
1473 | 
1474 | 	(
1475 | 		cd sparse-checkout &&
1476 | 		test_completion "git sparse-checkout set folder1/" <<-\EOF
1477 | 		folder1/0/
1478 | 		EOF
1479 | 	) &&
1480 | 
1481 | 	(
1482 | 		cd sparse-checkout &&
1483 | 		test_completion "git sparse-checkout set folder1/0/" <<-\EOF
1484 | 		folder1/0/1/
1485 | 		EOF
1486 | 	) &&
1487 | 
1488 | 	(
1489 | 		cd sparse-checkout/folder1 &&
1490 | 		test_completion "git sparse-checkout add 0" <<-\EOF
1491 | 		0/
1492 | 		EOF
1493 | 	)
1494 | '
1495 | 
1496 | test_expect_success 'cone mode sparse-checkout completes directory names with spaces and accents' '
1497 | 	# reset sparse-checkout
1498 | 	git -C sparse-checkout sparse-checkout disable &&
1499 | 	(
1500 | 		cd sparse-checkout &&
1501 | 		mkdir "directory with spaces" &&
1502 | 		mkdir "directory-with-áccent" &&
1503 | 		>"directory with spaces/randomfile" &&
1504 | 		>"directory-with-áccent/randomfile" &&
1505 | 		git add . &&
1506 | 		git commit -m "Add directory with spaces and directory with accent" &&
1507 | 		git sparse-checkout set --cone "directory with spaces" \
1508 | 			"directory-with-áccent" &&
1509 | 		test_completion "git sparse-checkout add dir" <<-\EOF &&
1510 | 		directory with spaces/
1511 | 		directory-with-áccent/
1512 | 		EOF
1513 | 		rm -rf "directory with spaces" &&
1514 | 		rm -rf "directory-with-áccent" &&
1515 | 		git add . &&
1516 | 		git commit -m "Remove directory with spaces and directory with accent"
1517 | 	)
1518 | '
1519 | 
1520 | # use FUNNYNAMES to avoid running on Windows, which doesn't permit tabs in paths
1521 | test_expect_success FUNNYNAMES 'cone mode sparse-checkout completes directory names with tabs' '
1522 | 	# reset sparse-checkout
1523 | 	git -C sparse-checkout sparse-checkout disable &&
1524 | 	(
1525 | 		cd sparse-checkout &&
1526 | 		mkdir "$(printf "directory\twith\ttabs")" &&
1527 | 		>"$(printf "directory\twith\ttabs")/randomfile" &&
1528 | 		git add . &&
1529 | 		git commit -m "Add directory with tabs" &&
1530 | 		git sparse-checkout set --cone \
1531 | 			"$(printf "directory\twith\ttabs")" &&
1532 | 		test_completion "git sparse-checkout add dir" <<-\EOF &&
1533 | 		directory	with	tabs/
1534 | 		EOF
1535 | 		rm -rf "$(printf "directory\twith\ttabs")" &&
1536 | 		git add . &&
1537 | 		git commit -m "Remove directory with tabs"
1538 | 	)
1539 | '
1540 | 
1541 | # use FUNNYNAMES to avoid running on Windows, and !CYGWIN for Cygwin, as neither permit backslashes in paths
1542 | test_expect_success FUNNYNAMES,!CYGWIN 'cone mode sparse-checkout completes directory names with backslashes' '
1543 | 	# reset sparse-checkout
1544 | 	git -C sparse-checkout sparse-checkout disable &&
1545 | 	(
1546 | 		cd sparse-checkout &&
1547 | 		mkdir "directory\with\backslashes" &&
1548 | 		>"directory\with\backslashes/randomfile" &&
1549 | 		git add . &&
1550 | 		git commit -m "Add directory with backslashes" &&
1551 | 		git sparse-checkout set --cone \
1552 | 			"directory\with\backslashes" &&
1553 | 		test_completion "git sparse-checkout add dir" <<-\EOF &&
1554 | 		directory\with\backslashes/
1555 | 		EOF
1556 | 		rm -rf "directory\with\backslashes" &&
1557 | 		git add . &&
1558 | 		git commit -m "Remove directory with backslashes"
1559 | 	)
1560 | '
1561 | 
1562 | test_expect_success 'non-cone mode sparse-checkout uses bash completion' '
1563 | 	# reset sparse-checkout repo to non-cone mode
1564 | 	git -C sparse-checkout sparse-checkout disable &&
1565 | 	git -C sparse-checkout sparse-checkout set --no-cone &&
1566 | 
1567 | 	(
1568 | 		cd sparse-checkout &&
1569 | 		# expected to be empty since we have not configured
1570 | 		# custom completion for non-cone mode
1571 | 		test_completion "git sparse-checkout set f" <<-\EOF
1572 | 
1573 | 		EOF
1574 | 	)
1575 | '
1576 | 
1577 | test_expect_success 'git sparse-checkout set --cone completes directory names' '
1578 | 	git -C sparse-checkout sparse-checkout disable &&
1579 | 
1580 | 	(
1581 | 		cd sparse-checkout &&
1582 | 		test_completion "git sparse-checkout set --cone f" <<-\EOF
1583 | 		folder1/
1584 | 		folder2/
1585 | 		folder3/
1586 | 		EOF
1587 | 	)
1588 | '
1589 | 
1590 | test_expect_success 'git switch - with -d, complete all references' '
1591 | 	test_completion "git switch -d " <<-\EOF
1592 | 	HEAD Z
1593 | 	main Z
1594 | 	matching-branch Z
1595 | 	matching-tag Z
1596 | 	other/branch-in-other Z
1597 | 	other/main-in-other Z
1598 | 	EOF
1599 | '
1600 | 
1601 | test_expect_success 'git checkout - with -d, complete only references' '
1602 | 	test_completion "git checkout -d " <<-\EOF
1603 | 	HEAD Z
1604 | 	main Z
1605 | 	matching-branch Z
1606 | 	matching-tag Z
1607 | 	other/branch-in-other Z
1608 | 	other/main-in-other Z
1609 | 	EOF
1610 | '
1611 | 
1612 | test_expect_success 'git switch - with --track, complete only remote branches' '
1613 | 	test_completion "git switch --track " <<-\EOF
1614 | 	other/branch-in-other Z
1615 | 	other/main-in-other Z
1616 | 	EOF
1617 | '
1618 | 
1619 | test_expect_success 'git checkout - with --track, complete only remote branches' '
1620 | 	test_completion "git checkout --track " <<-\EOF
1621 | 	other/branch-in-other Z
1622 | 	other/main-in-other Z
1623 | 	EOF
1624 | '
1625 | 
1626 | test_expect_success 'git switch - with --no-track, complete only local branch names' '
1627 | 	test_completion "git switch --no-track " <<-\EOF
1628 | 	main Z
1629 | 	matching-branch Z
1630 | 	EOF
1631 | '
1632 | 
1633 | test_expect_success 'git checkout - with --no-track, complete only local references' '
1634 | 	test_completion "git checkout --no-track " <<-\EOF
1635 | 	HEAD Z
1636 | 	main Z
1637 | 	matching-branch Z
1638 | 	matching-tag Z
1639 | 	other/branch-in-other Z
1640 | 	other/main-in-other Z
1641 | 	EOF
1642 | '
1643 | 
1644 | test_expect_success 'git switch - with -c, complete all references' '
1645 | 	test_completion "git switch -c new-branch " <<-\EOF
1646 | 	HEAD Z
1647 | 	main Z
1648 | 	matching-branch Z
1649 | 	matching-tag Z
1650 | 	other/branch-in-other Z
1651 | 	other/main-in-other Z
1652 | 	EOF
1653 | '
1654 | 
1655 | test_expect_success 'git switch - with -C, complete all references' '
1656 | 	test_completion "git switch -C new-branch " <<-\EOF
1657 | 	HEAD Z
1658 | 	main Z
1659 | 	matching-branch Z
1660 | 	matching-tag Z
1661 | 	other/branch-in-other Z
1662 | 	other/main-in-other Z
1663 | 	EOF
1664 | '
1665 | 
1666 | test_expect_success 'git switch - with -c and --track, complete all references' '
1667 | 	test_completion "git switch -c new-branch --track " <<-EOF
1668 | 	HEAD Z
1669 | 	main Z
1670 | 	matching-branch Z
1671 | 	matching-tag Z
1672 | 	other/branch-in-other Z
1673 | 	other/main-in-other Z
1674 | 	EOF
1675 | '
1676 | 
1677 | test_expect_success 'git switch - with -C and --track, complete all references' '
1678 | 	test_completion "git switch -C new-branch --track " <<-EOF
1679 | 	HEAD Z
1680 | 	main Z
1681 | 	matching-branch Z
1682 | 	matching-tag Z
1683 | 	other/branch-in-other Z
1684 | 	other/main-in-other Z
1685 | 	EOF
1686 | '
1687 | 
1688 | test_expect_success 'git switch - with -c and --no-track, complete all references' '
1689 | 	test_completion "git switch -c new-branch --no-track " <<-\EOF
1690 | 	HEAD Z
1691 | 	main Z
1692 | 	matching-branch Z
1693 | 	matching-tag Z
1694 | 	other/branch-in-other Z
1695 | 	other/main-in-other Z
1696 | 	EOF
1697 | '
1698 | 
1699 | test_expect_success 'git switch - with -C and --no-track, complete all references' '
1700 | 	test_completion "git switch -C new-branch --no-track " <<-\EOF
1701 | 	HEAD Z
1702 | 	main Z
1703 | 	matching-branch Z
1704 | 	matching-tag Z
1705 | 	other/branch-in-other Z
1706 | 	other/main-in-other Z
1707 | 	EOF
1708 | '
1709 | 
1710 | test_expect_success 'git checkout - with -b, complete all references' '
1711 | 	test_completion "git checkout -b new-branch " <<-\EOF
1712 | 	HEAD Z
1713 | 	main Z
1714 | 	matching-branch Z
1715 | 	matching-tag Z
1716 | 	other/branch-in-other Z
1717 | 	other/main-in-other Z
1718 | 	EOF
1719 | '
1720 | 
1721 | test_expect_success 'git checkout - with -B, complete all references' '
1722 | 	test_completion "git checkout -B new-branch " <<-\EOF
1723 | 	HEAD Z
1724 | 	main Z
1725 | 	matching-branch Z
1726 | 	matching-tag Z
1727 | 	other/branch-in-other Z
1728 | 	other/main-in-other Z
1729 | 	EOF
1730 | '
1731 | 
1732 | test_expect_success 'git checkout - with -b and --track, complete all references' '
1733 | 	test_completion "git checkout -b new-branch --track " <<-EOF
1734 | 	HEAD Z
1735 | 	main Z
1736 | 	matching-branch Z
1737 | 	matching-tag Z
1738 | 	other/branch-in-other Z
1739 | 	other/main-in-other Z
1740 | 	EOF
1741 | '
1742 | 
1743 | test_expect_success 'git checkout - with -B and --track, complete all references' '
1744 | 	test_completion "git checkout -B new-branch --track " <<-EOF
1745 | 	HEAD Z
1746 | 	main Z
1747 | 	matching-branch Z
1748 | 	matching-tag Z
1749 | 	other/branch-in-other Z
1750 | 	other/main-in-other Z
1751 | 	EOF
1752 | '
1753 | 
1754 | test_expect_success 'git checkout - with -b and --no-track, complete all references' '
1755 | 	test_completion "git checkout -b new-branch --no-track " <<-\EOF
1756 | 	HEAD Z
1757 | 	main Z
1758 | 	matching-branch Z
1759 | 	matching-tag Z
1760 | 	other/branch-in-other Z
1761 | 	other/main-in-other Z
1762 | 	EOF
1763 | '
1764 | 
1765 | test_expect_success 'git checkout - with -B and --no-track, complete all references' '
1766 | 	test_completion "git checkout -B new-branch --no-track " <<-\EOF
1767 | 	HEAD Z
1768 | 	main Z
1769 | 	matching-branch Z
1770 | 	matching-tag Z
1771 | 	other/branch-in-other Z
1772 | 	other/main-in-other Z
1773 | 	EOF
1774 | '
1775 | 
1776 | test_expect_success 'git switch - for -c, complete local branches and unique remote branches' '
1777 | 	test_completion "git switch -c " <<-\EOF
1778 | 	branch-in-other Z
1779 | 	main Z
1780 | 	main-in-other Z
1781 | 	matching-branch Z
1782 | 	EOF
1783 | '
1784 | 
1785 | test_expect_success 'git switch - for -C, complete local branches and unique remote branches' '
1786 | 	test_completion "git switch -C " <<-\EOF
1787 | 	branch-in-other Z
1788 | 	main Z
1789 | 	main-in-other Z
1790 | 	matching-branch Z
1791 | 	EOF
1792 | '
1793 | 
1794 | test_expect_success 'git switch - for -c with --no-guess, complete local branches only' '
1795 | 	test_completion "git switch --no-guess -c " <<-\EOF
1796 | 	main Z
1797 | 	matching-branch Z
1798 | 	EOF
1799 | '
1800 | 
1801 | test_expect_success 'git switch - for -C with --no-guess, complete local branches only' '
1802 | 	test_completion "git switch --no-guess -C " <<-\EOF
1803 | 	main Z
1804 | 	matching-branch Z
1805 | 	EOF
1806 | '
1807 | 
1808 | test_expect_success 'git switch - for -c with --no-track, complete local branches only' '
1809 | 	test_completion "git switch --no-track -c " <<-\EOF
1810 | 	main Z
1811 | 	matching-branch Z
1812 | 	EOF
1813 | '
1814 | 
1815 | test_expect_success 'git switch - for -C with --no-track, complete local branches only' '
1816 | 	test_completion "git switch --no-track -C " <<-\EOF
1817 | 	main Z
1818 | 	matching-branch Z
1819 | 	EOF
1820 | '
1821 | 
1822 | test_expect_success 'git checkout - for -b, complete local branches and unique remote branches' '
1823 | 	test_completion "git checkout -b " <<-\EOF
1824 | 	branch-in-other Z
1825 | 	main Z
1826 | 	main-in-other Z
1827 | 	matching-branch Z
1828 | 	EOF
1829 | '
1830 | 
1831 | test_expect_success 'git checkout - for -B, complete local branches and unique remote branches' '
1832 | 	test_completion "git checkout -B " <<-\EOF
1833 | 	branch-in-other Z
1834 | 	main Z
1835 | 	main-in-other Z
1836 | 	matching-branch Z
1837 | 	EOF
1838 | '
1839 | 
1840 | test_expect_success 'git checkout - for -b with --no-guess, complete local branches only' '
1841 | 	test_completion "git checkout --no-guess -b " <<-\EOF
1842 | 	main Z
1843 | 	matching-branch Z
1844 | 	EOF
1845 | '
1846 | 
1847 | test_expect_success 'git checkout - for -B with --no-guess, complete local branches only' '
1848 | 	test_completion "git checkout --no-guess -B " <<-\EOF
1849 | 	main Z
1850 | 	matching-branch Z
1851 | 	EOF
1852 | '
1853 | 
1854 | test_expect_success 'git checkout - for -b with --no-track, complete local branches only' '
1855 | 	test_completion "git checkout --no-track -b " <<-\EOF
1856 | 	main Z
1857 | 	matching-branch Z
1858 | 	EOF
1859 | '
1860 | 
1861 | test_expect_success 'git checkout - for -B with --no-track, complete local branches only' '
1862 | 	test_completion "git checkout --no-track -B " <<-\EOF
1863 | 	main Z
1864 | 	matching-branch Z
1865 | 	EOF
1866 | '
1867 | 
1868 | test_expect_success 'git switch - with --orphan completes local branch names and unique remote branch names' '
1869 | 	test_completion "git switch --orphan " <<-\EOF
1870 | 	branch-in-other Z
1871 | 	main Z
1872 | 	main-in-other Z
1873 | 	matching-branch Z
1874 | 	EOF
1875 | '
1876 | 
1877 | test_expect_success 'git switch - --orphan with branch already provided completes nothing else' '
1878 | 	test_completion "git switch --orphan main " <<-\EOF
1879 | 
1880 | 	EOF
1881 | '
1882 | 
1883 | test_expect_success 'git checkout - with --orphan completes local branch names and unique remote branch names' '
1884 | 	test_completion "git checkout --orphan " <<-\EOF
1885 | 	branch-in-other Z
1886 | 	main Z
1887 | 	main-in-other Z
1888 | 	matching-branch Z
1889 | 	EOF
1890 | '
1891 | 
1892 | test_expect_success 'git checkout - --orphan with branch already provided completes local refs for a start-point' '
1893 | 	test_completion "git checkout --orphan main " <<-\EOF
1894 | 	HEAD Z
1895 | 	main Z
1896 | 	matching-branch Z
1897 | 	matching-tag Z
1898 | 	other/branch-in-other Z
1899 | 	other/main-in-other Z
1900 | 	EOF
1901 | '
1902 | 
1903 | test_expect_success 'teardown after ref completion' '
1904 | 	git branch -d matching-branch &&
1905 | 	git tag -d matching-tag &&
1906 | 	git remote remove other
1907 | '
1908 | 
1909 | 
1910 | test_path_completion ()
1911 | {
1912 | 	test $# = 2 || BUG "not 2 parameters to test_path_completion"
1913 | 
1914 | 	local cur="$1" expected="$2"
1915 | 	echo "$expected" >expected &&
1916 | 	(
1917 | 		# In the following tests calling this function we only
1918 | 		# care about how __git_complete_index_file() deals with
1919 | 		# unusual characters in path names.  By requesting only
1920 | 		# untracked files we do not have to bother adding any
1921 | 		# paths to the index in those tests.
1922 | 		run_func __git_complete_index_file --others
1923 | 	) &&
1924 | 	test_cmp expected out
1925 | }
1926 | 
1927 | test_expect_success 'setup for path completion tests' '
1928 | 	mkdir simple-dir \
1929 | 	      "spaces in dir" \
1930 | 	      árvíztűrő &&
1931 | 	touch simple-dir/simple-file \
1932 | 	      "spaces in dir/spaces in file" \
1933 | 	      "árvíztűrő/Сайн яваарай" &&
1934 | 	if test_have_prereq !MINGW &&
1935 | 	   mkdir BS\\dir \
1936 | 		 '$'separators\034in\035dir'' &&
1937 | 	   touch BS\\dir/DQ\"file \
1938 | 		 '$'separators\034in\035dir/sep\036in\037file''
1939 | 	then
1940 | 		test_set_prereq FUNNIERNAMES
1941 | 	else
1942 | 		rm -rf BS\\dir '$'separators\034in\035dir''
1943 | 	fi
1944 | '
1945 | 
1946 | test_expect_success '__git_complete_index_file - simple' '
1947 | 	test_path_completion simple simple-dir &&  # Bash is supposed to
1948 | 						   # add the trailing /.
1949 | 	test_path_completion simple-dir/simple simple-dir/simple-file
1950 | '
1951 | 
1952 | test_expect_success \
1953 |     '__git_complete_index_file - escaped characters on cmdline' '
1954 | 	test_path_completion spac "spaces in dir" &&  # Bash will turn this
1955 | 						      # into "spaces\ in\ dir"
1956 | 	test_path_completion "spaces\\ i" \
1957 | 			     "spaces in dir" &&
1958 | 	test_path_completion "spaces\\ in\\ dir/s" \
1959 | 			     "spaces in dir/spaces in file" &&
1960 | 	test_path_completion "spaces\\ in\\ dir/spaces\\ i" \
1961 | 			     "spaces in dir/spaces in file"
1962 | '
1963 | 
1964 | test_expect_success \
1965 |     '__git_complete_index_file - quoted characters on cmdline' '
1966 | 	# Testing with an opening but without a corresponding closing
1967 | 	# double quote is important.
1968 | 	test_path_completion \"spac "spaces in dir" &&
1969 | 	test_path_completion "\"spaces i" \
1970 | 			     "spaces in dir" &&
1971 | 	test_path_completion "\"spaces in dir/s" \
1972 | 			     "spaces in dir/spaces in file" &&
1973 | 	test_path_completion "\"spaces in dir/spaces i" \
1974 | 			     "spaces in dir/spaces in file"
1975 | '
1976 | 
1977 | test_expect_success '__git_complete_index_file - UTF-8 in ls-files output' '
1978 | 	test_path_completion á árvíztűrő &&
1979 | 	test_path_completion árvíztűrő/С "árvíztűrő/Сайн яваарай"
1980 | '
1981 | 
1982 | test_expect_success FUNNIERNAMES \
1983 |     '__git_complete_index_file - C-style escapes in ls-files output' '
1984 | 	test_path_completion BS \
1985 | 			     BS\\dir &&
1986 | 	test_path_completion BS\\\\d \
1987 | 			     BS\\dir &&
1988 | 	test_path_completion BS\\\\dir/DQ \
1989 | 			     BS\\dir/DQ\"file &&
1990 | 	test_path_completion BS\\\\dir/DQ\\\"f \
1991 | 			     BS\\dir/DQ\"file
1992 | '
1993 | 
1994 | test_expect_success FUNNIERNAMES \
1995 |     '__git_complete_index_file - \nnn-escaped characters in ls-files output' '
1996 | 	test_path_completion sep '$'separators\034in\035dir'' &&
1997 | 	test_path_completion '$'separators\034i'' \
1998 | 			     '$'separators\034in\035dir'' &&
1999 | 	test_path_completion '$'separators\034in\035dir/sep'' \
2000 | 			     '$'separators\034in\035dir/sep\036in\037file'' &&
2001 | 	test_path_completion '$'separators\034in\035dir/sep\036i'' \
2002 | 			     '$'separators\034in\035dir/sep\036in\037file''
2003 | '
2004 | 
2005 | test_expect_success FUNNYNAMES \
2006 |     '__git_complete_index_file - removing repeated quoted path components' '
2007 | 	test_when_finished rm -r repeated-quoted &&
2008 | 	mkdir repeated-quoted &&      # A directory whose name in itself
2009 | 				      # would not be quoted ...
2010 | 	>repeated-quoted/0-file &&
2011 | 	>repeated-quoted/1\"file &&   # ... but here the file makes the
2012 | 				      # dirname quoted ...
2013 | 	>repeated-quoted/2-file &&
2014 | 	>repeated-quoted/3\"file &&   # ... and here, too.
2015 | 
2016 | 	# Still, we shold only list the directory name only once.
2017 | 	test_path_completion repeated repeated-quoted
2018 | '
2019 | 
2020 | test_expect_success 'teardown after path completion tests' '
2021 | 	rm -rf simple-dir "spaces in dir" árvíztűrő \
2022 | 	       BS\\dir '$'separators\034in\035dir''
2023 | '
2024 | 
2025 | test_expect_success '__git_find_on_cmdline - single match' '
2026 | 	echo list >expect &&
2027 | 	(
2028 | 		words=(git command --opt list) &&
2029 | 		cword=${#words[@]} &&
2030 | 		__git_cmd_idx=1 &&
2031 | 		__git_find_on_cmdline "add list remove" >actual
2032 | 	) &&
2033 | 	test_cmp expect actual
2034 | '
2035 | 
2036 | test_expect_success '__git_find_on_cmdline - multiple matches' '
2037 | 	echo remove >expect &&
2038 | 	(
2039 | 		words=(git command -o --opt remove list add) &&
2040 | 		cword=${#words[@]} &&
2041 | 		__git_cmd_idx=1 &&
2042 | 		__git_find_on_cmdline "add list remove" >actual
2043 | 	) &&
2044 | 	test_cmp expect actual
2045 | '
2046 | 
2047 | test_expect_success '__git_find_on_cmdline - no match' '
2048 | 	(
2049 | 		words=(git command --opt branch) &&
2050 | 		cword=${#words[@]} &&
2051 | 		__git_cmd_idx=1 &&
2052 | 		__git_find_on_cmdline "add list remove" >actual
2053 | 	) &&
2054 | 	test_must_be_empty actual
2055 | '
2056 | 
2057 | test_expect_success '__git_find_on_cmdline - single match with index' '
2058 | 	echo "3 list" >expect &&
2059 | 	(
2060 | 		words=(git command --opt list) &&
2061 | 		cword=${#words[@]} &&
2062 | 		__git_cmd_idx=1 &&
2063 | 		__git_find_on_cmdline --show-idx "add list remove" >actual
2064 | 	) &&
2065 | 	test_cmp expect actual
2066 | '
2067 | 
2068 | test_expect_success '__git_find_on_cmdline - multiple matches with index' '
2069 | 	echo "4 remove" >expect &&
2070 | 	(
2071 | 		words=(git command -o --opt remove list add) &&
2072 | 		cword=${#words[@]} &&
2073 | 		__git_cmd_idx=1 &&
2074 | 		__git_find_on_cmdline --show-idx "add list remove" >actual
2075 | 	) &&
2076 | 	test_cmp expect actual
2077 | '
2078 | 
2079 | test_expect_success '__git_find_on_cmdline - no match with index' '
2080 | 	(
2081 | 		words=(git command --opt branch) &&
2082 | 		cword=${#words[@]} &&
2083 | 		__git_cmd_idx=1 &&
2084 | 		__git_find_on_cmdline --show-idx "add list remove" >actual
2085 | 	) &&
2086 | 	test_must_be_empty actual
2087 | '
2088 | 
2089 | test_expect_success '__git_find_on_cmdline - ignores matches before command with index' '
2090 | 	echo "6 remove" >expect &&
2091 | 	(
2092 | 		words=(git -C remove command -o --opt remove list add) &&
2093 | 		cword=${#words[@]} &&
2094 | 		__git_cmd_idx=3 &&
2095 | 		__git_find_on_cmdline --show-idx "add list remove" >actual
2096 | 	) &&
2097 | 	test_cmp expect actual
2098 | '
2099 | 
2100 | test_expect_success '__git_get_config_variables' '
2101 | 	cat >expect <<-EOF &&
2102 | 	name-1
2103 | 	name-2
2104 | 	EOF
2105 | 	test_config interesting.name-1 good &&
2106 | 	test_config interesting.name-2 good &&
2107 | 	test_config subsection.interesting.name-3 bad &&
2108 | 	__git_get_config_variables interesting >actual &&
2109 | 	test_cmp expect actual
2110 | '
2111 | 
2112 | test_expect_success '__git_pretty_aliases' '
2113 | 	cat >expect <<-EOF &&
2114 | 	author
2115 | 	hash
2116 | 	EOF
2117 | 	test_config pretty.author "%an %ae" &&
2118 | 	test_config pretty.hash %H &&
2119 | 	__git_pretty_aliases >actual &&
2120 | 	test_cmp expect actual
2121 | '
2122 | 
2123 | test_expect_success 'basic' '
2124 | 	run_completion "git " &&
2125 | 	# built-in
2126 | 	grep -q "^add \$" out &&
2127 | 	# script
2128 | 	grep -q "^rebase \$" out &&
2129 | 	# plumbing
2130 | 	! grep -q "^ls-files \$" out &&
2131 | 
2132 | 	run_completion "git r" &&
2133 | 	! grep -q -v "^r" out
2134 | '
2135 | 
2136 | test_expect_success 'double dash "git" itself' '
2137 | 	test_completion "git --" <<-\EOF
2138 | 	--paginate Z
2139 | 	--no-pager Z
2140 | 	--git-dir=
2141 | 	--bare Z
2142 | 	--version Z
2143 | 	--exec-path Z
2144 | 	--exec-path=
2145 | 	--html-path Z
2146 | 	--man-path Z
2147 | 	--info-path Z
2148 | 	--work-tree=
2149 | 	--namespace=
2150 | 	--no-replace-objects Z
2151 | 	--help Z
2152 | 	EOF
2153 | '
2154 | 
2155 | test_expect_success 'double dash "git checkout"' '
2156 | 	test_completion "git checkout --" <<-\EOF
2157 | 	--quiet Z
2158 | 	--detach Z
2159 | 	--track Z
2160 | 	--orphan=Z
2161 | 	--ours Z
2162 | 	--theirs Z
2163 | 	--merge Z
2164 | 	--conflict=Z
2165 | 	--patch Z
2166 | 	--ignore-skip-worktree-bits Z
2167 | 	--ignore-other-worktrees Z
2168 | 	--recurse-submodules Z
2169 | 	--progress Z
2170 | 	--guess Z
2171 | 	--no-guess Z
2172 | 	--no-... Z
2173 | 	--overlay Z
2174 | 	--pathspec-file-nul Z
2175 | 	--pathspec-from-file=Z
2176 | 	EOF
2177 | '
2178 | 
2179 | test_expect_success 'general options' '
2180 | 	test_completion "git --ver" "--version " &&
2181 | 	test_completion "git --hel" "--help " &&
2182 | 	test_completion "git --exe" <<-\EOF &&
2183 | 	--exec-path Z
2184 | 	--exec-path=
2185 | 	EOF
2186 | 	test_completion "git --htm" "--html-path " &&
2187 | 	test_completion "git --pag" "--paginate " &&
2188 | 	test_completion "git --no-p" "--no-pager " &&
2189 | 	test_completion "git --git" "--git-dir=" &&
2190 | 	test_completion "git --wor" "--work-tree=" &&
2191 | 	test_completion "git --nam" "--namespace=" &&
2192 | 	test_completion "git --bar" "--bare " &&
2193 | 	test_completion "git --inf" "--info-path " &&
2194 | 	test_completion "git --no-r" "--no-replace-objects "
2195 | '
2196 | 
2197 | test_expect_success 'general options plus command' '
2198 | 	test_completion "git --version check" "checkout " &&
2199 | 	test_completion "git --paginate check" "checkout " &&
2200 | 	test_completion "git --git-dir=foo check" "checkout " &&
2201 | 	test_completion "git --bare check" "checkout " &&
2202 | 	test_completion "git --exec-path=foo check" "checkout " &&
2203 | 	test_completion "git --html-path check" "checkout " &&
2204 | 	test_completion "git --no-pager check" "checkout " &&
2205 | 	test_completion "git --work-tree=foo check" "checkout " &&
2206 | 	test_completion "git --namespace=foo check" "checkout " &&
2207 | 	test_completion "git --paginate check" "checkout " &&
2208 | 	test_completion "git --info-path check" "checkout " &&
2209 | 	test_completion "git --no-replace-objects check" "checkout " &&
2210 | 	test_completion "git --git-dir some/path check" "checkout " &&
2211 | 	test_completion "git -c conf.var=value check" "checkout " &&
2212 | 	test_completion "git -C some/path check" "checkout " &&
2213 | 	test_completion "git --work-tree some/path check" "checkout " &&
2214 | 	test_completion "git --namespace name/space check" "checkout "
2215 | '
2216 | 
2217 | test_expect_success 'git --help completion' '
2218 | 	test_completion "git --help ad" "add " &&
2219 | 	test_completion "git --help core" "core-tutorial "
2220 | '
2221 | 
2222 | test_expect_success 'completion.commands removes multiple commands' '
2223 | 	test_config_global completion.commands "-cherry -mergetool" &&
2224 | 	git --list-cmds=list-mainporcelain,list-complete,config >out &&
2225 | 	! grep -E "^(cherry|mergetool)$" out
2226 | '
2227 | 
2228 | test_expect_success 'setup for integration tests' '
2229 | 	echo content >file1 &&
2230 | 	echo more >file2 &&
2231 | 	git add file1 file2 &&
2232 | 	git commit -m one &&
2233 | 	git branch mybranch &&
2234 | 	git tag mytag
2235 | '
2236 | 
2237 | test_expect_success 'checkout completes ref names' '
2238 | 	test_completion "git checkout m" <<-\EOF
2239 | 	main Z
2240 | 	mybranch Z
2241 | 	mytag Z
2242 | 	EOF
2243 | '
2244 | 
2245 | test_expect_success 'checkout does not match ref names of a different case' '
2246 | 	test_completion "git checkout M" ""
2247 | '
2248 | 
2249 | test_expect_success 'checkout matches case insensitively with GIT_COMPLETION_IGNORE_CASE' '
2250 | 	(
2251 | 		GIT_COMPLETION_IGNORE_CASE=1 &&
2252 | 		test_completion "git checkout M" <<-\EOF
2253 | 		main Z
2254 | 		mybranch Z
2255 | 		mytag Z
2256 | 		EOF
2257 | 	)
2258 | '
2259 | 
2260 | test_expect_success 'checkout completes pseudo refs' '
2261 | 	test_completion "git checkout H" <<-\EOF
2262 | 	HEAD Z
2263 | 	EOF
2264 | '
2265 | 
2266 | test_expect_success 'checkout completes pseudo refs case insensitively with GIT_COMPLETION_IGNORE_CASE' '
2267 | 	(
2268 | 		GIT_COMPLETION_IGNORE_CASE=1 &&
2269 | 		test_completion "git checkout h" <<-\EOF
2270 | 		HEAD Z
2271 | 		EOF
2272 | 	)
2273 | '
2274 | 
2275 | test_expect_success 'git -C  checkout uses the right repo' '
2276 | 	test_completion "git -C subdir -C subsubdir -C .. -C ../otherrepo checkout b" <<-\EOF
2277 | 	branch-in-other Z
2278 | 	EOF
2279 | '
2280 | 
2281 | test_expect_success 'show completes all refs' '
2282 | 	test_completion "git show m" <<-\EOF
2283 | 	main Z
2284 | 	mybranch Z
2285 | 	mytag Z
2286 | 	EOF
2287 | '
2288 | 
2289 | test_expect_success ': completes paths' '
2290 | 	test_completion "git show mytag:f" <<-\EOF
2291 | 	file1Z
2292 | 	file2Z
2293 | 	EOF
2294 | '
2295 | 
2296 | test_expect_success 'complete tree filename with spaces' '
2297 | 	echo content >"name with spaces" &&
2298 | 	git add "name with spaces" &&
2299 | 	git commit -m spaces &&
2300 | 	test_completion "git show HEAD:nam" <<-\EOF
2301 | 	name with spacesZ
2302 | 	EOF
2303 | '
2304 | 
2305 | test_expect_success 'complete tree filename with metacharacters' '
2306 | 	echo content >"name with \${meta}" &&
2307 | 	git add "name with \${meta}" &&
2308 | 	git commit -m meta &&
2309 | 	test_completion "git show HEAD:nam" <<-\EOF
2310 | 	name with ${meta}Z
2311 | 	name with spacesZ
2312 | 	EOF
2313 | '
2314 | 
2315 | test_expect_success PERL 'send-email' '
2316 | 	test_completion "git send-email --cov" <<-\EOF &&
2317 | 	--cover-from-description=Z
2318 | 	--cover-letter Z
2319 | 	EOF
2320 | 	test_completion "git send-email --val" <<-\EOF &&
2321 | 	--validate Z
2322 | 	EOF
2323 | 	test_completion "git send-email ma" "main "
2324 | '
2325 | 
2326 | test_expect_success 'complete files' '
2327 | 	git init tmp && cd tmp &&
2328 | 	test_when_finished "cd .. && rm -rf tmp" &&
2329 | 
2330 | 	echo "expected" > .gitignore &&
2331 | 	echo "out" >> .gitignore &&
2332 | 	echo "out_sorted" >> .gitignore &&
2333 | 
2334 | 	git add .gitignore &&
2335 | 	test_completion "git commit " ".gitignore" &&
2336 | 
2337 | 	git commit -m ignore &&
2338 | 
2339 | 	touch new &&
2340 | 	test_completion "git add " "new" &&
2341 | 
2342 | 	git add new &&
2343 | 	git commit -a -m new &&
2344 | 	test_completion "git add " "" &&
2345 | 
2346 | 	git mv new modified &&
2347 | 	echo modify > modified &&
2348 | 	test_completion "git add " "modified" &&
2349 | 
2350 | 	mkdir -p some/deep &&
2351 | 	touch some/deep/path &&
2352 | 	test_completion "git add some/" "some/deep" &&
2353 | 	git clean -f some &&
2354 | 
2355 | 	touch untracked &&
2356 | 
2357 | 	: TODO .gitignore should not be here &&
2358 | 	test_completion "git rm " <<-\EOF &&
2359 | 	.gitignore
2360 | 	modified
2361 | 	EOF
2362 | 
2363 | 	test_completion "git clean " "untracked" &&
2364 | 
2365 | 	: TODO .gitignore should not be here &&
2366 | 	test_completion "git mv " <<-\EOF &&
2367 | 	.gitignore
2368 | 	modified
2369 | 	EOF
2370 | 
2371 | 	mkdir dir &&
2372 | 	touch dir/file-in-dir &&
2373 | 	git add dir/file-in-dir &&
2374 | 	git commit -m dir &&
2375 | 
2376 | 	mkdir untracked-dir &&
2377 | 
2378 | 	: TODO .gitignore should not be here &&
2379 | 	test_completion "git mv modified " <<-\EOF &&
2380 | 	.gitignore
2381 | 	dir
2382 | 	modified
2383 | 	untracked
2384 | 	untracked-dir
2385 | 	EOF
2386 | 
2387 | 	test_completion "git commit " "modified" &&
2388 | 
2389 | 	: TODO .gitignore should not be here &&
2390 | 	test_completion "git ls-files " <<-\EOF &&
2391 | 	.gitignore
2392 | 	dir
2393 | 	modified
2394 | 	EOF
2395 | 
2396 | 	touch momified &&
2397 | 	test_completion "git add mom" "momified"
2398 | '
2399 | 
2400 | test_expect_success "simple alias" '
2401 | 	test_config alias.co checkout &&
2402 | 	test_completion "git co m" <<-\EOF
2403 | 	main Z
2404 | 	mybranch Z
2405 | 	mytag Z
2406 | 	EOF
2407 | '
2408 | 
2409 | test_expect_success "recursive alias" '
2410 | 	test_config alias.co checkout &&
2411 | 	test_config alias.cod "co --detached" &&
2412 | 	test_completion "git cod m" <<-\EOF
2413 | 	main Z
2414 | 	mybranch Z
2415 | 	mytag Z
2416 | 	EOF
2417 | '
2418 | 
2419 | test_expect_success "completion uses  completion for alias: !sh -c 'git  ...'" '
2420 | 	test_config_global alias.co "!sh -c '"'"'git checkout ...'"'"'" &&
2421 | 	test_completion "git co m" <<-\EOF
2422 | 	main Z
2423 | 	mybranch Z
2424 | 	mytag Z
2425 | 	EOF
2426 | '
2427 | 
2428 | test_expect_success 'completion uses  completion for alias: !f () { VAR=val git  ... }' '
2429 | 	test_config_global alias.co "!f () { VAR=val git checkout ... ; } f" &&
2430 | 	test_completion "git co m" <<-\EOF
2431 | 	main Z
2432 | 	mybranch Z
2433 | 	mytag Z
2434 | 	EOF
2435 | '
2436 | 
2437 | test_expect_success 'completion used  completion for alias: !f() { : git  ; ... }' '
2438 | 	test_config_global alias.co "!f() { : git checkout ; if ... } f" &&
2439 | 	test_completion "git co m" <<-\EOF
2440 | 	main Z
2441 | 	mybranch Z
2442 | 	mytag Z
2443 | 	EOF
2444 | '
2445 | 
2446 | test_expect_success 'completion without explicit _git_xxx function' '
2447 | 	test_completion "git version --" <<-\EOF
2448 | 	--build-options Z
2449 | 	--no-build-options Z
2450 | 	EOF
2451 | '
2452 | 
2453 | test_expect_failure 'complete with tilde expansion' '
2454 | 	git init tmp && cd tmp &&
2455 | 	test_when_finished "cd .. && rm -rf tmp" &&
2456 | 
2457 | 	touch ~/tmp/file &&
2458 | 
2459 | 	test_completion "git add ~/tmp/" "~/tmp/file"
2460 | '
2461 | 
2462 | test_expect_success 'setup other remote for remote reference completion' '
2463 | 	git remote add other otherrepo &&
2464 | 	git fetch other
2465 | '
2466 | 
2467 | for flag in -d --delete
2468 | do
2469 | 	test_expect_success "__git_complete_remote_or_refspec - push $flag other" '
2470 | 		sed -e "s/Z$//" >expected <<-EOF &&
2471 | 		main-in-other Z
2472 | 		EOF
2473 | 		(
2474 | 			words=(git push '$flag' other ma) &&
2475 | 			cword=${#words[@]} cur=${words[cword-1]} &&
2476 | 			__git_cmd_idx=1 &&
2477 | 			run_func __git_complete_remote_or_refspec
2478 | 		) &&
2479 | 		test_cmp expected out
2480 | 	'
2481 | 
2482 | 	test_expect_failure "__git_complete_remote_or_refspec - push other $flag" '
2483 | 		sed -e "s/Z$//" >expected <<-EOF &&
2484 | 		main-in-other Z
2485 | 		EOF
2486 | 		(
2487 | 			words=(git push other '$flag' ma) &&
2488 | 			cword=${#words[@]} cur=${words[cword-1]} &&
2489 | 			__git_cmd_idx=1 &&
2490 | 			run_func __git_complete_remote_or_refspec
2491 | 		) &&
2492 | 		test_cmp expected out
2493 | 	'
2494 | done
2495 | 
2496 | test_expect_success 'git config - section' '
2497 | 	test_completion "git config br" <<-\EOF
2498 | 	branch.Z
2499 | 	browser.Z
2500 | 	EOF
2501 | '
2502 | 
2503 | test_expect_unstable 'git config - section include, includeIf' '
2504 | 	test_completion "git config inclu" <<-\EOF
2505 | 	include.Z
2506 | 	includeIf.Z
2507 | 	EOF
2508 | '
2509 | 
2510 | test_expect_success 'git config - variable name' '
2511 | 	test_completion "git config log.d" <<-\EOF
2512 | 	log.date Z
2513 | 	log.decorate Z
2514 | 	log.diffMerges Z
2515 | 	EOF
2516 | '
2517 | 
2518 | test_expect_unstable 'git config - variable name include' '
2519 | 	test_completion "git config include.p" <<-\EOF
2520 | 	include.path Z
2521 | 	EOF
2522 | '
2523 | 
2524 | test_expect_success 'git config - value' '
2525 | 	test_completion "git config color.pager " <<-\EOF
2526 | 	false Z
2527 | 	true Z
2528 | 	EOF
2529 | '
2530 | 
2531 | test_expect_success 'git config - direct completions' '
2532 | 	test_completion "git config branch.autoSetup" <<-\EOF
2533 | 	branch.autoSetupMerge Z
2534 | 	branch.autoSetupRebase Z
2535 | 	EOF
2536 | '
2537 | 
2538 | test_expect_success 'git -c - section' '
2539 | 	test_completion "git -c br" <<-\EOF
2540 | 	branch.Z
2541 | 	browser.Z
2542 | 	EOF
2543 | '
2544 | 
2545 | test_expect_success 'git -c - variable name' '
2546 | 	test_completion "git -c log.d" <<-\EOF
2547 | 	log.date=Z
2548 | 	log.decorate=Z
2549 | 	log.diffMerges=Z
2550 | 	EOF
2551 | '
2552 | 
2553 | test_expect_success 'git -c - value' '
2554 | 	test_completion "git -c color.pager=" <<-\EOF
2555 | 	false Z
2556 | 	true Z
2557 | 	EOF
2558 | '
2559 | 
2560 | test_expect_success 'git clone --config= - section' '
2561 | 	test_completion "git clone --config=br" <<-\EOF
2562 | 	branch.Z
2563 | 	browser.Z
2564 | 	EOF
2565 | '
2566 | 
2567 | test_expect_success 'git clone --config= - variable name' '
2568 | 	test_completion "git clone --config=log.d" <<-\EOF
2569 | 	log.date=Z
2570 | 	log.decorate=Z
2571 | 	log.diffMerges=Z
2572 | 	EOF
2573 | '
2574 | 
2575 | test_expect_success 'git clone --config= - value' '
2576 | 	test_completion "git clone --config=color.pager=" <<-\EOF
2577 | 	false Z
2578 | 	true Z
2579 | 	EOF
2580 | '
2581 | 
2582 | test_expect_success 'options with value' '
2583 | 	test_completion "git merge -X diff-algorithm=" <<-\EOF
2584 | 
2585 | 	EOF
2586 | '
2587 | 
2588 | test_expect_success 'sourcing the completion script clears cached commands' '
2589 | 	(
2590 | 		__git_compute_all_commands &&
2591 | 		verbose test -n "$__git_all_commands" &&
2592 | 		. "$SRC_DIR/git-completion.bash" &&
2593 | 		verbose test -z "$__git_all_commands"
2594 | 	)
2595 | '
2596 | 
2597 | test_expect_success 'sourcing the completion script clears cached merge strategies' '
2598 | 	(
2599 | 		__git_compute_merge_strategies &&
2600 | 		verbose test -n "$__git_merge_strategies" &&
2601 | 		. "$SRC_DIR/git-completion.bash" &&
2602 | 		verbose test -z "$__git_merge_strategies"
2603 | 	)
2604 | '
2605 | 
2606 | test_expect_success 'sourcing the completion script clears cached --options' '
2607 | 	(
2608 | 		__gitcomp_builtin checkout &&
2609 | 		verbose test -n "$__gitcomp_builtin_checkout" &&
2610 | 		__gitcomp_builtin notes_edit &&
2611 | 		verbose test -n "$__gitcomp_builtin_notes_edit" &&
2612 | 		. "$SRC_DIR/git-completion.bash" &&
2613 | 		verbose test -z "$__gitcomp_builtin_checkout" &&
2614 | 		verbose test -z "$__gitcomp_builtin_notes_edit"
2615 | 	)
2616 | '
2617 | 
2618 | test_expect_success 'option aliases are not shown by default' '
2619 | 	test_completion "git clone --recurs" "--recurse-submodules "
2620 | '
2621 | 
2622 | test_expect_success 'option aliases are shown with GIT_COMPLETION_SHOW_ALL' '
2623 | 	(
2624 | 		. "$SRC_DIR/git-completion.bash" &&
2625 | 		GIT_COMPLETION_SHOW_ALL=1 && export GIT_COMPLETION_SHOW_ALL &&
2626 | 		test_completion "git clone --recurs" <<-\EOF
2627 | 		--recurse-submodules Z
2628 | 		--recursive Z
2629 | 		EOF
2630 | 	)
2631 | '
2632 | 
2633 | test_expect_success 'plumbing commands are excluded without GIT_COMPLETION_SHOW_ALL_COMMANDS' '
2634 | 	(
2635 | 		. "$SRC_DIR/git-completion.bash" &&
2636 | 		sane_unset GIT_TESTING_PORCELAIN_COMMAND_LIST &&
2637 | 
2638 | 		# Just mainporcelain, not plumbing commands
2639 | 		run_completion "git c" &&
2640 | 		grep checkout out &&
2641 | 		! grep cat-file out
2642 | 	)
2643 | '
2644 | 
2645 | test_expect_success 'all commands are shown with GIT_COMPLETION_SHOW_ALL_COMMANDS (also main non-builtin)' '
2646 | 	(
2647 | 		. "$SRC_DIR/git-completion.bash" &&
2648 | 		GIT_COMPLETION_SHOW_ALL_COMMANDS=1 &&
2649 | 		export GIT_COMPLETION_SHOW_ALL_COMMANDS &&
2650 | 		sane_unset GIT_TESTING_PORCELAIN_COMMAND_LIST &&
2651 | 
2652 | 		# Both mainporcelain and plumbing commands
2653 | 		run_completion "git c" &&
2654 | 		grep checkout out &&
2655 | 		grep cat-file out &&
2656 | 
2657 | 		# Check "gitk", a "main" command, but not a built-in + more plumbing
2658 | 		run_completion "git g" &&
2659 | 		grep gitk out &&
2660 | 		grep get-tar-commit-id out
2661 | 	)
2662 | '
2663 | 
2664 | test_expect_success '__git_complete' '
2665 | 	unset -f __git_wrap__git_main &&
2666 | 
2667 | 	__git_complete foo __git_main &&
2668 | 	__git_have_func __git_wrap__git_main &&
2669 | 	unset -f __git_wrap__git_main &&
2670 | 
2671 | 	__git_complete gf _git_fetch &&
2672 | 	__git_have_func __git_wrap_git_fetch &&
2673 | 
2674 | 	__git_complete foo git &&
2675 | 	__git_have_func __git_wrap__git_main &&
2676 | 	unset -f __git_wrap__git_main &&
2677 | 
2678 | 	__git_complete gd git_diff &&
2679 | 	__git_have_func __git_wrap_git_diff &&
2680 | 
2681 | 	test_must_fail __git_complete ga missing
2682 | '
2683 | 
2684 | test_expect_success '__git_complete has correct __git_cmd_idx' '
2685 | 	__git_complete ga _git_add &&
2686 | 	echo modified > file1 &&
2687 | 	touch file3 &&
2688 | 	_words=(ga --update f) _cword=2 &&
2689 | 	__git_wrap_git_add &&
2690 | 	test "${COMPREPLY[*]}" = "file1"
2691 | '
2692 | 
2693 | test_done
2694 | 


--------------------------------------------------------------------------------
/t/lib-bash.sh:
--------------------------------------------------------------------------------
 1 | # Shell library sourced instead of ./test-lib.sh by tests that need
 2 | # to run under Bash; primarily intended for tests of the completion
 3 | # script.
 4 | 
 5 | if test -n "$BASH" && test -z "$POSIXLY_CORRECT"; then
 6 | 	# we are in full-on bash mode
 7 | 	true
 8 | elif type bash >/dev/null 2>&1; then
 9 | 	# execute in full-on bash mode
10 | 	unset POSIXLY_CORRECT
11 | 	exec bash "$0" "$@"
12 | else
13 | 	echo '1..0 #SKIP skipping bash completion tests; bash not available'
14 | 	exit 0
15 | fi
16 | 
17 | . "$(dirname "$0")"/test-lib.sh
18 | 


--------------------------------------------------------------------------------
/t/prompt.t:
--------------------------------------------------------------------------------
  1 | #!/bin/sh
  2 | #
  3 | # Copyright (c) 2012 SZEDER Gábor
  4 | #
  5 | 
  6 | test_description='test git-specific bash prompt functions'
  7 | 
  8 | . "$(dirname "$0")"/lib-bash.sh
  9 | 
 10 | . "$SRC_DIR/git-prompt.sh"
 11 | 
 12 | actual="$TRASH_DIRECTORY/actual"
 13 | c_red='\001\e[31m\002'
 14 | c_green='\001\e[32m\002'
 15 | c_lblue='\001\e[1;34m\002'
 16 | c_clear='\001\e[0m\002'
 17 | 
 18 | unset GIT_PS1_SHOWDIRTYSTATE
 19 | unset GIT_PS1_SHOWSTASHSTATE
 20 | unset GIT_PS1_SHOWUNTRACKEDFILES
 21 | unset GIT_PS1_COMPRESSSPARSESTATE
 22 | unset GIT_PS1_SHOWUPSTREAM
 23 | unset GIT_PS1_STATESEPARATOR
 24 | unset GIT_PS1_SHOWCOLORHINTS
 25 | 
 26 | test_expect_success 'setup for prompt tests' '
 27 | 	git init otherrepo &&
 28 | 	echo 1 >file &&
 29 | 	git add file &&
 30 | 	test_tick &&
 31 | 	git commit -m initial &&
 32 | 	git tag -a -m msg1 t1 &&
 33 | 	git checkout -b b1 &&
 34 | 	echo 2 >file &&
 35 | 	git commit -m "second b1" file &&
 36 | 	echo 3 >file &&
 37 | 	git commit -m "third b1" file &&
 38 | 	git tag -a -m msg2 t2 &&
 39 | 	git checkout -b b2 master &&
 40 | 	echo 0 >file &&
 41 | 	git commit -m "second b2" file &&
 42 | 	echo 00 >file &&
 43 | 	git commit -m "another b2" file &&
 44 | 	echo 000 >file &&
 45 | 	git commit -m "yet another b2" file &&
 46 | 	mkdir ignored_dir &&
 47 | 	echo "ignored_dir/" >>.gitignore &&
 48 | 	git checkout master
 49 | '
 50 | 
 51 | test_expect_success 'prompt - branch name' '
 52 | 	printf " (master)" >expected &&
 53 | 	__git_ps1 >"$actual" &&
 54 | 	test_cmp expected "$actual"
 55 | '
 56 | 
 57 | test_expect_success SYMLINKS 'prompt - branch name - symlink symref' '
 58 | 	printf " (master)" >expected &&
 59 | 	test_when_finished "git checkout master" &&
 60 | 	test_config core.preferSymlinkRefs true &&
 61 | 	git checkout master &&
 62 | 	__git_ps1 >"$actual" &&
 63 | 	test_cmp expected "$actual"
 64 | '
 65 | 
 66 | test_expect_success 'prompt - unborn branch' '
 67 | 	printf " (unborn)" >expected &&
 68 | 	git checkout --orphan unborn &&
 69 | 	test_when_finished "git checkout master" &&
 70 | 	__git_ps1 >"$actual" &&
 71 | 	test_cmp expected "$actual"
 72 | '
 73 | 
 74 | if test_have_prereq !FUNNYNAMES; then
 75 | 	say 'Your filesystem does not allow newlines in filenames.'
 76 | fi
 77 | 
 78 | test_expect_success FUNNYNAMES 'prompt - with newline in path' '
 79 |     repo_with_newline="repo
 80 | with
 81 | newline" &&
 82 | 	mkdir "$repo_with_newline" &&
 83 | 	printf " (master)" >expected &&
 84 | 	git init "$repo_with_newline" &&
 85 | 	test_when_finished "rm -rf \"$repo_with_newline\"" &&
 86 | 	mkdir "$repo_with_newline"/subdir &&
 87 | 	(
 88 | 		cd "$repo_with_newline/subdir" &&
 89 | 		__git_ps1 >"$actual"
 90 | 	) &&
 91 | 	test_cmp expected "$actual"
 92 | '
 93 | 
 94 | test_expect_success 'prompt - detached head' '
 95 | 	printf " ((%s...))" $(git log -1 --format="%h" --abbrev=13 b1^) >expected &&
 96 | 	test_config core.abbrev 13 &&
 97 | 	git checkout b1^ &&
 98 | 	test_when_finished "git checkout master" &&
 99 | 	__git_ps1 >"$actual" &&
100 | 	test_cmp expected "$actual"
101 | '
102 | 
103 | test_expect_success 'prompt - describe detached head - contains' '
104 | 	printf " ((t2~1))" >expected &&
105 | 	git checkout b1^ &&
106 | 	test_when_finished "git checkout master" &&
107 | 	(
108 | 		GIT_PS1_DESCRIBE_STYLE=contains &&
109 | 		__git_ps1 >"$actual"
110 | 	) &&
111 | 	test_cmp expected "$actual"
112 | '
113 | 
114 | test_expect_success 'prompt - describe detached head - branch' '
115 | 	printf " ((tags/t2~1))" >expected &&
116 | 	git checkout b1^ &&
117 | 	test_when_finished "git checkout master" &&
118 | 	(
119 | 		GIT_PS1_DESCRIBE_STYLE=branch &&
120 | 		__git_ps1 >"$actual"
121 | 	) &&
122 | 	test_cmp expected "$actual"
123 | '
124 | 
125 | test_expect_success 'prompt - describe detached head - describe' '
126 | 	printf " ((t1-1-g%s))" $(git log -1 --format="%h" b1^) >expected &&
127 | 	git checkout b1^ &&
128 | 	test_when_finished "git checkout master" &&
129 | 	(
130 | 		GIT_PS1_DESCRIBE_STYLE=describe &&
131 | 		__git_ps1 >"$actual"
132 | 	) &&
133 | 	test_cmp expected "$actual"
134 | '
135 | 
136 | test_expect_success 'prompt - describe detached head - default' '
137 | 	printf " ((t2))" >expected &&
138 | 	git checkout --detach b1 &&
139 | 	test_when_finished "git checkout master" &&
140 | 	__git_ps1 >"$actual" &&
141 | 	test_cmp expected "$actual"
142 | '
143 | 
144 | test_expect_success 'prompt - inside .git directory' '
145 | 	printf " (GIT_DIR!)" >expected &&
146 | 	(
147 | 		cd .git &&
148 | 		__git_ps1 >"$actual"
149 | 	) &&
150 | 	test_cmp expected "$actual"
151 | '
152 | 
153 | test_expect_success 'prompt - deep inside .git directory' '
154 | 	printf " (GIT_DIR!)" >expected &&
155 | 	(
156 | 		cd .git/objects &&
157 | 		__git_ps1 >"$actual"
158 | 	) &&
159 | 	test_cmp expected "$actual"
160 | '
161 | 
162 | test_expect_success 'prompt - inside bare repository' '
163 | 	printf " (BARE:master)" >expected &&
164 | 	git init --bare bare.git &&
165 | 	test_when_finished "rm -rf bare.git" &&
166 | 	(
167 | 		cd bare.git &&
168 | 		__git_ps1 >"$actual"
169 | 	) &&
170 | 	test_cmp expected "$actual"
171 | '
172 | 
173 | test_expect_success 'prompt - interactive rebase' '
174 | 	printf " (b1|REBASE 2/3)" >expected &&
175 | 	write_script fake_editor.sh <<-\EOF &&
176 | 		echo "exec echo" >"$1"
177 | 		echo "edit $(git log -1 --format="%h")" >>"$1"
178 | 		echo "exec echo" >>"$1"
179 | 	EOF
180 | 	test_when_finished "rm -f fake_editor.sh" &&
181 | 	test_set_editor "$TRASH_DIRECTORY/fake_editor.sh" &&
182 | 	git checkout b1 &&
183 | 	test_when_finished "git checkout master" &&
184 | 	git rebase -i HEAD^ &&
185 | 	test_when_finished "git rebase --abort" &&
186 | 	__git_ps1 >"$actual" &&
187 | 	test_cmp expected "$actual"
188 | '
189 | 
190 | test_expect_success 'prompt - rebase merge' '
191 | 	printf " (b2|REBASE 1/3)" >expected &&
192 | 	git checkout b2 &&
193 | 	test_when_finished "git checkout master" &&
194 | 	test_must_fail git rebase --merge b1 b2 &&
195 | 	test_when_finished "git rebase --abort" &&
196 | 	__git_ps1 >"$actual" &&
197 | 	test_cmp expected "$actual"
198 | '
199 | 
200 | test_expect_success 'prompt - rebase am' '
201 | 	printf " (b2|REBASE 1/3)" >expected &&
202 | 	git checkout b2 &&
203 | 	test_when_finished "git checkout master" &&
204 | 	test_must_fail git rebase --apply b1 b2 &&
205 | 	test_when_finished "git rebase --abort" &&
206 | 	__git_ps1 >"$actual" &&
207 | 	test_cmp expected "$actual"
208 | '
209 | 
210 | test_expect_success 'prompt - merge' '
211 | 	printf " (b1|MERGING)" >expected &&
212 | 	git checkout b1 &&
213 | 	test_when_finished "git checkout master" &&
214 | 	test_must_fail git merge b2 &&
215 | 	test_when_finished "git reset --hard" &&
216 | 	__git_ps1 >"$actual" &&
217 | 	test_cmp expected "$actual"
218 | '
219 | 
220 | test_expect_success 'prompt - cherry-pick' '
221 | 	printf " (master|CHERRY-PICKING)" >expected &&
222 | 	test_must_fail git cherry-pick b1 b1^ &&
223 | 	test_when_finished "git cherry-pick --abort" &&
224 | 	__git_ps1 >"$actual" &&
225 | 	test_cmp expected "$actual" &&
226 | 	git reset --merge &&
227 | 	test_must_fail git rev-parse CHERRY_PICK_HEAD &&
228 | 	__git_ps1 >"$actual" &&
229 | 	test_cmp expected "$actual"
230 | '
231 | 
232 | test_expect_success 'prompt - revert' '
233 | 	printf " (master|REVERTING)" >expected &&
234 | 	test_must_fail git revert b1^ b1 &&
235 | 	test_when_finished "git revert --abort" &&
236 | 	__git_ps1 >"$actual" &&
237 | 	test_cmp expected "$actual" &&
238 | 	git reset --merge &&
239 | 	test_must_fail git rev-parse REVERT_HEAD &&
240 | 	__git_ps1 >"$actual" &&
241 | 	test_cmp expected "$actual"
242 | '
243 | 
244 | test_expect_success 'prompt - bisect' '
245 | 	printf " (master|BISECTING)" >expected &&
246 | 	git bisect start &&
247 | 	test_when_finished "git bisect reset" &&
248 | 	__git_ps1 >"$actual" &&
249 | 	test_cmp expected "$actual"
250 | '
251 | 
252 | test_expect_success 'prompt - dirty status indicator - clean' '
253 | 	printf " (master)" >expected &&
254 | 	(
255 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
256 | 		__git_ps1 >"$actual"
257 | 	) &&
258 | 	test_cmp expected "$actual"
259 | '
260 | 
261 | test_expect_success 'prompt - dirty status indicator - dirty worktree' '
262 | 	printf " (master *)" >expected &&
263 | 	echo "dirty" >file &&
264 | 	test_when_finished "git reset --hard" &&
265 | 	(
266 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
267 | 		__git_ps1 >"$actual"
268 | 	) &&
269 | 	test_cmp expected "$actual"
270 | '
271 | 
272 | test_expect_success 'prompt - dirty status indicator - dirty index' '
273 | 	printf " (master +)" >expected &&
274 | 	echo "dirty" >file &&
275 | 	test_when_finished "git reset --hard" &&
276 | 	git add -u &&
277 | 	(
278 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
279 | 		__git_ps1 >"$actual"
280 | 	) &&
281 | 	test_cmp expected "$actual"
282 | '
283 | 
284 | test_expect_success 'prompt - dirty status indicator - dirty index and worktree' '
285 | 	printf " (master *+)" >expected &&
286 | 	echo "dirty index" >file &&
287 | 	test_when_finished "git reset --hard" &&
288 | 	git add -u &&
289 | 	echo "dirty worktree" >file &&
290 | 	(
291 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
292 | 		__git_ps1 >"$actual"
293 | 	) &&
294 | 	test_cmp expected "$actual"
295 | '
296 | 
297 | test_expect_success 'prompt - dirty status indicator - orphan branch - clean' '
298 | 	printf " (orphan #)" >expected &&
299 | 	test_when_finished "git checkout master" &&
300 | 	git checkout --orphan orphan &&
301 | 	git reset --hard &&
302 | 	(
303 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
304 | 		__git_ps1 >"$actual"
305 | 	) &&
306 | 	test_cmp expected "$actual"
307 | '
308 | 
309 | test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index' '
310 | 	printf " (orphan +)" >expected &&
311 | 	test_when_finished "git checkout master" &&
312 | 	git checkout --orphan orphan &&
313 | 	(
314 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
315 | 		__git_ps1 >"$actual"
316 | 	) &&
317 | 	test_cmp expected "$actual"
318 | '
319 | 
320 | test_expect_success 'prompt - dirty status indicator - orphan branch - dirty index and worktree' '
321 | 	printf " (orphan *+)" >expected &&
322 | 	test_when_finished "git checkout master" &&
323 | 	git checkout --orphan orphan &&
324 | 	>file &&
325 | 	(
326 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
327 | 		__git_ps1 >"$actual"
328 | 	) &&
329 | 	test_cmp expected "$actual"
330 | '
331 | 
332 | test_expect_success 'prompt - dirty status indicator - shell variable unset with config disabled' '
333 | 	printf " (master)" >expected &&
334 | 	echo "dirty" >file &&
335 | 	test_when_finished "git reset --hard" &&
336 | 	test_config bash.showDirtyState false &&
337 | 	(
338 | 		sane_unset GIT_PS1_SHOWDIRTYSTATE &&
339 | 		__git_ps1 >"$actual"
340 | 	) &&
341 | 	test_cmp expected "$actual"
342 | '
343 | 
344 | test_expect_success 'prompt - dirty status indicator - shell variable unset with config enabled' '
345 | 	printf " (master)" >expected &&
346 | 	echo "dirty" >file &&
347 | 	test_when_finished "git reset --hard" &&
348 | 	test_config bash.showDirtyState true &&
349 | 	(
350 | 		sane_unset GIT_PS1_SHOWDIRTYSTATE &&
351 | 		__git_ps1 >"$actual"
352 | 	) &&
353 | 	test_cmp expected "$actual"
354 | '
355 | 
356 | test_expect_success 'prompt - dirty status indicator - shell variable set with config disabled' '
357 | 	printf " (master)" >expected &&
358 | 	echo "dirty" >file &&
359 | 	test_when_finished "git reset --hard" &&
360 | 	test_config bash.showDirtyState false &&
361 | 	(
362 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
363 | 		__git_ps1 >"$actual"
364 | 	) &&
365 | 	test_cmp expected "$actual"
366 | '
367 | 
368 | test_expect_success 'prompt - dirty status indicator - shell variable set with config enabled' '
369 | 	printf " (master *)" >expected &&
370 | 	echo "dirty" >file &&
371 | 	test_when_finished "git reset --hard" &&
372 | 	test_config bash.showDirtyState true &&
373 | 	(
374 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
375 | 		__git_ps1 >"$actual"
376 | 	) &&
377 | 	test_cmp expected "$actual"
378 | '
379 | 
380 | test_expect_success 'prompt - dirty status indicator - not shown inside .git directory' '
381 | 	printf " (GIT_DIR!)" >expected &&
382 | 	echo "dirty" >file &&
383 | 	test_when_finished "git reset --hard" &&
384 | 	(
385 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
386 | 		cd .git &&
387 | 		__git_ps1 >"$actual"
388 | 	) &&
389 | 	test_cmp expected "$actual"
390 | '
391 | 
392 | test_expect_success 'prompt - stash status indicator - no stash' '
393 | 	printf " (master)" >expected &&
394 | 	(
395 | 		GIT_PS1_SHOWSTASHSTATE=y &&
396 | 		__git_ps1 >"$actual"
397 | 	) &&
398 | 	test_cmp expected "$actual"
399 | '
400 | 
401 | test_expect_success 'prompt - stash status indicator - stash' '
402 | 	printf " (master $)" >expected &&
403 | 	echo 2 >file &&
404 | 	git stash &&
405 | 	test_when_finished "git stash drop" &&
406 | 	git pack-refs --all &&
407 | 	(
408 | 		GIT_PS1_SHOWSTASHSTATE=y &&
409 | 		__git_ps1 >"$actual"
410 | 	) &&
411 | 	test_cmp expected "$actual"
412 | '
413 | 
414 | test_expect_success 'prompt - stash status indicator - not shown inside .git directory' '
415 | 	printf " (GIT_DIR!)" >expected &&
416 | 	echo 2 >file &&
417 | 	git stash &&
418 | 	test_when_finished "git stash drop" &&
419 | 	(
420 | 		GIT_PS1_SHOWSTASHSTATE=y &&
421 | 		cd .git &&
422 | 		__git_ps1 >"$actual"
423 | 	) &&
424 | 	test_cmp expected "$actual"
425 | '
426 | 
427 | test_expect_success 'prompt - untracked files status indicator - no untracked files' '
428 | 	printf " (master)" >expected &&
429 | 	(
430 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
431 | 		cd otherrepo &&
432 | 		__git_ps1 >"$actual"
433 | 	) &&
434 | 	test_cmp expected "$actual"
435 | '
436 | 
437 | test_expect_success 'prompt - untracked files status indicator - untracked files' '
438 | 	printf " (master %%)" >expected &&
439 | 	(
440 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
441 | 		__git_ps1 >"$actual"
442 | 	) &&
443 | 	test_cmp expected "$actual"
444 | '
445 | 
446 | test_expect_success 'prompt - untracked files status indicator - empty untracked dir' '
447 | 	printf " (master)" >expected &&
448 | 	mkdir otherrepo/untracked-dir &&
449 | 	test_when_finished "rm -rf otherrepo/untracked-dir" &&
450 | 	(
451 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
452 | 		cd otherrepo &&
453 | 		__git_ps1 >"$actual"
454 | 	) &&
455 | 	test_cmp expected "$actual"
456 | '
457 | 
458 | test_expect_success 'prompt - untracked files status indicator - non-empty untracked dir' '
459 | 	printf " (master %%)" >expected &&
460 | 	mkdir otherrepo/untracked-dir &&
461 | 	test_when_finished "rm -rf otherrepo/untracked-dir" &&
462 | 	>otherrepo/untracked-dir/untracked-file &&
463 | 	(
464 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
465 | 		cd otherrepo &&
466 | 		__git_ps1 >"$actual"
467 | 	) &&
468 | 	test_cmp expected "$actual"
469 | '
470 | 
471 | test_expect_success 'prompt - untracked files status indicator - untracked files outside cwd' '
472 | 	printf " (master %%)" >expected &&
473 | 	(
474 | 		mkdir -p ignored_dir &&
475 | 		cd ignored_dir &&
476 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
477 | 		__git_ps1 >"$actual"
478 | 	) &&
479 | 	test_cmp expected "$actual"
480 | '
481 | 
482 | test_expect_success 'prompt - untracked files status indicator - shell variable unset with config disabled' '
483 | 	printf " (master)" >expected &&
484 | 	test_config bash.showUntrackedFiles false &&
485 | 	(
486 | 		sane_unset GIT_PS1_SHOWUNTRACKEDFILES &&
487 | 		__git_ps1 >"$actual"
488 | 	) &&
489 | 	test_cmp expected "$actual"
490 | '
491 | 
492 | test_expect_success 'prompt - untracked files status indicator - shell variable unset with config enabled' '
493 | 	printf " (master)" >expected &&
494 | 	test_config bash.showUntrackedFiles true &&
495 | 	(
496 | 		sane_unset GIT_PS1_SHOWUNTRACKEDFILES &&
497 | 		__git_ps1 >"$actual"
498 | 	) &&
499 | 	test_cmp expected "$actual"
500 | '
501 | 
502 | test_expect_success 'prompt - untracked files status indicator - shell variable set with config disabled' '
503 | 	printf " (master)" >expected &&
504 | 	test_config bash.showUntrackedFiles false &&
505 | 	(
506 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
507 | 		__git_ps1 >"$actual"
508 | 	) &&
509 | 	test_cmp expected "$actual"
510 | '
511 | 
512 | test_expect_success 'prompt - untracked files status indicator - shell variable set with config enabled' '
513 | 	printf " (master %%)" >expected &&
514 | 	test_config bash.showUntrackedFiles true &&
515 | 	(
516 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
517 | 		__git_ps1 >"$actual"
518 | 	) &&
519 | 	test_cmp expected "$actual"
520 | '
521 | 
522 | test_expect_success 'prompt - untracked files status indicator - not shown inside .git directory' '
523 | 	printf " (GIT_DIR!)" >expected &&
524 | 	(
525 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
526 | 		cd .git &&
527 | 		__git_ps1 >"$actual"
528 | 	) &&
529 | 	test_cmp expected "$actual"
530 | '
531 | 
532 | test_expect_success 'prompt - format string starting with dash' '
533 | 	printf -- "-master" >expected &&
534 | 	__git_ps1 "-%s" >"$actual" &&
535 | 	test_cmp expected "$actual"
536 | '
537 | 
538 | test_expect_success 'prompt - pc mode' '
539 | 	printf "BEFORE: (\${__git_ps1_branch_name}):AFTER\\nmaster" >expected &&
540 | 	(
541 | 		__git_ps1 "BEFORE:" ":AFTER" >"$actual" &&
542 | 		test_must_be_empty "$actual" &&
543 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
544 | 	) &&
545 | 	test_cmp expected "$actual"
546 | '
547 | 
548 | test_expect_success 'prompt - bash color pc mode - branch name' '
549 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear}):AFTER\\nmaster" >expected &&
550 | 	(
551 | 		GIT_PS1_SHOWCOLORHINTS=y &&
552 | 		__git_ps1 "BEFORE:" ":AFTER" >"$actual" &&
553 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
554 | 	) &&
555 | 	test_cmp expected "$actual"
556 | '
557 | 
558 | test_expect_success 'prompt - bash color pc mode - detached head' '
559 | 	printf "BEFORE: (${c_red}\${__git_ps1_branch_name}${c_clear}):AFTER\\n(%s...)" $(git log -1 --format="%h" b1^) >expected &&
560 | 	git checkout b1^ &&
561 | 	test_when_finished "git checkout master" &&
562 | 	(
563 | 		GIT_PS1_SHOWCOLORHINTS=y &&
564 | 		__git_ps1 "BEFORE:" ":AFTER" &&
565 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
566 | 	) &&
567 | 	test_cmp expected "$actual"
568 | '
569 | 
570 | test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty worktree' '
571 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear} ${c_red}*${c_clear}):AFTER\\nmaster" >expected &&
572 | 	echo "dirty" >file &&
573 | 	test_when_finished "git reset --hard" &&
574 | 	(
575 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
576 | 		GIT_PS1_SHOWCOLORHINTS=y &&
577 | 		__git_ps1 "BEFORE:" ":AFTER" &&
578 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
579 | 	) &&
580 | 	test_cmp expected "$actual"
581 | '
582 | 
583 | test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty index' '
584 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear} ${c_green}+${c_clear}):AFTER\\nmaster" >expected &&
585 | 	echo "dirty" >file &&
586 | 	test_when_finished "git reset --hard" &&
587 | 	git add -u &&
588 | 	(
589 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
590 | 		GIT_PS1_SHOWCOLORHINTS=y &&
591 | 		__git_ps1 "BEFORE:" ":AFTER" &&
592 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
593 | 	) &&
594 | 	test_cmp expected "$actual"
595 | '
596 | 
597 | test_expect_success 'prompt - bash color pc mode - dirty status indicator - dirty index and worktree' '
598 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear} ${c_red}*${c_clear}${c_green}+${c_clear}):AFTER\\nmaster" >expected &&
599 | 	echo "dirty index" >file &&
600 | 	test_when_finished "git reset --hard" &&
601 | 	git add -u &&
602 | 	echo "dirty worktree" >file &&
603 | 	(
604 | 		GIT_PS1_SHOWCOLORHINTS=y &&
605 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
606 | 		__git_ps1 "BEFORE:" ":AFTER" &&
607 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
608 | 	) &&
609 | 	test_cmp expected "$actual"
610 | '
611 | 
612 | test_expect_success 'prompt - bash color pc mode - dirty status indicator - before root commit' '
613 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear} ${c_green}#${c_clear}):AFTER\\nmaster" >expected &&
614 | 	(
615 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
616 | 		GIT_PS1_SHOWCOLORHINTS=y &&
617 | 		cd otherrepo &&
618 | 		__git_ps1 "BEFORE:" ":AFTER" &&
619 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
620 | 	) &&
621 | 	test_cmp expected "$actual"
622 | '
623 | 
624 | test_expect_success 'prompt - bash color pc mode - inside .git directory' '
625 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear}):AFTER\\nGIT_DIR!" >expected &&
626 | 	echo "dirty" >file &&
627 | 	test_when_finished "git reset --hard" &&
628 | 	(
629 | 		GIT_PS1_SHOWDIRTYSTATE=y &&
630 | 		GIT_PS1_SHOWCOLORHINTS=y &&
631 | 		cd .git &&
632 | 		__git_ps1 "BEFORE:" ":AFTER" &&
633 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
634 | 	) &&
635 | 	test_cmp expected "$actual"
636 | '
637 | 
638 | test_expect_success 'prompt - bash color pc mode - stash status indicator' '
639 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear} ${c_lblue}\$${c_clear}):AFTER\\nmaster" >expected &&
640 | 	echo 2 >file &&
641 | 	git stash &&
642 | 	test_when_finished "git stash drop" &&
643 | 	(
644 | 		GIT_PS1_SHOWSTASHSTATE=y &&
645 | 		GIT_PS1_SHOWCOLORHINTS=y &&
646 | 		__git_ps1 "BEFORE:" ":AFTER" &&
647 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
648 | 	) &&
649 | 	test_cmp expected "$actual"
650 | '
651 | 
652 | test_expect_success 'prompt - bash color pc mode - untracked files status indicator' '
653 | 	printf "BEFORE: (${c_green}\${__git_ps1_branch_name}${c_clear} ${c_red}%%${c_clear}):AFTER\\nmaster" >expected &&
654 | 	(
655 | 		GIT_PS1_SHOWUNTRACKEDFILES=y &&
656 | 		GIT_PS1_SHOWCOLORHINTS=y &&
657 | 		__git_ps1 "BEFORE:" ":AFTER" &&
658 | 		printf "%s\\n%s" "$PS1" "${__git_ps1_branch_name}" >"$actual"
659 | 	) &&
660 | 	test_cmp expected "$actual"
661 | '
662 | 
663 | test_expect_success 'prompt - zsh color pc mode' '
664 | 	printf "BEFORE: (%%F{green}master%%f):AFTER" >expected &&
665 | 	(
666 | 		ZSH_VERSION=5.0.0 &&
667 | 		GIT_PS1_SHOWCOLORHINTS=y &&
668 | 		__git_ps1 "BEFORE:" ":AFTER" &&
669 | 		printf "%s" "$PS1" >"$actual"
670 | 	) &&
671 | 	test_cmp expected "$actual"
672 | '
673 | 
674 | test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled' '
675 | 	printf " (master)" >expected &&
676 | 	test_config bash.hideIfPwdIgnored false &&
677 | 	(
678 | 		cd ignored_dir &&
679 | 		__git_ps1 >"$actual"
680 | 	) &&
681 | 	test_cmp expected "$actual"
682 | '
683 | 
684 | test_expect_success 'prompt - hide if pwd ignored - env var unset, config disabled, pc mode' '
685 | 	printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
686 | 	test_config bash.hideIfPwdIgnored false &&
687 | 	(
688 | 		cd ignored_dir &&
689 | 		__git_ps1 "BEFORE:" ":AFTER" &&
690 | 		printf "%s" "$PS1" >"$actual"
691 | 	) &&
692 | 	test_cmp expected "$actual"
693 | '
694 | 
695 | test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset' '
696 | 	printf " (master)" >expected &&
697 | 	(
698 | 		cd ignored_dir &&
699 | 		__git_ps1 >"$actual"
700 | 	) &&
701 | 	test_cmp expected "$actual"
702 | '
703 | 
704 | test_expect_success 'prompt - hide if pwd ignored - env var unset, config unset, pc mode' '
705 | 	printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
706 | 	(
707 | 		cd ignored_dir &&
708 | 		__git_ps1 "BEFORE:" ":AFTER" &&
709 | 		printf "%s" "$PS1" >"$actual"
710 | 	) &&
711 | 	test_cmp expected "$actual"
712 | '
713 | 
714 | test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled' '
715 | 	printf " (master)" >expected &&
716 | 	test_config bash.hideIfPwdIgnored false &&
717 | 	(
718 | 		cd ignored_dir &&
719 | 		GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
720 | 		__git_ps1 >"$actual"
721 | 	) &&
722 | 	test_cmp expected "$actual"
723 | '
724 | 
725 | test_expect_success 'prompt - hide if pwd ignored - env var set, config disabled, pc mode' '
726 | 	printf "BEFORE: (\${__git_ps1_branch_name}):AFTER" >expected &&
727 | 	test_config bash.hideIfPwdIgnored false &&
728 | 	(
729 | 		cd ignored_dir &&
730 | 		GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
731 | 		__git_ps1 "BEFORE:" ":AFTER" &&
732 | 		printf "%s" "$PS1" >"$actual"
733 | 	) &&
734 | 	test_cmp expected "$actual"
735 | '
736 | 
737 | test_expect_success 'prompt - hide if pwd ignored - env var set, config unset' '
738 | 	(
739 | 		cd ignored_dir &&
740 | 		GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
741 | 		__git_ps1 >"$actual"
742 | 	) &&
743 | 	test_must_be_empty "$actual"
744 | '
745 | 
746 | test_expect_success 'prompt - hide if pwd ignored - env var set, config unset, pc mode' '
747 | 	printf "BEFORE::AFTER" >expected &&
748 | 	(
749 | 		cd ignored_dir &&
750 | 		GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
751 | 		__git_ps1 "BEFORE:" ":AFTER" &&
752 | 		printf "%s" "$PS1" >"$actual"
753 | 	) &&
754 | 	test_cmp expected "$actual"
755 | '
756 | 
757 | test_expect_success 'prompt - hide if pwd ignored - inside gitdir' '
758 | 	printf " (GIT_DIR!)" >expected &&
759 | 	(
760 | 		GIT_PS1_HIDE_IF_PWD_IGNORED=y &&
761 | 		cd .git &&
762 | 		__git_ps1 >"$actual"
763 | 	) &&
764 | 	test_cmp expected "$actual"
765 | '
766 | 
767 | test_expect_success 'prompt - conflict indicator' '
768 | 	printf " (master|CONFLICT)" >expected &&
769 | 	echo "stash" >file &&
770 | 	git stash &&
771 | 	test_when_finished "git stash drop" &&
772 | 	echo "commit" >file &&
773 | 	git commit -m "commit" file &&
774 | 	test_when_finished "git reset --hard HEAD~" &&
775 | 	test_must_fail git stash apply &&
776 | 	(
777 | 		GIT_PS1_SHOWCONFLICTSTATE="yes" &&
778 | 		__git_ps1 >"$actual"
779 | 	) &&
780 | 	test_cmp expected "$actual"
781 | '
782 | 
783 | test_done
784 | 


--------------------------------------------------------------------------------
/t/sharness.sh:
--------------------------------------------------------------------------------
  1 | # Sharness test framework.
  2 | #
  3 | # Copyright (c) 2011-2012 Mathias Lafeldt
  4 | # Copyright (c) 2005-2012 Git project
  5 | # Copyright (c) 2005-2012 Junio C Hamano
  6 | # Copyright (c) 2019-2023 Felipe Contreras
  7 | #
  8 | # This program is free software: you can redistribute it and/or modify
  9 | # it under the terms of the GNU General Public License as published by
 10 | # the Free Software Foundation, either version 2 of the License, or
 11 | # (at your option) any later version.
 12 | #
 13 | # This program is distributed in the hope that it will be useful,
 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 | # GNU General Public License for more details.
 17 | #
 18 | # You should have received a copy of the GNU General Public License
 19 | # along with this program.  If not, see http://www.gnu.org/licenses/ .
 20 | 
 21 | if test -n "${ZSH_VERSION-}"
 22 | then
 23 | 	emulate sh
 24 | 	ARGZERO="$ZSH_ARGZERO"
 25 | else
 26 | 	ARGZERO="$0"
 27 | fi
 28 | 
 29 | # Public: Current version of Sharness.
 30 | SHARNESS_VERSION="1.2.0"
 31 | export SHARNESS_VERSION
 32 | 
 33 | : "${SHARNESS_TEST_EXTENSION:=t}"
 34 | # Public: The file extension for tests.  By default, it is set to "t".
 35 | export SHARNESS_TEST_EXTENSION
 36 | 
 37 | : "${SHARNESS_TEST_DIRECTORY:=$(dirname "$ARGZERO")}"
 38 | # ensure that SHARNESS_TEST_DIRECTORY is an absolute path so that it
 39 | # is valid even if the current working directory is changed
 40 | SHARNESS_TEST_DIRECTORY=$(cd "$SHARNESS_TEST_DIRECTORY" && pwd) || exit 1
 41 | # Public: Root directory containing tests. Tests can override this variable,
 42 | # e.g. for testing Sharness itself.
 43 | export SHARNESS_TEST_DIRECTORY
 44 | 
 45 | # shellcheck disable=SC3028
 46 | : "${SHARNESS_TEST_SRCDIR:=$(cd "$(dirname "${BASH_SOURCE-$0}")" && pwd)}"
 47 | # Public: Source directory of test code and sharness library.
 48 | # This directory may be different from the directory in which tests are
 49 | # being run.
 50 | export SHARNESS_TEST_SRCDIR
 51 | 
 52 | : "${SHARNESS_TEST_OUTDIR:=$SHARNESS_TEST_DIRECTORY}"
 53 | # Public: Directory where the output of the tests should be stored (i.e.
 54 | # trash directories).
 55 | export SHARNESS_TEST_OUTDIR
 56 | 
 57 | #  Reset TERM to original terminal if found, otherwise save original TERM
 58 | [ -z "$SHARNESS_ORIG_TERM" ] &&
 59 | 		SHARNESS_ORIG_TERM="$TERM" ||
 60 | 		TERM="$SHARNESS_ORIG_TERM"
 61 | # Public: The unsanitized TERM under which sharness is originally run
 62 | export SHARNESS_ORIG_TERM
 63 | 
 64 | # Export SHELL_PATH
 65 | : "${SHELL_PATH:=/bin/sh}"
 66 | export SHELL_PATH
 67 | 
 68 | # if --tee was passed, write the output not only to the terminal, but
 69 | # additionally to the file test-results/$BASENAME.out, too.
 70 | case "$SHARNESS_TEST_TEE_STARTED, $* " in
 71 | done,*)
 72 | 	# do not redirect again
 73 | 	;;
 74 | *' --tee '*|*' --verbose-log '*)
 75 | 	mkdir -p "$SHARNESS_TEST_OUTDIR/test-results"
 76 | 	BASE="$SHARNESS_TEST_OUTDIR/test-results/$(basename "$ARGZERO" ".$SHARNESS_TEST_EXTENSION")"
 77 | 
 78 | 	# Make this filename available to the sub-process in case it is using
 79 | 	# --verbose-log.
 80 | 	SHARNESS_TEST_TEE_OUTPUT_FILE="$BASE.out"
 81 | 	export SHARNESS_TEST_TEE_OUTPUT_FILE
 82 | 
 83 | 	# Truncate before calling "tee -a" to get rid of the results
 84 | 	# from any previous runs.
 85 | 	: >"$SHARNESS_TEST_TEE_OUTPUT_FILE"
 86 | 
 87 | 	(SHARNESS_TEST_TEE_STARTED="done" ${SHELL_PATH} "$ARGZERO" "$@" 2>&1;
 88 | 	 echo $? >"$BASE.exit") | tee -a "$SHARNESS_TEST_TEE_OUTPUT_FILE"
 89 | 	test "$(cat "$BASE.exit")" = 0
 90 | 	exit
 91 | 	;;
 92 | esac
 93 | 
 94 | # For repeatability, reset the environment to a known state.
 95 | # TERM is sanitized below, after saving color control sequences.
 96 | LANG=C
 97 | LC_ALL=C
 98 | PAGER="cat"
 99 | TZ=UTC
100 | EDITOR=:
101 | export LANG LC_ALL PAGER TZ EDITOR
102 | unset VISUAL CDPATH GREP_OPTIONS
103 | 
104 | [ "x$TERM" != "xdumb" ] && (
105 | 		[ -t 1 ] &&
106 | 		tput bold >/dev/null 2>&1 &&
107 | 		tput setaf 1 >/dev/null 2>&1 &&
108 | 		tput sgr0 >/dev/null 2>&1
109 | 	) &&
110 | 	color=t
111 | 
112 | while test "$#" -ne 0; do
113 | 	case "$1" in
114 | 	-d|--d|--de|--deb|--debu|--debug)
115 | 		debug=t; shift ;;
116 | 	-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
117 | 		immediate=t; shift ;;
118 | 	-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
119 | 		TEST_LONG=t; export TEST_LONG; shift ;;
120 | 	--in|--int|--inte|--inter|--intera|--interac|--interact|--interacti|--interactiv|--interactive|--interactive-|--interactive-t|--interactive-te|--interactive-tes|--interactive-test|--interactive-tests):
121 | 		TEST_INTERACTIVE=t; export TEST_INTERACTIVE; verbose=t; shift ;;
122 | 	-h|--h|--he|--hel|--help)
123 | 		help=t; shift ;;
124 | 	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
125 | 		verbose=t; shift ;;
126 | 	-q|--q|--qu|--qui|--quie|--quiet)
127 | 		# Ignore --quiet under a TAP::Harness. Saying how many tests
128 | 		# passed without the ok/not ok details is always an error.
129 | 		test -z "$HARNESS_ACTIVE" && quiet=t; shift ;;
130 | 	--chain-lint)
131 | 		chain_lint=t; shift ;;
132 | 	--no-chain-lint)
133 | 		chain_lint=; shift ;;
134 | 	--no-color)
135 | 		color=; shift ;;
136 | 	--tee)
137 | 		shift ;; # was handled already
138 | 	--root=*)
139 | 		root=$(expr "z$1" : 'z[^=]*=\(.*\)')
140 | 		shift ;;
141 | 	-x)
142 | 		trace=t
143 | 		shift ;;
144 | 	--verbose-log)
145 | 		verbose_log=t
146 | 		shift ;;
147 | 	*)
148 | 		echo "error: unknown test option '$1'" >&2; exit 1 ;;
149 | 	esac
150 | done
151 | 
152 | if test -n "$color"; then
153 | 	# Save the color control sequences now rather than run tput
154 | 	# each time say_color() is called.  This is done for two
155 | 	# reasons:
156 | 	#   * TERM will be changed to dumb
157 | 	#   * HOME will be changed to a temporary directory and tput
158 | 	#     might need to read ~/.terminfo from the original HOME
159 | 	#     directory to get the control sequences
160 | 	# Note:  This approach assumes the control sequences don't end
161 | 	# in a newline for any terminal of interest (command
162 | 	# substitutions strip trailing newlines).  Given that most
163 | 	# (all?) terminals in common use are related to ECMA-48, this
164 | 	# shouldn't be a problem.
165 | 	say_color_error=$(tput bold; tput setaf 1) # bold red
166 | 	say_color_skip=$(tput setaf 4) # blue
167 | 	say_color_warn=$(tput setaf 3) # brown/yellow
168 | 	say_color_pass=$(tput setaf 2) # green
169 | 	say_color_info=$(tput setaf 6) # cyan
170 | 	say_color_reset=$(tput sgr0)
171 | 	say_color_raw="" # no formatting for normal text
172 | 	say_color() {
173 | 		test -z "$1" && test -n "$quiet" && return
174 | 		case "$1" in
175 | 			error) say_color_color=$say_color_error ;;
176 | 			skip) say_color_color=$say_color_skip ;;
177 | 			warn) say_color_color=$say_color_warn ;;
178 | 			pass) say_color_color=$say_color_pass ;;
179 | 			info) say_color_color=$say_color_info ;;
180 | 			*) say_color_color=$say_color_raw ;;
181 | 		esac
182 | 		shift
183 | 		printf '%s%s%s\n' "$say_color_color" "$*" "$say_color_reset"
184 | 	}
185 | else
186 | 	say_color() {
187 | 		test -z "$1" && test -n "$quiet" && return
188 | 		shift
189 | 		printf '%s\n' "$*"
190 | 	}
191 | fi
192 | 
193 | : "${test_untraceable:=}"
194 | # Public: When set to a non-empty value, the current test will not be
195 | # traced, unless it's run with a Bash version supporting
196 | # BASH_XTRACEFD, i.e. v4.1 or later.
197 | export test_untraceable
198 | 
199 | if test -n "$trace" && test -n "$test_untraceable"
200 | then
201 | 	# '-x' tracing requested, but this test script can't be reliably
202 | 	# traced, unless it is run with a Bash version supporting
203 | 	# BASH_XTRACEFD (introduced in Bash v4.1).
204 | 	#
205 | 	# Perform this version check _after_ the test script was
206 | 	# potentially re-executed with $TEST_SHELL_PATH for '--tee' or
207 | 	# '--verbose-log', so the right shell is checked and the
208 | 	# warning is issued only once.
209 | 	if test -n "$BASH_VERSION" && eval '
210 | 	     test ${BASH_VERSINFO[0]} -gt 4 || {
211 | 	       test ${BASH_VERSINFO[0]} -eq 4 &&
212 | 	       test ${BASH_VERSINFO[1]} -ge 1
213 | 	     }
214 | 	   '
215 | 	then
216 | 		: Executed by a Bash version supporting BASH_XTRACEFD.  Good.
217 | 	else
218 | 		echo >&2 "warning: ignoring -x; '$0' is untraceable without BASH_XTRACEFD"
219 | 		trace=
220 | 	fi
221 | fi
222 | if test -n "$trace" && test -z "$verbose_log"
223 | then
224 | 	verbose=t
225 | fi
226 | 
227 | TERM=dumb
228 | export TERM
229 | 
230 | error() {
231 | 	say_color error "error: $*"
232 | 	EXIT_OK=t
233 | 	exit 1
234 | }
235 | 
236 | say() {
237 | 	say_color info "$*"
238 | }
239 | 
240 | test -n "${test_description:-}" || error "Test script did not set test_description."
241 | 
242 | if test "$help" = "t"; then
243 | 	echo "$test_description"
244 | 	exit 0
245 | fi
246 | 
247 | exec 5>&1
248 | exec 6<&0
249 | if test "$verbose_log" = "t"
250 | then
251 | 	exec 3>>"$SHARNESS_TEST_TEE_OUTPUT_FILE" 4>&3
252 | elif test "$verbose" = "t"
253 | then
254 | 	exec 4>&2 3>&1
255 | else
256 | 	exec 4>/dev/null 3>/dev/null
257 | fi
258 | 
259 | # Send any "-x" output directly to stderr to avoid polluting tests
260 | # which capture stderr. We can do this unconditionally since it
261 | # has no effect if tracing isn't turned on.
262 | #
263 | # Note that this sets up the trace fd as soon as we assign the variable, so it
264 | # must come after the creation of descriptor 4 above. Likewise, we must never
265 | # unset this, as it has the side effect of closing descriptor 4, which we
266 | # use to show verbose tests to the user.
267 | #
268 | # Note also that we don't need or want to export it. The tracing is local to
269 | # this shell, and we would not want to influence any shells we exec.
270 | BASH_XTRACEFD=4
271 | 
272 | # Public: The current test number, starting at 0.
273 | SHARNESS_TEST_NB=0
274 | export SHARNESS_TEST_NB
275 | 
276 | die() {
277 | 	code=$?
278 | 	if test -n "$EXIT_OK"; then
279 | 		exit $code
280 | 	else
281 | 		echo >&5 "FATAL: Unexpected exit with code $code"
282 | 		exit 1
283 | 	fi
284 | }
285 | 
286 | EXIT_OK=
287 | trap 'die' EXIT
288 | 
289 | test_prereq=
290 | missing_prereq=
291 | 
292 | test_failure=0
293 | test_fixed=0
294 | test_broken=0
295 | test_success=0
296 | 
297 | if test -e "$SHARNESS_TEST_SRCDIR/lib-sharness/functions.sh"
298 | then
299 | 	. "$SHARNESS_TEST_SRCDIR/lib-sharness/functions.sh"
300 | fi
301 | 
302 | # You are not expected to call test_ok_ and test_failure_ directly, use
303 | # the text_expect_* functions instead.
304 | 
305 | test_ok_() {
306 | 	test_success=$((test_success + 1))
307 | 	say_color "" "ok $SHARNESS_TEST_NB - $*"
308 | }
309 | 
310 | test_failure_() {
311 | 	test_failure=$((test_failure + 1))
312 | 	say_color error "not ok $SHARNESS_TEST_NB - $1"
313 | 	shift
314 | 	echo "$@" | sed -e 's/^/#	/'
315 | 	test "$immediate" = "" || { EXIT_OK=t; exit 1; }
316 | }
317 | 
318 | test_known_broken_ok_() {
319 | 	test_fixed=$((test_fixed + 1))
320 | 	say_color error "ok $SHARNESS_TEST_NB - $* # TODO known breakage vanished"
321 | }
322 | 
323 | test_known_broken_failure_() {
324 | 	test_broken=$((test_broken + 1))
325 | 	say_color warn "not ok $SHARNESS_TEST_NB - $* # TODO known breakage"
326 | }
327 | 
328 | want_trace () {
329 | 	test "$trace" = t && {
330 | 		test "$verbose" = t || test "$verbose_log" = t
331 | 	}
332 | }
333 | 
334 | # This is a separate function because some tests use
335 | # "return" to end a test_expect_success block early
336 | # (and we want to make sure we run any cleanup like
337 | # "set +x").
338 | test_eval_inner_ () {
339 | 	# Do not add anything extra (including LF) after '$*'
340 | 	eval "
341 | 		want_trace && set -x
342 | 		$*"
343 | }
344 | 
345 | test_eval_x_ () {
346 | 	# If "-x" tracing is in effect, then we want to avoid polluting stderr
347 | 	# with non-test commands. But once in "set -x" mode, we cannot prevent
348 | 	# the shell from printing the "set +x" to turn it off (nor the saving
349 | 	# of $? before that). But we can make sure that the output goes to
350 | 	# /dev/null.
351 | 	#
352 | 	# There are a few subtleties here:
353 | 	#
354 | 	#   - we have to redirect descriptor 4 in addition to 2, to cover
355 | 	#     BASH_XTRACEFD
356 | 	#
357 | 	#   - the actual eval has to come before the redirection block (since
358 | 	#     it needs to see descriptor 4 to set up its stderr)
359 | 	#
360 | 	#   - likewise, any error message we print must be outside the block to
361 | 	#     access descriptor 4
362 | 	#
363 | 	#   - checking $? has to come immediately after the eval, but it must
364 | 	#     be _inside_ the block to avoid polluting the "set -x" output
365 | 	#
366 | 
367 | 	test_eval_inner_ "$@" &3 2>&4
368 | 	{
369 | 		test_eval_ret_=$?
370 | 		if want_trace
371 | 		then
372 | 			set +x
373 | 		fi
374 | 	} 2>/dev/null 4>&2
375 | 
376 | 	if test "$test_eval_ret_" != 0 && want_trace
377 | 	then
378 | 		say_color error >&4 "error: last command exited with \$?=$test_eval_ret_"
379 | 	fi
380 | 	return $test_eval_ret_
381 | }
382 | 
383 | test_eval_() {
384 | 	case ",$test_prereq," in
385 | 	*,INTERACTIVE,*)
386 | 		eval "$*"
387 | 		;;
388 | 	*)
389 | 		test_eval_x_ "$@"
390 | 		;;
391 | 	esac
392 | }
393 | 
394 | test_run_() {
395 | 	test_cleanup=:
396 | 	expecting_failure=$2
397 | 	test_eval_ "$1"
398 | 	eval_ret=$?
399 | 
400 | 	if test "$chain_lint" = "t"; then
401 | 		# turn off tracing for this test-eval, as it simply creates
402 | 		# confusing noise in the "-x" output
403 | 		trace_tmp=$trace
404 | 		trace=
405 | 		# 117 is magic because it is unlikely to match the exit
406 | 		# code of other programs
407 | 		test_eval_ "(exit 117) && $1"
408 | 		if test "$?" != 117; then
409 | 			error "bug in the test script: broken &&-chain: $1"
410 | 		fi
411 | 		trace=$trace_tmp
412 | 	fi
413 | 
414 | 	if test -z "$immediate" || test $eval_ret = 0 ||
415 | 	   test -n "$expecting_failure" && test "$test_cleanup" != ":"
416 | 	then
417 | 		test_eval_ "$test_cleanup"
418 | 	fi
419 | 	if test "$verbose" = "t" && test -n "$HARNESS_ACTIVE"; then
420 | 		echo ""
421 | 	fi
422 | 	return "$eval_ret"
423 | }
424 | 
425 | test_skip_() {
426 | 	SHARNESS_TEST_NB=$((SHARNESS_TEST_NB + 1))
427 | 	to_skip=
428 | 	for skp in $SKIP_TESTS; do
429 | 		# shellcheck disable=SC2254
430 | 		case $this_test.$SHARNESS_TEST_NB in
431 | 		$skp)
432 | 			to_skip=t
433 | 			break
434 | 		esac
435 | 	done
436 | 	if test -z "$to_skip" && test -n "$test_prereq" && ! test_have_prereq "$test_prereq"; then
437 | 		to_skip=t
438 | 	fi
439 | 	case "$to_skip" in
440 | 	t)
441 | 		of_prereq=
442 | 		if test "$missing_prereq" != "$test_prereq"; then
443 | 			of_prereq=" of $test_prereq"
444 | 		fi
445 | 
446 | 		say_color skip >&3 "skipping test: $*"
447 | 		say_color skip "ok $SHARNESS_TEST_NB # skip $1 (missing $missing_prereq${of_prereq})"
448 | 		: true
449 | 		;;
450 | 	*)
451 | 		false
452 | 		;;
453 | 	esac
454 | }
455 | 
456 | remove_trash_() {
457 | 	test -d "$remove_trash" && (
458 | 		cd "$(dirname "$remove_trash")" &&
459 | 			rm -rf "$(basename "$remove_trash")"
460 | 	)
461 | }
462 | 
463 | # Public: Run test commands and expect them to succeed.
464 | #
465 | # When the test passed, an "ok" message is printed and the number of successful
466 | # tests is incremented. When it failed, a "not ok" message is printed and the
467 | # number of failed tests is incremented.
468 | #
469 | # With --immediate, exit test immediately upon the first failed test.
470 | #
471 | # Usually takes two arguments:
472 | # $1 - Test description
473 | # $2 - Commands to be executed.
474 | #
475 | # With three arguments, the first will be taken to be a prerequisite:
476 | # $1 - Comma-separated list of test prerequisites. The test will be skipped if
477 | #      not all of the given prerequisites are set. To negate a prerequisite,
478 | #      put a "!" in front of it.
479 | # $2 - Test description
480 | # $3 - Commands to be executed.
481 | #
482 | # Examples
483 | #
484 | #   test_expect_success \
485 | #       'git-write-tree should be able to write an empty tree.' \
486 | #       'tree=$(git-write-tree)'
487 | #
488 | #   # Test depending on one prerequisite.
489 | #   test_expect_success TTY 'git --paginate rev-list uses a pager' \
490 | #       ' ... '
491 | #
492 | #   # Multiple prerequisites are separated by a comma.
493 | #   test_expect_success PERL,PYTHON 'yo dawg' \
494 | #       ' test $(perl -E 'print eval "1 +" . qx[python -c "print 2"]') == "4" '
495 | #
496 | # Returns nothing.
497 | test_expect_success() {
498 | 	test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
499 | 	test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_success"
500 | 	export test_prereq
501 | 	if ! test_skip_ "$@"; then
502 | 		say >&3 "expecting success: $2"
503 | 		if test_run_ "$2"; then
504 | 			test_ok_ "$1"
505 | 		else
506 | 			test_failure_ "$@"
507 | 		fi
508 | 	fi
509 | 	echo >&3 ""
510 | }
511 | 
512 | # Public: Run test commands and expect them to fail. Used to demonstrate a known
513 | # breakage.
514 | #
515 | # This is NOT the opposite of test_expect_success, but rather used to mark a
516 | # test that demonstrates a known breakage.
517 | #
518 | # When the test passed, an "ok" message is printed and the number of fixed tests
519 | # is incremented. When it failed, a "not ok" message is printed and the number
520 | # of tests still broken is incremented.
521 | #
522 | # Failures from these tests won't cause --immediate to stop.
523 | #
524 | # Usually takes two arguments:
525 | # $1 - Test description
526 | # $2 - Commands to be executed.
527 | #
528 | # With three arguments, the first will be taken to be a prerequisite:
529 | # $1 - Comma-separated list of test prerequisites. The test will be skipped if
530 | #      not all of the given prerequisites are set. To negate a prerequisite,
531 | #      put a "!" in front of it.
532 | # $2 - Test description
533 | # $3 - Commands to be executed.
534 | #
535 | # Returns nothing.
536 | test_expect_failure() {
537 | 	test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
538 | 	test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_failure"
539 | 	export test_prereq
540 | 	if ! test_skip_ "$@"; then
541 | 		say >&3 "checking known breakage: $2"
542 | 		if test_run_ "$2" expecting_failure; then
543 | 			test_known_broken_ok_ "$1"
544 | 		else
545 | 			test_known_broken_failure_ "$1"
546 | 		fi
547 | 	fi
548 | 	echo >&3 ""
549 | }
550 | 
551 | # Public: Run test commands and expect anything from them. Used when a
552 | # test is not stable or not finished for some reason.
553 | #
554 | # When the test passed, an "ok" message is printed, but the number of
555 | # fixed tests is not incremented.
556 | #
557 | # When it failed, a "not ok ... # TODO known breakage" message is
558 | # printed, and the number of tests still broken is incremented.
559 | #
560 | # Failures from these tests won't cause --immediate to stop.
561 | #
562 | # Usually takes two arguments:
563 | # $1 - Test description
564 | # $2 - Commands to be executed.
565 | #
566 | # With three arguments, the first will be taken to be a prerequisite:
567 | # $1 - Comma-separated list of test prerequisites. The test will be skipped if
568 | #      not all of the given prerequisites are set. To negate a prerequisite,
569 | #      put a "!" in front of it.
570 | # $2 - Test description
571 | # $3 - Commands to be executed.
572 | #
573 | # Returns nothing.
574 | test_expect_unstable() {
575 | 	test "$#" = 3 && { test_prereq=$1; shift; } || test_prereq=
576 | 	test "$#" = 2 || error "bug in the test script: not 2 or 3 parameters to test_expect_unstable"
577 | 	export test_prereq
578 | 	if ! test_skip_ "$@"; then
579 | 		say >&3 "checking unstable test: $2"
580 | 		if test_run_ "$2" unstable; then
581 | 			test_ok_ "$1"
582 | 		else
583 | 			test_known_broken_failure_ "$1"
584 | 		fi
585 | 	fi
586 | 	echo >&3 ""
587 | }
588 | 
589 | # Public: Summarize test results and exit with an appropriate error code.
590 | #
591 | # Must be called at the end of each test script.
592 | #
593 | # Can also be used to stop tests early and skip all remaining tests. For this,
594 | # set skip_all to a string explaining why the tests were skipped before calling
595 | # test_done.
596 | #
597 | # Examples
598 | #
599 | #   # Each test script must call test_done at the end.
600 | #   test_done
601 | #
602 | #   # Skip all remaining tests if prerequisite is not set.
603 | #   if ! test_have_prereq PERL; then
604 | #       skip_all='skipping perl interface tests, perl not available'
605 | #       test_done
606 | #   fi
607 | #
608 | # Returns 0 if all tests passed or 1 if there was a failure.
609 | # shellcheck disable=SC2154,SC2034
610 | test_done() {
611 | 	EXIT_OK=t
612 | 
613 | 	if test -z "$HARNESS_ACTIVE"; then
614 | 		test_results_dir="$SHARNESS_TEST_OUTDIR/test-results"
615 | 		mkdir -p "$test_results_dir"
616 | 		test_results_path="$test_results_dir/$this_test.$$.counts"
617 | 
618 | 		cat >>"$test_results_path" <<-EOF
619 | 		total $SHARNESS_TEST_NB
620 | 		success $test_success
621 | 		fixed $test_fixed
622 | 		broken $test_broken
623 | 		failed $test_failure
624 | 
625 | 		EOF
626 | 	fi
627 | 
628 | 	if test "$test_fixed" != 0; then
629 | 		say_color error "# $test_fixed known breakage(s) vanished; please update test(s)"
630 | 	fi
631 | 	if test "$test_broken" != 0; then
632 | 		say_color warn "# still have $test_broken known breakage(s)"
633 | 	fi
634 | 	if test "$test_broken" != 0 || test "$test_fixed" != 0; then
635 | 		test_remaining=$((SHARNESS_TEST_NB - test_broken - test_fixed))
636 | 		msg="remaining $test_remaining test(s)"
637 | 	else
638 | 		test_remaining=$SHARNESS_TEST_NB
639 | 		msg="$SHARNESS_TEST_NB test(s)"
640 | 	fi
641 | 
642 | 	case "$test_failure" in
643 | 	0)
644 | 		# Maybe print SKIP message
645 | 		check_skip_all_
646 | 		if test "$test_remaining" -gt 0; then
647 | 			say_color pass "# passed all $msg"
648 | 		fi
649 | 		say "1..$SHARNESS_TEST_NB$skip_all"
650 | 
651 | 		test_eval_ "$final_cleanup"
652 | 
653 | 		remove_trash_
654 | 
655 | 		exit 0 ;;
656 | 
657 | 	*)
658 | 		say_color error "# failed $test_failure among $msg"
659 | 		say "1..$SHARNESS_TEST_NB"
660 | 
661 | 		exit 1 ;;
662 | 
663 | 	esac
664 | }
665 | 
666 | : "${SHARNESS_BUILD_DIRECTORY:="$SHARNESS_TEST_DIRECTORY/.."}"
667 | # Public: Build directory that will be added to PATH. By default, it is set to
668 | # the parent directory of SHARNESS_TEST_DIRECTORY.
669 | export SHARNESS_BUILD_DIRECTORY
670 | PATH="$SHARNESS_BUILD_DIRECTORY:$PATH"
671 | export PATH
672 | 
673 | # Public: Path to test script currently executed.
674 | SHARNESS_TEST_FILE="$ARGZERO"
675 | export SHARNESS_TEST_FILE
676 | 
677 | # Prepare test area.
678 | SHARNESS_TRASH_DIRECTORY="trash directory.$(basename "$SHARNESS_TEST_FILE" ".$SHARNESS_TEST_EXTENSION")"
679 | test -n "$root" && SHARNESS_TRASH_DIRECTORY="$root/$SHARNESS_TRASH_DIRECTORY"
680 | case "$SHARNESS_TRASH_DIRECTORY" in
681 | /*) ;; # absolute path is good
682 |  *) SHARNESS_TRASH_DIRECTORY="$SHARNESS_TEST_OUTDIR/$SHARNESS_TRASH_DIRECTORY" ;;
683 | esac
684 | test "$debug" = "t" || remove_trash="$SHARNESS_TRASH_DIRECTORY"
685 | rm -rf "$SHARNESS_TRASH_DIRECTORY" || {
686 | 	EXIT_OK=t
687 | 	echo >&5 "FATAL: Cannot prepare test area"
688 | 	exit 1
689 | }
690 | 
691 | 
692 | #
693 | #  Load any extensions in $testdir/sharness.d/*.sh
694 | #
695 | if test -d "${SHARNESS_TEST_DIRECTORY}/sharness.d"
696 | then
697 | 	for file in "${SHARNESS_TEST_DIRECTORY}"/sharness.d/*.sh
698 | 	do
699 | 		# Ensure glob was not an empty match:
700 | 		test -e "${file}" || break
701 | 
702 | 		if test -n "$debug"
703 | 		then
704 | 			echo >&5 "sharness: loading extensions from ${file}"
705 | 		fi
706 | 		# shellcheck disable=SC1090
707 | 		. "${file}"
708 | 		if test $? != 0
709 | 		then
710 | 			echo >&5 "sharness: Error loading ${file}. Aborting."
711 | 			exit 1
712 | 		fi
713 | 	done
714 | fi
715 | 
716 | # Public: Empty trash directory, the test area, provided for each test. The HOME
717 | # variable is set to that directory too.
718 | export SHARNESS_TRASH_DIRECTORY
719 | 
720 | HOME="$SHARNESS_TRASH_DIRECTORY"
721 | export HOME
722 | 
723 | # shellcheck disable=SC3028
724 | if [ "$OSTYPE" = msys ]; then
725 | 	USERPROFILE="$SHARNESS_TRASH_DIRECTORY"
726 | 	export USERPROFILE
727 | fi
728 | 
729 | mkdir -p "$SHARNESS_TRASH_DIRECTORY" || exit 1
730 | # Use -P to resolve symlinks in our working directory so that the cwd
731 | # in subprocesses like git equals our $PWD (for pathname comparisons).
732 | cd -P "$SHARNESS_TRASH_DIRECTORY" || exit 1
733 | 
734 | check_skip_all_() {
735 | 	if test -n "$skip_all" && test $SHARNESS_TEST_NB -gt 0; then
736 | 		error "Can't use skip_all after running some tests"
737 | 	fi
738 | 	[ -z "$skip_all" ] || skip_all=" # SKIP $skip_all"
739 | }
740 | 
741 | this_test=${SHARNESS_TEST_FILE##*/}
742 | this_test=${this_test%".$SHARNESS_TEST_EXTENSION"}
743 | for skp in $SKIP_TESTS; do
744 | 	# shellcheck disable=SC2254
745 | 	case "$this_test" in
746 | 	$skp)
747 | 		say_color info >&3 "skipping test $this_test altogether"
748 | 		skip_all="skip all tests in $this_test"
749 | 		test_done
750 | 	esac
751 | done
752 | 
753 | test -n "$TEST_LONG" && test_set_prereq EXPENSIVE
754 | test -n "$TEST_INTERACTIVE" && test_set_prereq INTERACTIVE
755 | 
756 | # Make sure this script ends with code 0
757 | :
758 | 
759 | # vi: set ts=4 sw=4 noet :
760 | 


--------------------------------------------------------------------------------
/t/test-lib.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/sh
  2 | #
  3 | # Copyright (c) 2005 Junio C Hamano
  4 | #
  5 | 
  6 | . "$(dirname "$0")"/sharness.sh
  7 | 
  8 | SRC_DIR="$SHARNESS_TEST_DIRECTORY"/../src
  9 | TRASH_DIRECTORY="$SHARNESS_TRASH_DIRECTORY"
 10 | 
 11 | : "${GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME:=master}"
 12 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 13 | 
 14 | export GIT_AUTHOR_EMAIL=author@example.com
 15 | export GIT_AUTHOR_NAME='A U Thor'
 16 | export GIT_COMMITTER_EMAIL=committer@example.com
 17 | export GIT_COMMITTER_NAME='C O Mitter'
 18 | 
 19 | export LC_ALL=C
 20 | export TERM=dumb
 21 | 
 22 | unset GIT_EDITOR
 23 | 
 24 | LF='
 25 | '
 26 | 
 27 | test_cmp() {
 28 | 	diff -u "$@"
 29 | }
 30 | 
 31 | test_when_finished() {
 32 | 	test_cleanup="{ $*
 33 | 		} && (exit \"\$eval_ret\"); eval_ret=\$?; $test_cleanup"
 34 | }
 35 | 
 36 | test_must_fail() {
 37 | 	"$@"
 38 | 	exit_code=$?
 39 | 	if test $exit_code = 0; then
 40 | 		echo >&2 "test_must_fail: command succeeded: $*"
 41 | 		return 1
 42 | 	elif test $exit_code -gt 129 -a $exit_code -le 192; then
 43 | 		echo >&2 "test_must_fail: died by signal: $*"
 44 | 		return 1
 45 | 	elif test $exit_code = 127; then
 46 | 		echo >&2 "test_must_fail: command not found: $*"
 47 | 		return 1
 48 | 	fi
 49 | 	return 0
 50 | }
 51 | 
 52 | test_must_be_empty() {
 53 | 	if test -s "$1"
 54 | 	then
 55 | 		echo "'$1' is not empty, it contains:"
 56 | 		cat "$1"
 57 | 		return 1
 58 | 	fi
 59 | }
 60 | 
 61 | verbose () {
 62 | 	"$@" && return 0
 63 | 	echo >&4 "command failed: $(git rev-parse --sq-quote "$@")"
 64 | 	return 1
 65 | }
 66 | 
 67 | test_unconfig () {
 68 | 	config_dir=
 69 | 	if test "$1" = -C
 70 | 	then
 71 | 		shift
 72 | 		config_dir=$1
 73 | 		shift
 74 | 	fi
 75 | 	git ${config_dir:+-C "$config_dir"} config --unset-all "$@"
 76 | 	config_status=$?
 77 | 	case "$config_status" in
 78 | 	5) # ok, nothing to unset
 79 | 		config_status=0
 80 | 		;;
 81 | 	esac
 82 | 	return $config_status
 83 | }
 84 | 
 85 | test_config () {
 86 | 	config_dir=
 87 | 	if test "$1" = -C
 88 | 	then
 89 | 		shift
 90 | 		config_dir=$1
 91 | 		shift
 92 | 	fi
 93 | 	test_when_finished "test_unconfig ${config_dir:+-C '$config_dir'} '$1'" &&
 94 | 	git ${config_dir:+-C "$config_dir"} config "$@"
 95 | }
 96 | 
 97 | test_config_global () {
 98 | 	test_when_finished "test_unconfig --global '$1'" &&
 99 | 	git config --global "$@"
100 | }
101 | 
102 | test_tick () {
103 | 	if test -z "${test_tick+set}"
104 | 	then
105 | 		test_tick=1112911993
106 | 	else
107 | 		test_tick=$((test_tick + 60))
108 | 	fi
109 | 	GIT_COMMITTER_DATE="$test_tick -0700"
110 | 	GIT_AUTHOR_DATE="$test_tick -0700"
111 | 	export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
112 | }
113 | 
114 | write_script () {
115 | 	{
116 | 		echo "#!${2-"$SHELL_PATH"}" &&
117 | 		cat
118 | 	} >"$1" &&
119 | 	chmod +x "$1"
120 | }
121 | 
122 | test_set_editor () {
123 | 	FAKE_EDITOR="$1"
124 | 	export FAKE_EDITOR
125 | 	EDITOR='"$FAKE_EDITOR"'
126 | 	export EDITOR
127 | }
128 | 
129 | sane_unset () {
130 | 	unset "$@"
131 | 	return 0
132 | }
133 | 
134 | # We don't need the full implementation
135 | test_set_prereq() {
136 | 	:
137 | }
138 | 
139 | test_have_prereq() {
140 | 	# prerequisites can be concatenated with ','
141 | 	save_IFS=$IFS
142 | 	IFS=,
143 | 	# shellcheck disable=SC2086
144 | 	set -- $1
145 | 	IFS=$save_IFS
146 | 
147 | 	for prerequisite; do
148 | 		case "$prerequisite" in
149 | 			PERL|SYMLINKS|FUNNYNAMES|FUNNIERNAMES|!CYGWIN|!MINGW)
150 | 				;;
151 | 			*)
152 | 				return 1;
153 | 				;;
154 | 		esac
155 | 	done
156 | }
157 | 
158 | git init "$TRASH_DIRECTORY" || exit
159 | 


--------------------------------------------------------------------------------
/t/zsh/.gitignore:
--------------------------------------------------------------------------------
1 | /.zcompdump
2 | 


--------------------------------------------------------------------------------
/t/zsh/.zshrc:
--------------------------------------------------------------------------------
 1 | setopt zle
 2 | setopt list_rows_first
 3 | 
 4 | PS1=""
 5 | fpath=($ZDOTDIR "$SRC_DIR" $fpath)
 6 | LISTMAX=1000
 7 | 
 8 | autoload -U compinit && compinit -u
 9 | 
10 | zstyle ':completion:*' list-colors "no=" "fi=" "di=" "ec=\n" "rc=" "lc=" "sp="
11 | zstyle ':completion:*' verbose no
12 | 
13 | zle_complete () {
14 | 	zle list-choices
15 | 	zle kill-whole-line
16 | 	print ""
17 | }
18 | zle -N zle_complete
19 | bindkey "^I" zle_complete
20 | 
21 | functions[_default]=:
22 | 
23 | compadd () {
24 | 	local pfx sfx
25 | 	local -a args
26 | 
27 | 	if (( ${@[(I)-a|-d]} )); then
28 | 		builtin compadd -V unsorted "$@"
29 | 	else
30 | 		while (($#)); do
31 | 			case "$1" in
32 | 			-p) pfx="$2" ; shift 2 ;;
33 | 			-S) sfx="$2" ; shift 2 ;;
34 | 			--) args+=($1) ; shift ; break ;;
35 | 			*) args+=("$1") ; shift ;;
36 | 			esac
37 | 		done
38 | 
39 | 		while (($#)); do
40 | 			args+=(${pfx}$1${sfx})
41 | 			shift
42 | 		done
43 | 
44 | 		builtin compadd -V unsorted -S '' "${args[@]}"
45 | 	fi
46 | }
47 | 
48 | _git_func () {
49 | 	eval ${words[2,-2]}
50 | }
51 | 


--------------------------------------------------------------------------------
/tools/converts.json:
--------------------------------------------------------------------------------
 1 | [
 2 |   [ "src/_git", "contrib/completion/git-completion.zsh" ],
 3 |   [ "src/git-completion.bash", "contrib/completion/git-completion.bash" ],
 4 |   [ "src/git-prompt.sh", "contrib/completion/git-prompt.sh" ],
 5 |   [ "t/completion.t", "t/t9902-completion.sh" ],
 6 |   [ "t/completion-zsh.t", "t/t9904-completion-zsh.sh" ],
 7 |   [ "t/prompt.t", "t/t9903-bash-prompt.sh" ],
 8 |   [ "t/zsh/completion", "t/t9904/completion" ],
 9 |   [ "t/zsh/.zshrc", "t/t9904/.zshrc" ],
10 |   [ "t/zsh/_git", "t/t9904/_git" ],
11 |   [ "t/zsh/.gitignore", "t/t9904/.gitignore" ]
12 | ]
13 | 


--------------------------------------------------------------------------------
/tools/transplant:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/env ruby
 2 | 
 3 | require 'json'
 4 | 
 5 | $reverse = !!ARGV.delete('-r')
 6 | 
 7 | repo_a = Dir.pwd
 8 | repo_b = ARGV.shift
 9 | revset = ARGV
10 | 
11 | repo_a, repo_b = repo_b, repo_a if $reverse
12 | 
13 | $converts = JSON.parse(File.read(__dir__ + '/converts.json'))
14 | 
15 | def convert(str)
16 |   $converts.reduce(str) do |m,(a,b)|
17 |     a, b = b, a if $reverse
18 |     m.gsub(/(a|b)\/#{a}/, "\\1/#{b}").gsub(/^ #{a}/, " #{b}")
19 |   end
20 | end
21 | 
22 | IO.popen(%w[git format-patch --no-cover-letter --stdout] + revset, 'r', chdir: repo_a) do |format_patch|
23 |   IO.popen(%w[git am], 'w', chdir: repo_b) do |am|
24 |     am.write(convert(format_patch.read))
25 |   end
26 | end
27 | 


--------------------------------------------------------------------------------
/tools/update:
--------------------------------------------------------------------------------
 1 | #!/bin/sh
 2 | 
 3 | url="https://git.kernel.org/pub/scm/git/git.git/plain"
 4 | version="2.40.0"
 5 | 
 6 | git stash push -q &&
 7 | git checkout -q upstream &&
 8 | curl -s -o src/_git "${url}/contrib/completion/git-completion.zsh?h=v${version}" &&
 9 | curl -s -o src/git-completion.bash "${url}/contrib/completion/git-completion.bash?h=v${version}" &&
10 | curl -s -o src/git-prompt.sh "${url}/contrib/completion/git-prompt.sh?h=v${version}" &&
11 | curl -s -o t/completion.t "${url}/t/t9902-completion.sh?h=v${version}" &&
12 | curl -s -o t/prompt.t "${url}/t/t9903-bash-prompt.sh?h=v${version}" &&
13 | git commit -q -a -s -m "Update to upstream v${version}" &&
14 | git checkout -q - &&
15 | git stash pop -q &&
16 | echo "Updated to v${version}"
17 | 


--------------------------------------------------------------------------------