Created
April 8, 2022 13:31
-
-
Save RS-DU34/bdadadf4bd77980a68e9d1bc71b9a5af to your computer and use it in GitHub Desktop.
Bash auto-complete (SSH, git, etc)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#~/.bash_profile | |
for f in /etc/bash_completion.d/*; do source $f; done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/etc/bash_completion.d/git-prompt.sh | |
# bash/zsh git prompt support | |
# | |
# Copyright (C) 2006,2007 Shawn O. Pearce <[email protected]> | |
# Distributed under the GNU General Public License, version 2.0. | |
# | |
# This script allows you to see repository status in your prompt. | |
# | |
# To enable: | |
# | |
# 1) Copy this file to somewhere (e.g. ~/.git-prompt.sh). | |
# 2) Add the following line to your .bashrc/.zshrc: | |
# source ~/.git-prompt.sh | |
# 3a) Change your PS1 to call __git_ps1 as | |
# command-substitution: | |
# Bash: PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' | |
# ZSH: setopt PROMPT_SUBST ; PS1='[%n@%m %c$(__git_ps1 " (%s)")]\$ ' | |
# the optional argument will be used as format string. | |
# 3b) Alternatively, for a slightly faster prompt, __git_ps1 can | |
# be used for PROMPT_COMMAND in Bash or for precmd() in Zsh | |
# with two parameters, <pre> and <post>, which are strings | |
# you would put in $PS1 before and after the status string | |
# generated by the git-prompt machinery. e.g. | |
# Bash: PROMPT_COMMAND='__git_ps1 "\u@\h:\w" "\\\$ "' | |
# will show username, at-sign, host, colon, cwd, then | |
# various status string, followed by dollar and SP, as | |
# your prompt. | |
# ZSH: precmd () { __git_ps1 "%n" ":%~$ " "|%s" } | |
# will show username, pipe, then various status string, | |
# followed by colon, cwd, dollar and SP, as your prompt. | |
# Optionally, you can supply a third argument with a printf | |
# format string to finetune the output of the branch status | |
# | |
# The repository status will be displayed only if you are currently in a | |
# git repository. The %s token is the placeholder for the shown status. | |
# | |
# The prompt status always includes the current branch name. | |
# | |
# In addition, if you set GIT_PS1_SHOWDIRTYSTATE to a nonempty value, | |
# unstaged (*) and staged (+) changes will be shown next to the branch | |
# name. You can configure this per-repository with the | |
# bash.showDirtyState variable, which defaults to true once | |
# GIT_PS1_SHOWDIRTYSTATE is enabled. | |
# | |
# You can also see if currently something is stashed, by setting | |
# GIT_PS1_SHOWSTASHSTATE to a nonempty value. If something is stashed, | |
# then a '$' will be shown next to the branch name. | |
# | |
# If you would like to see if there're untracked files, then you can set | |
# GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're untracked | |
# files, then a '%' will be shown next to the branch name. You can | |
# configure this per-repository with the bash.showUntrackedFiles | |
# variable, which defaults to true once GIT_PS1_SHOWUNTRACKEDFILES is | |
# enabled. | |
# | |
# If you would like to see the difference between HEAD and its upstream, | |
# set GIT_PS1_SHOWUPSTREAM="auto". A "<" indicates you are behind, ">" | |
# indicates you are ahead, "<>" indicates you have diverged and "=" | |
# indicates that there is no difference. You can further control | |
# behaviour by setting GIT_PS1_SHOWUPSTREAM to a space-separated list | |
# of values: | |
# | |
# verbose show number of commits ahead/behind (+/-) upstream | |
# name if verbose, then also show the upstream abbrev name | |
# legacy don't use the '--count' option available in recent | |
# versions of git-rev-list | |
# git always compare HEAD to @{upstream} | |
# svn always compare HEAD to your SVN upstream | |
# | |
# You can change the separator between the branch name and the above | |
# state symbols by setting GIT_PS1_STATESEPARATOR. The default separator | |
# is SP. | |
# | |
# By default, __git_ps1 will compare HEAD to your SVN upstream if it can | |
# find one, or @{upstream} otherwise. Once you have set | |
# GIT_PS1_SHOWUPSTREAM, you can override it on a per-repository basis by | |
# setting the bash.showUpstream config variable. | |
# | |
# If you would like to see more information about the identity of | |
# commits checked out as a detached HEAD, set GIT_PS1_DESCRIBE_STYLE | |
# to one of these values: | |
# | |
# contains relative to newer annotated tag (v1.6.3.2~35) | |
# branch relative to newer tag or branch (master~4) | |
# describe relative to older annotated tag (v1.6.3.1-13-gdd42c2f) | |
# tag relative to any older tag (v1.6.3.1-13-gdd42c2f) | |
# default exactly matching tag | |
# | |
# If you would like a colored hint about the current dirty state, set | |
# GIT_PS1_SHOWCOLORHINTS to a nonempty value. The colors are based on | |
# the colored output of "git status -sb" and are available only when | |
# using __git_ps1 for PROMPT_COMMAND or precmd. | |
# | |
# If you would like __git_ps1 to do nothing in the case when the current | |
# directory is set up to be ignored by git, then set | |
# GIT_PS1_HIDE_IF_PWD_IGNORED to a nonempty value. Override this on the | |
# repository level by setting bash.hideIfPwdIgnored to "false". | |
# check whether printf supports -v | |
__git_printf_supports_v= | |
printf -v __git_printf_supports_v -- '%s' yes >/dev/null 2>&1 | |
# stores the divergence from upstream in $p | |
# used by GIT_PS1_SHOWUPSTREAM | |
__git_ps1_show_upstream () | |
{ | |
local key value | |
local svn_remote svn_url_pattern count n | |
local upstream=git legacy="" verbose="" name="" | |
svn_remote=() | |
# get some config options from git-config | |
local output="$(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ')" | |
while read -r key value; do | |
case "$key" in | |
bash.showupstream) | |
GIT_PS1_SHOWUPSTREAM="$value" | |
if [[ -z "${GIT_PS1_SHOWUPSTREAM}" ]]; then | |
p="" | |
return | |
fi | |
;; | |
svn-remote.*.url) | |
svn_remote[$((${#svn_remote[@]} + 1))]="$value" | |
svn_url_pattern="$svn_url_pattern\\|$value" | |
upstream=svn+git # default upstream is SVN if available, else git | |
;; | |
esac | |
done <<< "$output" | |
# parse configuration values | |
for option in ${GIT_PS1_SHOWUPSTREAM}; do | |
case "$option" in | |
git|svn) upstream="$option" ;; | |
verbose) verbose=1 ;; | |
legacy) legacy=1 ;; | |
name) name=1 ;; | |
esac | |
done | |
# Find our upstream | |
case "$upstream" in | |
git) upstream="@{upstream}" ;; | |
svn*) | |
# get the upstream from the "git-svn-id: ..." in a commit message | |
# (git-svn uses essentially the same procedure internally) | |
local -a svn_upstream | |
svn_upstream=($(git log --first-parent -1 \ | |
--grep="^git-svn-id: \(${svn_url_pattern#??}\)" 2>/dev/null)) | |
if [[ 0 -ne ${#svn_upstream[@]} ]]; then | |
svn_upstream=${svn_upstream[${#svn_upstream[@]} - 2]} | |
svn_upstream=${svn_upstream%@*} | |
local n_stop="${#svn_remote[@]}" | |
for ((n=1; n <= n_stop; n++)); do | |
svn_upstream=${svn_upstream#${svn_remote[$n]}} | |
done | |
if [[ -z "$svn_upstream" ]]; then | |
# default branch name for checkouts with no layout: | |
upstream=${GIT_SVN_ID:-git-svn} | |
else | |
upstream=${svn_upstream#/} | |
fi | |
elif [[ "svn+git" = "$upstream" ]]; then | |
upstream="@{upstream}" | |
fi | |
;; | |
esac | |
# Find how many commits we are ahead/behind our upstream | |
if [[ -z "$legacy" ]]; then | |
count="$(git rev-list --count --left-right \ | |
"$upstream"...HEAD 2>/dev/null)" | |
else | |
# produce equivalent output to --count for older versions of git | |
local commits | |
if commits="$(git rev-list --left-right "$upstream"...HEAD 2>/dev/null)" | |
then | |
local commit behind=0 ahead=0 | |
for commit in $commits | |
do | |
case "$commit" in | |
"<"*) ((behind++)) ;; | |
*) ((ahead++)) ;; | |
esac | |
done | |
count="$behind $ahead" | |
else | |
count="" | |
fi | |
fi | |
# calculate the result | |
if [[ -z "$verbose" ]]; then | |
case "$count" in | |
"") # no upstream | |
p="" ;; | |
"0 0") # equal to upstream | |
p="=" ;; | |
"0 "*) # ahead of upstream | |
p=">" ;; | |
*" 0") # behind upstream | |
p="<" ;; | |
*) # diverged from upstream | |
p="<>" ;; | |
esac | |
else | |
case "$count" in | |
"") # no upstream | |
p="" ;; | |
"0 0") # equal to upstream | |
p=" u=" ;; | |
"0 "*) # ahead of upstream | |
p=" u+${count#0 }" ;; | |
*" 0") # behind upstream | |
p=" u-${count% 0}" ;; | |
*) # diverged from upstream | |
p=" u+${count#* }-${count% *}" ;; | |
esac | |
if [[ -n "$count" && -n "$name" ]]; then | |
__git_ps1_upstream_name=$(git rev-parse \ | |
--abbrev-ref "$upstream" 2>/dev/null) | |
if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then | |
p="$p \${__git_ps1_upstream_name}" | |
else | |
p="$p ${__git_ps1_upstream_name}" | |
# not needed anymore; keep user's | |
# environment clean | |
unset __git_ps1_upstream_name | |
fi | |
fi | |
fi | |
} | |
# Helper function that is meant to be called from __git_ps1. It | |
# injects color codes into the appropriate gitstring variables used | |
# to build a gitstring. | |
__git_ps1_colorize_gitstring () | |
{ | |
if [[ -n ${ZSH_VERSION-} ]]; then | |
local c_red='%F{red}' | |
local c_green='%F{green}' | |
local c_lblue='%F{blue}' | |
local c_clear='%f' | |
else | |
# Using \[ and \] around colors is necessary to prevent | |
# issues with command line editing/browsing/completion! | |
local c_red='\[\e[31m\]' | |
local c_green='\[\e[32m\]' | |
local c_lblue='\[\e[1;34m\]' | |
local c_clear='\[\e[0m\]' | |
fi | |
local bad_color=$c_red | |
local ok_color=$c_green | |
local flags_color="$c_lblue" | |
local branch_color="" | |
if [ $detached = no ]; then | |
branch_color="$ok_color" | |
else | |
branch_color="$bad_color" | |
fi | |
c="$branch_color$c" | |
z="$c_clear$z" | |
if [ "$w" = "*" ]; then | |
w="$bad_color$w" | |
fi | |
if [ -n "$i" ]; then | |
i="$ok_color$i" | |
fi | |
if [ -n "$s" ]; then | |
s="$flags_color$s" | |
fi | |
if [ -n "$u" ]; then | |
u="$bad_color$u" | |
fi | |
r="$c_clear$r" | |
} | |
# Helper function to read the first line of a file into a variable. | |
# __git_eread requires 2 arguments, the file path and the name of the | |
# variable, in that order. | |
__git_eread () | |
{ | |
test -r "$1" && IFS=$'\r\n' read "$2" <"$1" | |
} | |
# see if a cherry-pick or revert is in progress, if the user has committed a | |
# conflict resolution with 'git commit' in the middle of a sequence of picks or | |
# reverts then CHERRY_PICK_HEAD/REVERT_HEAD will not exist so we have to read | |
# the todo file. | |
__git_sequencer_status () | |
{ | |
local todo | |
if test -f "$g/CHERRY_PICK_HEAD" | |
then | |
r="|CHERRY-PICKING" | |
return 0; | |
elif test -f "$g/REVERT_HEAD" | |
then | |
r="|REVERTING" | |
return 0; | |
elif __git_eread "$g/sequencer/todo" todo | |
then | |
case "$todo" in | |
p[\ \ ]|pick[\ \ ]*) | |
r="|CHERRY-PICKING" | |
return 0 | |
;; | |
revert[\ \ ]*) | |
r="|REVERTING" | |
return 0 | |
;; | |
esac | |
fi | |
return 1 | |
} | |
# __git_ps1 accepts 0 or 1 arguments (i.e., format string) | |
# when called from PS1 using command substitution | |
# in this mode it prints text to add to bash PS1 prompt (includes branch name) | |
# | |
# __git_ps1 requires 2 or 3 arguments when called from PROMPT_COMMAND (pc) | |
# in that case it _sets_ PS1. The arguments are parts of a PS1 string. | |
# when two arguments are given, the first is prepended and the second appended | |
# to the state string when assigned to PS1. | |
# The optional third parameter will be used as printf format string to further | |
# customize the output of the git-status string. | |
# In this mode you can request colored hints using GIT_PS1_SHOWCOLORHINTS=true | |
__git_ps1 () | |
{ | |
# preserve exit status | |
local exit=$? | |
local pcmode=no | |
local detached=no | |
local ps1pc_start='\u@\h:\w ' | |
local ps1pc_end='\$ ' | |
local printf_format=' (%s)' | |
case "$#" in | |
2|3) pcmode=yes | |
ps1pc_start="$1" | |
ps1pc_end="$2" | |
printf_format="${3:-$printf_format}" | |
# set PS1 to a plain prompt so that we can | |
# simply return early if the prompt should not | |
# be decorated | |
PS1="$ps1pc_start$ps1pc_end" | |
;; | |
0|1) printf_format="${1:-$printf_format}" | |
;; | |
*) return $exit | |
;; | |
esac | |
# ps1_expanded: This variable is set to 'yes' if the shell | |
# subjects the value of PS1 to parameter expansion: | |
# | |
# * bash does unless the promptvars option is disabled | |
# * zsh does not unless the PROMPT_SUBST option is set | |
# * POSIX shells always do | |
# | |
# If the shell would expand the contents of PS1 when drawing | |
# the prompt, a raw ref name must not be included in PS1. | |
# This protects the user from arbitrary code execution via | |
# specially crafted ref names. For example, a ref named | |
# 'refs/heads/$(IFS=_;cmd=sudo_rm_-rf_/;$cmd)' might cause the | |
# shell to execute 'sudo rm -rf /' when the prompt is drawn. | |
# | |
# Instead, the ref name should be placed in a separate global | |
# variable (in the __git_ps1_* namespace to avoid colliding | |
# with the user's environment) and that variable should be | |
# referenced from PS1. For example: | |
# | |
# __git_ps1_foo=$(do_something_to_get_ref_name) | |
# PS1="...stuff...\${__git_ps1_foo}...stuff..." | |
# | |
# If the shell does not expand the contents of PS1, the raw | |
# ref name must be included in PS1. | |
# | |
# The value of this variable is only relevant when in pcmode. | |
# | |
# Assume that the shell follows the POSIX specification and | |
# expands PS1 unless determined otherwise. (This is more | |
# likely to be correct if the user has a non-bash, non-zsh | |
# shell and safer than the alternative if the assumption is | |
# incorrect.) | |
# | |
local ps1_expanded=yes | |
[ -z "${ZSH_VERSION-}" ] || [[ -o PROMPT_SUBST ]] || ps1_expanded=no | |
[ -z "${BASH_VERSION-}" ] || shopt -q promptvars || ps1_expanded=no | |
local repo_info rev_parse_exit_code | |
repo_info="$(git rev-parse --git-dir --is-inside-git-dir \ | |
--is-bare-repository --is-inside-work-tree \ | |
--short HEAD 2>/dev/null)" | |
rev_parse_exit_code="$?" | |
if [ -z "$repo_info" ]; then | |
return $exit | |
fi | |
local short_sha="" | |
if [ "$rev_parse_exit_code" = "0" ]; then | |
short_sha="${repo_info##*$'\n'}" | |
repo_info="${repo_info%$'\n'*}" | |
fi | |
local inside_worktree="${repo_info##*$'\n'}" | |
repo_info="${repo_info%$'\n'*}" | |
local bare_repo="${repo_info##*$'\n'}" | |
repo_info="${repo_info%$'\n'*}" | |
local inside_gitdir="${repo_info##*$'\n'}" | |
local g="${repo_info%$'\n'*}" | |
if [ "true" = "$inside_worktree" ] && | |
[ -n "${GIT_PS1_HIDE_IF_PWD_IGNORED-}" ] && | |
[ "$(git config --bool bash.hideIfPwdIgnored)" != "false" ] && | |
git check-ignore -q . | |
then | |
return $exit | |
fi | |
local r="" | |
local b="" | |
local step="" | |
local total="" | |
if [ -d "$g/rebase-merge" ]; then | |
__git_eread "$g/rebase-merge/head-name" b | |
__git_eread "$g/rebase-merge/msgnum" step | |
__git_eread "$g/rebase-merge/end" total | |
r="|REBASE" | |
else | |
if [ -d "$g/rebase-apply" ]; then | |
__git_eread "$g/rebase-apply/next" step | |
__git_eread "$g/rebase-apply/last" total | |
if [ -f "$g/rebase-apply/rebasing" ]; then | |
__git_eread "$g/rebase-apply/head-name" b | |
r="|REBASE" | |
elif [ -f "$g/rebase-apply/applying" ]; then | |
r="|AM" | |
else | |
r="|AM/REBASE" | |
fi | |
elif [ -f "$g/MERGE_HEAD" ]; then | |
r="|MERGING" | |
elif __git_sequencer_status; then | |
: | |
elif [ -f "$g/BISECT_LOG" ]; then | |
r="|BISECTING" | |
fi | |
if [ -n "$b" ]; then | |
: | |
elif [ -h "$g/HEAD" ]; then | |
# symlink symbolic ref | |
b="$(git symbolic-ref HEAD 2>/dev/null)" | |
else | |
local head="" | |
if ! __git_eread "$g/HEAD" head; then | |
return $exit | |
fi | |
# is it a symbolic ref? | |
b="${head#ref: }" | |
if [ "$head" = "$b" ]; then | |
detached=yes | |
b="$( | |
case "${GIT_PS1_DESCRIBE_STYLE-}" in | |
(contains) | |
git describe --contains HEAD ;; | |
(branch) | |
git describe --contains --all HEAD ;; | |
(tag) | |
git describe --tags HEAD ;; | |
(describe) | |
git describe HEAD ;; | |
(* | default) | |
git describe --tags --exact-match HEAD ;; | |
esac 2>/dev/null)" || | |
b="$short_sha..." | |
b="($b)" | |
fi | |
fi | |
fi | |
if [ -n "$step" ] && [ -n "$total" ]; then | |
r="$r $step/$total" | |
fi | |
local w="" | |
local i="" | |
local s="" | |
local u="" | |
local c="" | |
local p="" | |
if [ "true" = "$inside_gitdir" ]; then | |
if [ "true" = "$bare_repo" ]; then | |
c="BARE:" | |
else | |
b="GIT_DIR!" | |
fi | |
elif [ "true" = "$inside_worktree" ]; then | |
if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ] && | |
[ "$(git config --bool bash.showDirtyState)" != "false" ] | |
then | |
git diff --no-ext-diff --quiet || w="*" | |
git diff --no-ext-diff --cached --quiet || i="+" | |
if [ -z "$short_sha" ] && [ -z "$i" ]; then | |
i="#" | |
fi | |
fi | |
if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ] && | |
git rev-parse --verify --quiet refs/stash >/dev/null | |
then | |
s="$" | |
fi | |
if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ] && | |
[ "$(git config --bool bash.showUntrackedFiles)" != "false" ] && | |
git ls-files --others --exclude-standard --directory --no-empty-directory --error-unmatch -- ':/*' >/dev/null 2>/dev/null | |
then | |
u="%${ZSH_VERSION+%}" | |
fi | |
if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then | |
__git_ps1_show_upstream | |
fi | |
fi | |
local z="${GIT_PS1_STATESEPARATOR-" "}" | |
# NO color option unless in PROMPT_COMMAND mode | |
if [ $pcmode = yes ] && [ -n "${GIT_PS1_SHOWCOLORHINTS-}" ]; then | |
__git_ps1_colorize_gitstring | |
fi | |
b=${b##refs/heads/} | |
if [ $pcmode = yes ] && [ $ps1_expanded = yes ]; then | |
__git_ps1_branch_name=$b | |
b="\${__git_ps1_branch_name}" | |
fi | |
local f="$w$i$s$u" | |
local gitstring="$c$b${f:+$z$f}$r$p" | |
if [ $pcmode = yes ]; then | |
if [ "${__git_printf_supports_v-}" != yes ]; then | |
gitstring=$(printf -- "$printf_format" "$gitstring") | |
else | |
printf -v gitstring -- "$printf_format" "$gitstring" | |
fi | |
PS1="$ps1pc_start$gitstring$ps1pc_end" | |
else | |
printf -- "$printf_format" "$gitstring" | |
fi | |
return $exit | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/etc/bash_completion.d/git.sh | |
# bash/zsh completion support for core Git. | |
# | |
# Copyright (C) 2006,2007 Shawn O. Pearce <[email protected]> | |
# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/). | |
# Distributed under the GNU General Public License, version 2.0. | |
# | |
# The contained completion routines provide support for completing: | |
# | |
# *) local and remote branch names | |
# *) local and remote tag names | |
# *) .git/remotes file names | |
# *) git 'subcommands' | |
# *) git email aliases for git-send-email | |
# *) tree paths within 'ref:path/to/file' expressions | |
# *) file paths within current working directory and index | |
# *) common --long-options | |
# | |
# To use these routines: | |
# | |
# 1) Copy this file to somewhere (e.g. ~/.git-completion.bash). | |
# 2) Add the following line to your .bashrc/.zshrc: | |
# source ~/.git-completion.bash | |
# 3) Consider changing your PS1 to also show the current branch, | |
# see git-prompt.sh for details. | |
# | |
# If you use complex aliases of form '!f() { ... }; f', you can use the null | |
# command ':' as the first command in the function body to declare the desired | |
# completion style. For example '!f() { : git commit ; ... }; f' will | |
# tell the completion to use commit completion. This also works with aliases | |
# of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '". | |
# | |
# Compatible with bash 3.2.57. | |
# | |
# You can set the following environment variables to influence the behavior of | |
# the completion routines: | |
# | |
# GIT_COMPLETION_CHECKOUT_NO_GUESS | |
# | |
# When set to "1", do not include "DWIM" suggestions in git-checkout | |
# and git-switch completion (e.g., completing "foo" when "origin/foo" | |
# exists). | |
# SUSE-specific: We trust the system is consistent and do not let individual | |
# scripts play ping-pong with the global $COMP_WORDBREAKS value. | |
#case "$COMP_WORDBREAKS" in | |
#*:*) : great ;; | |
#*) COMP_WORDBREAKS="$COMP_WORDBREAKS:" | |
#esac | |
# Discovers the path to the git repository taking any '--git-dir=<path>' and | |
# '-C <path>' options into account and stores it in the $__git_repo_path | |
# variable. | |
__git_find_repo_path () | |
{ | |
if [ -n "$__git_repo_path" ]; then | |
# we already know where it is | |
return | |
fi | |
if [ -n "${__git_C_args-}" ]; then | |
__git_repo_path="$(git "${__git_C_args[@]}" \ | |
${__git_dir:+--git-dir="$__git_dir"} \ | |
rev-parse --absolute-git-dir 2>/dev/null)" | |
elif [ -n "${__git_dir-}" ]; then | |
test -d "$__git_dir" && | |
__git_repo_path="$__git_dir" | |
elif [ -n "${GIT_DIR-}" ]; then | |
test -d "${GIT_DIR-}" && | |
__git_repo_path="$GIT_DIR" | |
elif [ -d .git ]; then | |
__git_repo_path=.git | |
else | |
__git_repo_path="$(git rev-parse --git-dir 2>/dev/null)" | |
fi | |
} | |
# Deprecated: use __git_find_repo_path() and $__git_repo_path instead | |
# __gitdir accepts 0 or 1 arguments (i.e., location) | |
# returns location of .git repo | |
__gitdir () | |
{ | |
if [ -z "${1-}" ]; then | |
__git_find_repo_path || return 1 | |
echo "$__git_repo_path" | |
elif [ -d "$1/.git" ]; then | |
echo "$1/.git" | |
else | |
echo "$1" | |
fi | |
} | |
# Runs git with all the options given as argument, respecting any | |
# '--git-dir=<path>' and '-C <path>' options present on the command line | |
__git () | |
{ | |
git ${__git_C_args:+"${__git_C_args[@]}"} \ | |
${__git_dir:+--git-dir="$__git_dir"} "$@" 2>/dev/null | |
} | |
# Removes backslash escaping, single quotes and double quotes from a word, | |
# stores the result in the variable $dequoted_word. | |
# 1: The word to dequote. | |
__git_dequote () | |
{ | |
local rest="$1" len ch | |
dequoted_word="" | |
while test -n "$rest"; do | |
len=${#dequoted_word} | |
dequoted_word="$dequoted_word${rest%%[\\\'\"]*}" | |
rest="${rest:$((${#dequoted_word}-$len))}" | |
case "${rest:0:1}" in | |
\\) | |
ch="${rest:1:1}" | |
case "$ch" in | |
$'\n') | |
;; | |
*) | |
dequoted_word="$dequoted_word$ch" | |
;; | |
esac | |
rest="${rest:2}" | |
;; | |
\') | |
rest="${rest:1}" | |
len=${#dequoted_word} | |
dequoted_word="$dequoted_word${rest%%\'*}" | |
rest="${rest:$((${#dequoted_word}-$len+1))}" | |
;; | |
\") | |
rest="${rest:1}" | |
while test -n "$rest" ; do | |
len=${#dequoted_word} | |
dequoted_word="$dequoted_word${rest%%[\\\"]*}" | |
rest="${rest:$((${#dequoted_word}-$len))}" | |
case "${rest:0:1}" in | |
\\) | |
ch="${rest:1:1}" | |
case "$ch" in | |
\"|\\|\$|\`) | |
dequoted_word="$dequoted_word$ch" | |
;; | |
$'\n') | |
;; | |
*) | |
dequoted_word="$dequoted_word\\$ch" | |
;; | |
esac | |
rest="${rest:2}" | |
;; | |
\") | |
rest="${rest:1}" | |
break | |
;; | |
esac | |
done | |
;; | |
esac | |
done | |
} | |
# The following function is based on code from: | |
# | |
# bash_completion - programmable completion functions for bash 3.2+ | |
# | |
# Copyright © 2006-2008, Ian Macdonald <[email protected]> | |
# © 2009-2010, Bash Completion Maintainers | |
# <[email protected]> | |
# | |
# This program is free software; you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation; either version 2, or (at your option) | |
# any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program; if not, see <http://www.gnu.org/licenses/>. | |
# | |
# The latest version of this software can be obtained here: | |
# | |
# http://bash-completion.alioth.debian.org/ | |
# | |
# RELEASE: 2.x | |
# This function can be used to access a tokenized list of words | |
# on the command line: | |
# | |
# __git_reassemble_comp_words_by_ref '=:' | |
# if test "${words_[cword_-1]}" = -w | |
# then | |
# ... | |
# fi | |
# | |
# The argument should be a collection of characters from the list of | |
# word completion separators (COMP_WORDBREAKS) to treat as ordinary | |
# characters. | |
# | |
# This is roughly equivalent to going back in time and setting | |
# COMP_WORDBREAKS to exclude those characters. The intent is to | |
# make option types like --date=<type> and <rev>:<path> easy to | |
# recognize by treating each shell word as a single token. | |
# | |
# It is best not to set COMP_WORDBREAKS directly because the value is | |
# shared with other completion scripts. By the time the completion | |
# function gets called, COMP_WORDS has already been populated so local | |
# changes to COMP_WORDBREAKS have no effect. | |
# | |
# Output: words_, cword_, cur_. | |
__git_reassemble_comp_words_by_ref() | |
{ | |
local exclude i j first | |
# Which word separators to exclude? | |
exclude="${1//[^$COMP_WORDBREAKS]}" | |
cword_=$COMP_CWORD | |
if [ -z "$exclude" ]; then | |
words_=("${COMP_WORDS[@]}") | |
return | |
fi | |
# List of word completion separators has shrunk; | |
# re-assemble words to complete. | |
for ((i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do | |
# Append each nonempty word consisting of just | |
# word separator characters to the current word. | |
first=t | |
while | |
[ $i -gt 0 ] && | |
[ -n "${COMP_WORDS[$i]}" ] && | |
# word consists of excluded word separators | |
[ "${COMP_WORDS[$i]//[^$exclude]}" = "${COMP_WORDS[$i]}" ] | |
do | |
# Attach to the previous token, | |
# unless the previous token is the command name. | |
if [ $j -ge 2 ] && [ -n "$first" ]; then | |
((j--)) | |
fi | |
first= | |
words_[$j]=${words_[j]}${COMP_WORDS[i]} | |
if [ $i = $COMP_CWORD ]; then | |
cword_=$j | |
fi | |
if (($i < ${#COMP_WORDS[@]} - 1)); then | |
((i++)) | |
else | |
# Done. | |
return | |
fi | |
done | |
words_[$j]=${words_[j]}${COMP_WORDS[i]} | |
if [ $i = $COMP_CWORD ]; then | |
cword_=$j | |
fi | |
done | |
} | |
if ! type _get_comp_words_by_ref >/dev/null 2>&1; then | |
_get_comp_words_by_ref () | |
{ | |
local exclude cur_ words_ cword_ | |
if [ "$1" = "-n" ]; then | |
exclude=$2 | |
shift 2 | |
fi | |
__git_reassemble_comp_words_by_ref "$exclude" | |
cur_=${words_[cword_]} | |
while [ $# -gt 0 ]; do | |
case "$1" in | |
cur) | |
cur=$cur_ | |
;; | |
prev) | |
prev=${words_[$cword_-1]} | |
;; | |
words) | |
words=("${words_[@]}") | |
;; | |
cword) | |
cword=$cword_ | |
;; | |
esac | |
shift | |
done | |
} | |
fi | |
# Fills the COMPREPLY array with prefiltered words without any additional | |
# processing. | |
# Callers must take care of providing only words that match the current word | |
# to be completed and adding any prefix and/or suffix (trailing space!), if | |
# necessary. | |
# 1: List of newline-separated matching completion words, complete with | |
# prefix and suffix. | |
__gitcomp_direct () | |
{ | |
local IFS=$'\n' | |
COMPREPLY=($1) | |
} | |
__gitcompappend () | |
{ | |
local x i=${#COMPREPLY[@]} | |
for x in $1; do | |
if [[ "$x" == "$3"* ]]; then | |
COMPREPLY[i++]="$2$x$4" | |
fi | |
done | |
} | |
__gitcompadd () | |
{ | |
COMPREPLY=() | |
__gitcompappend "$@" | |
} | |
# Generates completion reply, appending a space to possible completion words, | |
# if necessary. | |
# It accepts 1 to 4 arguments: | |
# 1: List of possible completion words. | |
# 2: A prefix to be added to each possible completion word (optional). | |
# 3: Generate possible completion matches for this word (optional). | |
# 4: A suffix to be appended to each possible completion word (optional). | |
__gitcomp () | |
{ | |
local cur_="${3-$cur}" | |
case "$cur_" in | |
--*=) | |
;; | |
--no-*) | |
local c i=0 IFS=$' \t\n' | |
for c in $1; do | |
if [[ $c == "--" ]]; then | |
continue | |
fi | |
c="$c${4-}" | |
if [[ $c == "$cur_"* ]]; then | |
case $c in | |
--*=|*.) ;; | |
*) c="$c " ;; | |
esac | |
COMPREPLY[i++]="${2-}$c" | |
fi | |
done | |
;; | |
*) | |
local c i=0 IFS=$' \t\n' | |
for c in $1; do | |
if [[ $c == "--" ]]; then | |
c="--no-...${4-}" | |
if [[ $c == "$cur_"* ]]; then | |
COMPREPLY[i++]="${2-}$c " | |
fi | |
break | |
fi | |
c="$c${4-}" | |
if [[ $c == "$cur_"* ]]; then | |
case $c in | |
*=|*.) ;; | |
*) c="$c " ;; | |
esac | |
COMPREPLY[i++]="${2-}$c" | |
fi | |
done | |
;; | |
esac | |
} | |
# Clear the variables caching builtins' options when (re-)sourcing | |
# the completion script. | |
if [[ -n ${ZSH_VERSION-} ]]; then | |
unset $(set |sed -ne 's/^\(__gitcomp_builtin_[a-zA-Z0-9_][a-zA-Z0-9_]*\)=.*/\1/p') 2>/dev/null | |
else | |
unset $(compgen -v __gitcomp_builtin_) | |
fi | |
# This function is equivalent to | |
# | |
# __gitcomp "$(git xxx --git-completion-helper) ..." | |
# | |
# except that the output is cached. Accept 1-3 arguments: | |
# 1: the git command to execute, this is also the cache key | |
# 2: extra options to be added on top (e.g. negative forms) | |
# 3: options to be excluded | |
__gitcomp_builtin () | |
{ | |
# spaces must be replaced with underscore for multi-word | |
# commands, e.g. "git remote add" becomes remote_add. | |
local cmd="$1" | |
local incl="$2" | |
local excl="$3" | |
local var=__gitcomp_builtin_"${cmd/-/_}" | |
local options | |
eval "options=\$$var" | |
if [ -z "$options" ]; then | |
# leading and trailing spaces are significant to make | |
# option removal work correctly. | |
options=" $incl $(__git ${cmd/_/ } --git-completion-helper) " || return | |
for i in $excl; do | |
options="${options/ $i / }" | |
done | |
eval "$var=\"$options\"" | |
fi | |
__gitcomp "$options" | |
} | |
# Variation of __gitcomp_nl () that appends to the existing list of | |
# completion candidates, COMPREPLY. | |
__gitcomp_nl_append () | |
{ | |
local IFS=$'\n' | |
__gitcompappend "$1" "${2-}" "${3-$cur}" "${4- }" | |
} | |
# Generates completion reply from newline-separated possible completion words | |
# by appending a space to all of them. | |
# It accepts 1 to 4 arguments: | |
# 1: List of possible completion words, separated by a single newline. | |
# 2: A prefix to be added to each possible completion word (optional). | |
# 3: Generate possible completion matches for this word (optional). | |
# 4: A suffix to be appended to each possible completion word instead of | |
# the default space (optional). If specified but empty, nothing is | |
# appended. | |
__gitcomp_nl () | |
{ | |
COMPREPLY=() | |
__gitcomp_nl_append "$@" | |
} | |
# Fills the COMPREPLY array with prefiltered paths without any additional | |
# processing. | |
# Callers must take care of providing only paths that match the current path | |
# to be completed and adding any prefix path components, if necessary. | |
# 1: List of newline-separated matching paths, complete with all prefix | |
# path components. | |
__gitcomp_file_direct () | |
{ | |
local IFS=$'\n' | |
COMPREPLY=($1) | |
# use a hack to enable file mode in bash < 4 | |
compopt -o filenames +o nospace 2>/dev/null || | |
compgen -f /non-existing-dir/ >/dev/null || | |
true | |
} | |
# Generates completion reply with compgen from newline-separated possible | |
# completion filenames. | |
# It accepts 1 to 3 arguments: | |
# 1: List of possible completion filenames, separated by a single newline. | |
# 2: A directory prefix to be added to each possible completion filename | |
# (optional). | |
# 3: Generate possible completion matches for this word (optional). | |
__gitcomp_file () | |
{ | |
local IFS=$'\n' | |
# XXX does not work when the directory prefix contains a tilde, | |
# since tilde expansion is not applied. | |
# This means that COMPREPLY will be empty and Bash default | |
# completion will be used. | |
__gitcompadd "$1" "${2-}" "${3-$cur}" "" | |
# use a hack to enable file mode in bash < 4 | |
compopt -o filenames +o nospace 2>/dev/null || | |
compgen -f /non-existing-dir/ >/dev/null || | |
true | |
} | |
# Execute 'git ls-files', unless the --committable option is specified, in | |
# which case it runs 'git diff-index' to find out the files that can be | |
# committed. It return paths relative to the directory specified in the first | |
# argument, and using the options specified in the second argument. | |
__git_ls_files_helper () | |
{ | |
if [ "$2" == "--committable" ]; then | |
__git -C "$1" -c core.quotePath=false diff-index \ | |
--name-only --relative HEAD -- "${3//\\/\\\\}*" | |
else | |
# NOTE: $2 is not quoted in order to support multiple options | |
__git -C "$1" -c core.quotePath=false ls-files \ | |
--exclude-standard $2 -- "${3//\\/\\\\}*" | |
fi | |
} | |
# __git_index_files accepts 1 or 2 arguments: | |
# 1: Options to pass to ls-files (required). | |
# 2: A directory path (optional). | |
# If provided, only files within the specified directory are listed. | |
# Sub directories are never recursed. Path must have a trailing | |
# slash. | |
# 3: List only paths matching this path component (optional). | |
__git_index_files () | |
{ | |
local root="$2" match="$3" | |
__git_ls_files_helper "$root" "$1" "$match" | | |
awk -F / -v pfx="${2//\\/\\\\}" '{ | |
paths[$1] = 1 | |
} | |
END { | |
for (p in paths) { | |
if (substr(p, 1, 1) != "\"") { | |
# No special characters, easy! | |
print pfx p | |
continue | |
} | |
# The path is quoted. | |
p = dequote(p) | |
if (p == "") | |
continue | |
# Even when a directory name itself does not contain | |
# any special characters, it will still be quoted if | |
# any of its (stripped) trailing path components do. | |
# Because of this we may have seen the same directory | |
# both quoted and unquoted. | |
if (p in paths) | |
# We have seen the same directory unquoted, | |
# skip it. | |
continue | |
else | |
print pfx p | |
} | |
} | |
function dequote(p, bs_idx, out, esc, esc_idx, dec) { | |
# Skip opening double quote. | |
p = substr(p, 2) | |
# Interpret backslash escape sequences. | |
while ((bs_idx = index(p, "\\")) != 0) { | |
out = out substr(p, 1, bs_idx - 1) | |
esc = substr(p, bs_idx + 1, 1) | |
p = substr(p, bs_idx + 2) | |
if ((esc_idx = index("abtvfr\"\\", esc)) != 0) { | |
# C-style one-character escape sequence. | |
out = out substr("\a\b\t\v\f\r\"\\", | |
esc_idx, 1) | |
} else if (esc == "n") { | |
# Uh-oh, a newline character. | |
# We cannot reliably put a pathname | |
# containing a newline into COMPREPLY, | |
# and the newline would create a mess. | |
# Skip this path. | |
return "" | |
} else { | |
# Must be a \nnn octal value, then. | |
dec = esc * 64 + \ | |
substr(p, 1, 1) * 8 + \ | |
substr(p, 2, 1) | |
out = out sprintf("%c", dec) | |
p = substr(p, 3) | |
} | |
} | |
# Drop closing double quote, if there is one. | |
# (There is not any if this is a directory, as it was | |
# already stripped with the trailing path components.) | |
if (substr(p, length(p), 1) == "\"") | |
out = out substr(p, 1, length(p) - 1) | |
else | |
out = out p | |
return out | |
}' | |
} | |
# __git_complete_index_file requires 1 argument: | |
# 1: the options to pass to ls-file | |
# | |
# The exception is --committable, which finds the files appropriate commit. | |
__git_complete_index_file () | |
{ | |
local dequoted_word pfx="" cur_ | |
__git_dequote "$cur" | |
case "$dequoted_word" in | |
?*/*) | |
pfx="${dequoted_word%/*}/" | |
cur_="${dequoted_word##*/}" | |
;; | |
*) | |
cur_="$dequoted_word" | |
esac | |
__gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")" | |
} | |
# Lists branches from the local repository. | |
# 1: A prefix to be added to each listed branch (optional). | |
# 2: List only branches matching this word (optional; list all branches if | |
# unset or empty). | |
# 3: A suffix to be appended to each listed branch (optional). | |
__git_heads () | |
{ | |
local pfx="${1-}" cur_="${2-}" sfx="${3-}" | |
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ | |
"refs/heads/$cur_*" "refs/heads/$cur_*/**" | |
} | |
# Lists tags from the local repository. | |
# Accepts the same positional parameters as __git_heads() above. | |
__git_tags () | |
{ | |
local pfx="${1-}" cur_="${2-}" sfx="${3-}" | |
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ | |
"refs/tags/$cur_*" "refs/tags/$cur_*/**" | |
} | |
# Lists refs from the local (by default) or from a remote repository. | |
# It accepts 0, 1 or 2 arguments: | |
# 1: The remote to list refs from (optional; ignored, if set but empty). | |
# Can be the name of a configured remote, a path, or a URL. | |
# 2: In addition to local refs, list unique branches from refs/remotes/ for | |
# 'git checkout's tracking DWIMery (optional; ignored, if set but empty). | |
# 3: A prefix to be added to each listed ref (optional). | |
# 4: List only refs matching this word (optional; list all refs if unset or | |
# empty). | |
# 5: A suffix to be appended to each listed ref (optional; ignored, if set | |
# but empty). | |
# | |
# Use __git_complete_refs() instead. | |
__git_refs () | |
{ | |
local i hash dir track="${2-}" | |
local list_refs_from=path remote="${1-}" | |
local format refs | |
local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}" | |
local match="${4-}" | |
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers | |
__git_find_repo_path | |
dir="$__git_repo_path" | |
if [ -z "$remote" ]; then | |
if [ -z "$dir" ]; then | |
return | |
fi | |
else | |
if __git_is_configured_remote "$remote"; then | |
# configured remote takes precedence over a | |
# local directory with the same name | |
list_refs_from=remote | |
elif [ -d "$remote/.git" ]; then | |
dir="$remote/.git" | |
elif [ -d "$remote" ]; then | |
dir="$remote" | |
else | |
list_refs_from=url | |
fi | |
fi | |
if [ "$list_refs_from" = path ]; then | |
if [[ "$cur_" == ^* ]]; then | |
pfx="$pfx^" | |
fer_pfx="$fer_pfx^" | |
cur_=${cur_#^} | |
match=${match#^} | |
fi | |
case "$cur_" in | |
refs|refs/*) | |
format="refname" | |
refs=("$match*" "$match*/**") | |
track="" | |
;; | |
*) | |
for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD; do | |
case "$i" in | |
$match*) | |
if [ -e "$dir/$i" ]; then | |
echo "$pfx$i$sfx" | |
fi | |
;; | |
esac | |
done | |
format="refname:strip=2" | |
refs=("refs/tags/$match*" "refs/tags/$match*/**" | |
"refs/heads/$match*" "refs/heads/$match*/**" | |
"refs/remotes/$match*" "refs/remotes/$match*/**") | |
;; | |
esac | |
__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \ | |
"${refs[@]}" | |
if [ -n "$track" ]; then | |
# employ the heuristic used by git checkout | |
# Try to find a remote branch that matches the completion word | |
# but only output if the branch name is unique | |
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ | |
--sort="refname:strip=3" \ | |
"refs/remotes/*/$match*" "refs/remotes/*/$match*/**" | \ | |
uniq -u | |
fi | |
return | |
fi | |
case "$cur_" in | |
refs|refs/*) | |
__git ls-remote "$remote" "$match*" | \ | |
while read -r hash i; do | |
case "$i" in | |
*^{}) ;; | |
*) echo "$pfx$i$sfx" ;; | |
esac | |
done | |
;; | |
*) | |
if [ "$list_refs_from" = remote ]; then | |
case "HEAD" in | |
$match*) echo "${pfx}HEAD$sfx" ;; | |
esac | |
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ | |
"refs/remotes/$remote/$match*" \ | |
"refs/remotes/$remote/$match*/**" | |
else | |
local query_symref | |
case "HEAD" in | |
$match*) query_symref="HEAD" ;; | |
esac | |
__git ls-remote "$remote" $query_symref \ | |
"refs/tags/$match*" "refs/heads/$match*" \ | |
"refs/remotes/$match*" | | |
while read -r hash i; do | |
case "$i" in | |
*^{}) ;; | |
refs/*) echo "$pfx${i#refs/*/}$sfx" ;; | |
*) echo "$pfx$i$sfx" ;; # symbolic refs | |
esac | |
done | |
fi | |
;; | |
esac | |
} | |
# Completes refs, short and long, local and remote, symbolic and pseudo. | |
# | |
# Usage: __git_complete_refs [<option>]... | |
# --remote=<remote>: The remote to list refs from, can be the name of a | |
# configured remote, a path, or a URL. | |
# --track: List unique remote branches for 'git checkout's tracking DWIMery. | |
# --pfx=<prefix>: A prefix to be added to each ref. | |
# --cur=<word>: The current ref to be completed. Defaults to the current | |
# word to be completed. | |
# --sfx=<suffix>: A suffix to be appended to each ref instead of the default | |
# space. | |
__git_complete_refs () | |
{ | |
local remote track pfx cur_="$cur" sfx=" " | |
while test $# != 0; do | |
case "$1" in | |
--remote=*) remote="${1##--remote=}" ;; | |
--track) track="yes" ;; | |
--pfx=*) pfx="${1##--pfx=}" ;; | |
--cur=*) cur_="${1##--cur=}" ;; | |
--sfx=*) sfx="${1##--sfx=}" ;; | |
*) return 1 ;; | |
esac | |
shift | |
done | |
__gitcomp_direct "$(__git_refs "$remote" "$track" "$pfx" "$cur_" "$sfx")" | |
} | |
# __git_refs2 requires 1 argument (to pass to __git_refs) | |
# Deprecated: use __git_complete_fetch_refspecs() instead. | |
__git_refs2 () | |
{ | |
local i | |
for i in $(__git_refs "$1"); do | |
echo "$i:$i" | |
done | |
} | |
# Completes refspecs for fetching from a remote repository. | |
# 1: The remote repository. | |
# 2: A prefix to be added to each listed refspec (optional). | |
# 3: The ref to be completed as a refspec instead of the current word to be | |
# completed (optional) | |
# 4: A suffix to be appended to each listed refspec instead of the default | |
# space (optional). | |
__git_complete_fetch_refspecs () | |
{ | |
local i remote="$1" pfx="${2-}" cur_="${3-$cur}" sfx="${4- }" | |
__gitcomp_direct "$( | |
for i in $(__git_refs "$remote" "" "" "$cur_") ; do | |
echo "$pfx$i:$i$sfx" | |
done | |
)" | |
} | |
# __git_refs_remotes requires 1 argument (to pass to ls-remote) | |
__git_refs_remotes () | |
{ | |
local i hash | |
__git ls-remote "$1" 'refs/heads/*' | \ | |
while read -r hash i; do | |
echo "$i:refs/remotes/$1/${i#refs/heads/}" | |
done | |
} | |
__git_remotes () | |
{ | |
__git_find_repo_path | |
test -d "$__git_repo_path/remotes" && ls -1 "$__git_repo_path/remotes" | |
__git remote | |
} | |
# Returns true if $1 matches the name of a configured remote, false otherwise. | |
__git_is_configured_remote () | |
{ | |
local remote | |
for remote in $(__git_remotes); do | |
if [ "$remote" = "$1" ]; then | |
return 0 | |
fi | |
done | |
return 1 | |
} | |
__git_list_merge_strategies () | |
{ | |
LANG=C LC_ALL=C git merge -s help 2>&1 | | |
sed -n -e '/[Aa]vailable strategies are: /,/^$/{ | |
s/\.$// | |
s/.*:// | |
s/^[ ]*// | |
s/[ ]*$// | |
p | |
}' | |
} | |
__git_merge_strategies= | |
# 'git merge -s help' (and thus detection of the merge strategy | |
# list) fails, unfortunately, if run outside of any git working | |
# tree. __git_merge_strategies is set to the empty string in | |
# that case, and the detection will be repeated the next time it | |
# is needed. | |
__git_compute_merge_strategies () | |
{ | |
test -n "$__git_merge_strategies" || | |
__git_merge_strategies=$(__git_list_merge_strategies) | |
} | |
__git_merge_strategy_options="ours theirs subtree subtree= patience | |
histogram diff-algorithm= ignore-space-change ignore-all-space | |
ignore-space-at-eol renormalize no-renormalize no-renames | |
find-renames find-renames= rename-threshold=" | |
__git_complete_revlist_file () | |
{ | |
local dequoted_word pfx ls ref cur_="$cur" | |
case "$cur_" in | |
*..?*:*) | |
return | |
;; | |
?*:*) | |
ref="${cur_%%:*}" | |
cur_="${cur_#*:}" | |
__git_dequote "$cur_" | |
case "$dequoted_word" in | |
?*/*) | |
pfx="${dequoted_word%/*}" | |
cur_="${dequoted_word##*/}" | |
ls="$ref:$pfx" | |
pfx="$pfx/" | |
;; | |
*) | |
cur_="$dequoted_word" | |
ls="$ref" | |
;; | |
esac | |
case "$COMP_WORDBREAKS" in | |
*:*) : great ;; | |
*) pfx="$ref:$pfx" ;; | |
esac | |
__gitcomp_file "$(__git ls-tree "$ls" \ | |
| sed 's/^.* // | |
s/$//')" \ | |
"$pfx" "$cur_" | |
;; | |
*...*) | |
pfx="${cur_%...*}..." | |
cur_="${cur_#*...}" | |
__git_complete_refs --pfx="$pfx" --cur="$cur_" | |
;; | |
*..*) | |
pfx="${cur_%..*}.." | |
cur_="${cur_#*..}" | |
__git_complete_refs --pfx="$pfx" --cur="$cur_" | |
;; | |
*) | |
__git_complete_refs | |
;; | |
esac | |
} | |
__git_complete_file () | |
{ | |
__git_complete_revlist_file | |
} | |
__git_complete_revlist () | |
{ | |
__git_complete_revlist_file | |
} | |
__git_complete_remote_or_refspec () | |
{ | |
local cur_="$cur" cmd="${words[1]}" | |
local i c=2 remote="" pfx="" lhs=1 no_complete_refspec=0 | |
if [ "$cmd" = "remote" ]; then | |
((c++)) | |
fi | |
while [ $c -lt $cword ]; do | |
i="${words[c]}" | |
case "$i" in | |
--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;; | |
-d|--delete) [ "$cmd" = "push" ] && lhs=0 ;; | |
--all) | |
case "$cmd" in | |
push) no_complete_refspec=1 ;; | |
fetch) | |
return | |
;; | |
*) ;; | |
esac | |
;; | |
--multiple) no_complete_refspec=1; break ;; | |
-*) ;; | |
*) remote="$i"; break ;; | |
esac | |
((c++)) | |
done | |
if [ -z "$remote" ]; then | |
__gitcomp_nl "$(__git_remotes)" | |
return | |
fi | |
if [ $no_complete_refspec = 1 ]; then | |
return | |
fi | |
[ "$remote" = "." ] && remote= | |
case "$cur_" in | |
*:*) | |
case "$COMP_WORDBREAKS" in | |
*:*) : great ;; | |
*) pfx="${cur_%%:*}:" ;; | |
esac | |
cur_="${cur_#*:}" | |
lhs=0 | |
;; | |
+*) | |
pfx="+" | |
cur_="${cur_#+}" | |
;; | |
esac | |
case "$cmd" in | |
fetch) | |
if [ $lhs = 1 ]; then | |
__git_complete_fetch_refspecs "$remote" "$pfx" "$cur_" | |
else | |
__git_complete_refs --pfx="$pfx" --cur="$cur_" | |
fi | |
;; | |
pull|remote) | |
if [ $lhs = 1 ]; then | |
__git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_" | |
else | |
__git_complete_refs --pfx="$pfx" --cur="$cur_" | |
fi | |
;; | |
push) | |
if [ $lhs = 1 ]; then | |
__git_complete_refs --pfx="$pfx" --cur="$cur_" | |
else | |
__git_complete_refs --remote="$remote" --pfx="$pfx" --cur="$cur_" | |
fi | |
;; | |
esac | |
} | |
__git_complete_strategy () | |
{ | |
__git_compute_merge_strategies | |
case "$prev" in | |
-s|--strategy) | |
__gitcomp "$__git_merge_strategies" | |
return 0 | |
;; | |
-X) | |
__gitcomp "$__git_merge_strategy_options" | |
return 0 | |
;; | |
esac | |
case "$cur" in | |
--strategy=*) | |
__gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}" | |
return 0 | |
;; | |
--strategy-option=*) | |
__gitcomp "$__git_merge_strategy_options" "" "${cur##--strategy-option=}" | |
return 0 | |
;; | |
esac | |
return 1 | |
} | |
__git_all_commands= | |
__git_compute_all_commands () | |
{ | |
test -n "$__git_all_commands" || | |
__git_all_commands=$(__git --list-cmds=main,others,alias,nohelpers) | |
} | |
# Lists all set config variables starting with the given section prefix, | |
# with the prefix removed. | |
__git_get_config_variables () | |
{ | |
local section="$1" i IFS=$'\n' | |
for i in $(__git config --name-only --get-regexp "^$section\..*"); do | |
echo "${i#$section.}" | |
done | |
} | |
__git_pretty_aliases () | |
{ | |
__git_get_config_variables "pretty" | |
} | |
# __git_aliased_command requires 1 argument | |
__git_aliased_command () | |
{ | |
local word cmdline=$(__git config --get "alias.$1") | |
for word in $cmdline; do | |
case "$word" in | |
\!gitk|gitk) | |
echo "gitk" | |
return | |
;; | |
\!*) : shell command alias ;; | |
-*) : option ;; | |
*=*) : setting env ;; | |
git) : git itself ;; | |
\(\)) : skip parens of shell function definition ;; | |
{) : skip start of shell helper function ;; | |
:) : skip null command ;; | |
\'*) : skip opening quote after sh -c ;; | |
*) | |
echo "$word" | |
return | |
esac | |
done | |
} | |
# Check whether one of the given words is present on the command line, | |
# and print the first word found. | |
# | |
# Usage: __git_find_on_cmdline [<option>]... "<wordlist>" | |
# --show-idx: Optionally show the index of the found word in the $words array. | |
__git_find_on_cmdline () | |
{ | |
local word c=1 show_idx | |
while test $# -gt 1; do | |
case "$1" in | |
--show-idx) show_idx=y ;; | |
*) return 1 ;; | |
esac | |
shift | |
done | |
local wordlist="$1" | |
while [ $c -lt $cword ]; do | |
for word in $wordlist; do | |
if [ "$word" = "${words[c]}" ]; then | |
if [ -n "$show_idx" ]; then | |
echo "$c $word" | |
else | |
echo "$word" | |
fi | |
return | |
fi | |
done | |
((c++)) | |
done | |
} | |
# Echo the value of an option set on the command line or config | |
# | |
# $1: short option name | |
# $2: long option name including = | |
# $3: list of possible values | |
# $4: config string (optional) | |
# | |
# example: | |
# result="$(__git_get_option_value "-d" "--do-something=" \ | |
# "yes no" "core.doSomething")" | |
# | |
# result is then either empty (no option set) or "yes" or "no" | |
# | |
# __git_get_option_value requires 3 arguments | |
__git_get_option_value () | |
{ | |
local c short_opt long_opt val | |
local result= values config_key word | |
short_opt="$1" | |
long_opt="$2" | |
values="$3" | |
config_key="$4" | |
((c = $cword - 1)) | |
while [ $c -ge 0 ]; do | |
word="${words[c]}" | |
for val in $values; do | |
if [ "$short_opt$val" = "$word" ] || | |
[ "$long_opt$val" = "$word" ]; then | |
result="$val" | |
break 2 | |
fi | |
done | |
((c--)) | |
done | |
if [ -n "$config_key" ] && [ -z "$result" ]; then | |
result="$(__git config "$config_key")" | |
fi | |
echo "$result" | |
} | |
__git_has_doubledash () | |
{ | |
local c=1 | |
while [ $c -lt $cword ]; do | |
if [ "--" = "${words[c]}" ]; then | |
return 0 | |
fi | |
((c++)) | |
done | |
return 1 | |
} | |
# Try to count non option arguments passed on the command line for the | |
# specified git command. | |
# When options are used, it is necessary to use the special -- option to | |
# tell the implementation were non option arguments begin. | |
# XXX this can not be improved, since options can appear everywhere, as | |
# an example: | |
# git mv x -n y | |
# | |
# __git_count_arguments requires 1 argument: the git command executed. | |
__git_count_arguments () | |
{ | |
local word i c=0 | |
# Skip "git" (first argument) | |
for ((i=1; i < ${#words[@]}; i++)); do | |
word="${words[i]}" | |
case "$word" in | |
--) | |
# Good; we can assume that the following are only non | |
# option arguments. | |
((c = 0)) | |
;; | |
"$1") | |
# Skip the specified git command and discard git | |
# main options | |
((c = 0)) | |
;; | |
?*) | |
((c++)) | |
;; | |
esac | |
done | |
printf "%d" $c | |
} | |
__git_whitespacelist="nowarn warn error error-all fix" | |
__git_patchformat="mbox stgit stgit-series hg mboxrd" | |
__git_showcurrentpatch="diff raw" | |
__git_am_inprogress_options="--skip --continue --resolved --abort --quit --show-current-patch" | |
_git_am () | |
{ | |
__git_find_repo_path | |
if [ -d "$__git_repo_path"/rebase-apply ]; then | |
__gitcomp "$__git_am_inprogress_options" | |
return | |
fi | |
case "$cur" in | |
--whitespace=*) | |
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" | |
return | |
;; | |
--patch-format=*) | |
__gitcomp "$__git_patchformat" "" "${cur##--patch-format=}" | |
return | |
;; | |
--show-current-patch=*) | |
__gitcomp "$__git_showcurrentpatch" "" "${cur##--show-current-patch=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin am "" \ | |
"$__git_am_inprogress_options" | |
return | |
esac | |
} | |
_git_apply () | |
{ | |
case "$cur" in | |
--whitespace=*) | |
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin apply | |
return | |
esac | |
} | |
_git_add () | |
{ | |
case "$cur" in | |
--chmod=*) | |
__gitcomp "+x -x" "" "${cur##--chmod=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin add | |
return | |
esac | |
local complete_opt="--others --modified --directory --no-empty-directory" | |
if test -n "$(__git_find_on_cmdline "-u --update")" | |
then | |
complete_opt="--modified" | |
fi | |
__git_complete_index_file "$complete_opt" | |
} | |
_git_archive () | |
{ | |
case "$cur" in | |
--format=*) | |
__gitcomp "$(git archive --list)" "" "${cur##--format=}" | |
return | |
;; | |
--remote=*) | |
__gitcomp_nl "$(__git_remotes)" "" "${cur##--remote=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin archive "--format= --list --verbose --prefix= --worktree-attributes" | |
return | |
;; | |
esac | |
__git_complete_file | |
} | |
_git_bisect () | |
{ | |
__git_has_doubledash && return | |
local subcommands="start bad good skip reset visualize replay log run" | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
if [ -z "$subcommand" ]; then | |
__git_find_repo_path | |
if [ -f "$__git_repo_path"/BISECT_START ]; then | |
__gitcomp "$subcommands" | |
else | |
__gitcomp "replay start" | |
fi | |
return | |
fi | |
case "$subcommand" in | |
bad|good|reset|skip|start) | |
__git_complete_refs | |
;; | |
*) | |
;; | |
esac | |
} | |
__git_ref_fieldlist="refname objecttype objectsize objectname upstream push HEAD symref" | |
_git_branch () | |
{ | |
local i c=1 only_local_ref="n" has_r="n" | |
while [ $c -lt $cword ]; do | |
i="${words[c]}" | |
case "$i" in | |
-d|--delete|-m|--move) only_local_ref="y" ;; | |
-r|--remotes) has_r="y" ;; | |
esac | |
((c++)) | |
done | |
case "$cur" in | |
--set-upstream-to=*) | |
__git_complete_refs --cur="${cur##--set-upstream-to=}" | |
;; | |
--*) | |
__gitcomp_builtin branch | |
;; | |
*) | |
if [ $only_local_ref = "y" -a $has_r = "n" ]; then | |
__gitcomp_direct "$(__git_heads "" "$cur" " ")" | |
else | |
__git_complete_refs | |
fi | |
;; | |
esac | |
} | |
_git_bundle () | |
{ | |
local cmd="${words[2]}" | |
case "$cword" in | |
2) | |
__gitcomp "create list-heads verify unbundle" | |
;; | |
3) | |
# looking for a file | |
;; | |
*) | |
case "$cmd" in | |
create) | |
__git_complete_revlist | |
;; | |
esac | |
;; | |
esac | |
} | |
_git_checkout () | |
{ | |
__git_has_doubledash && return | |
case "$cur" in | |
--conflict=*) | |
__gitcomp "diff3 merge" "" "${cur##--conflict=}" | |
;; | |
--*) | |
__gitcomp_builtin checkout | |
;; | |
*) | |
# check if --track, --no-track, or --no-guess was specified | |
# if so, disable DWIM mode | |
local flags="--track --no-track --no-guess" track_opt="--track" | |
if [ "$GIT_COMPLETION_CHECKOUT_NO_GUESS" = "1" ] || | |
[ -n "$(__git_find_on_cmdline "$flags")" ]; then | |
track_opt='' | |
fi | |
__git_complete_refs $track_opt | |
;; | |
esac | |
} | |
__git_sequencer_inprogress_options="--continue --quit --abort --skip" | |
__git_cherry_pick_inprogress_options=$__git_sequencer_inprogress_options | |
_git_cherry_pick () | |
{ | |
__git_find_repo_path | |
if [ -f "$__git_repo_path"/CHERRY_PICK_HEAD ]; then | |
__gitcomp "$__git_cherry_pick_inprogress_options" | |
return | |
fi | |
__git_complete_strategy && return | |
case "$cur" in | |
--*) | |
__gitcomp_builtin cherry-pick "" \ | |
"$__git_cherry_pick_inprogress_options" | |
;; | |
*) | |
__git_complete_refs | |
;; | |
esac | |
} | |
_git_clean () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin clean | |
return | |
;; | |
esac | |
# XXX should we check for -x option ? | |
__git_complete_index_file "--others --directory" | |
} | |
_git_clone () | |
{ | |
case "$prev" in | |
-c|--config) | |
__git_complete_config_variable_name_and_value | |
return | |
;; | |
esac | |
case "$cur" in | |
--config=*) | |
__git_complete_config_variable_name_and_value \ | |
--cur="${cur##--config=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin clone | |
return | |
;; | |
esac | |
} | |
__git_untracked_file_modes="all no normal" | |
_git_commit () | |
{ | |
case "$prev" in | |
-c|-C) | |
__git_complete_refs | |
return | |
;; | |
esac | |
case "$cur" in | |
--cleanup=*) | |
__gitcomp "default scissors strip verbatim whitespace | |
" "" "${cur##--cleanup=}" | |
return | |
;; | |
--reuse-message=*|--reedit-message=*|\ | |
--fixup=*|--squash=*) | |
__git_complete_refs --cur="${cur#*=}" | |
return | |
;; | |
--untracked-files=*) | |
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin commit | |
return | |
esac | |
if __git rev-parse --verify --quiet HEAD >/dev/null; then | |
__git_complete_index_file "--committable" | |
else | |
# This is the first commit | |
__git_complete_index_file "--cached" | |
fi | |
} | |
_git_describe () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin describe | |
return | |
esac | |
__git_complete_refs | |
} | |
__git_diff_algorithms="myers minimal patience histogram" | |
__git_diff_submodule_formats="diff log short" | |
__git_color_moved_opts="no default plain blocks zebra dimmed-zebra" | |
__git_color_moved_ws_opts="no ignore-space-at-eol ignore-space-change | |
ignore-all-space allow-indentation-change" | |
__git_diff_common_options="--stat --numstat --shortstat --summary | |
--patch-with-stat --name-only --name-status --color | |
--no-color --color-words --no-renames --check | |
--color-moved --color-moved= --no-color-moved | |
--color-moved-ws= --no-color-moved-ws | |
--full-index --binary --abbrev --diff-filter= | |
--find-copies-harder --ignore-cr-at-eol | |
--text --ignore-space-at-eol --ignore-space-change | |
--ignore-all-space --ignore-blank-lines --exit-code | |
--quiet --ext-diff --no-ext-diff | |
--no-prefix --src-prefix= --dst-prefix= | |
--inter-hunk-context= | |
--patience --histogram --minimal | |
--raw --word-diff --word-diff-regex= | |
--dirstat --dirstat= --dirstat-by-file | |
--dirstat-by-file= --cumulative | |
--diff-algorithm= | |
--submodule --submodule= --ignore-submodules | |
--indent-heuristic --no-indent-heuristic | |
--textconv --no-textconv | |
" | |
_git_diff () | |
{ | |
__git_has_doubledash && return | |
case "$cur" in | |
--diff-algorithm=*) | |
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}" | |
return | |
;; | |
--submodule=*) | |
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}" | |
return | |
;; | |
--color-moved=*) | |
__gitcomp "$__git_color_moved_opts" "" "${cur##--color-moved=}" | |
return | |
;; | |
--color-moved-ws=*) | |
__gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}" | |
return | |
;; | |
--*) | |
__gitcomp "--cached --staged --pickaxe-all --pickaxe-regex | |
--base --ours --theirs --no-index | |
$__git_diff_common_options | |
" | |
return | |
;; | |
esac | |
__git_complete_revlist_file | |
} | |
__git_mergetools_common="diffuse diffmerge ecmerge emerge kdiff3 meld opendiff | |
tkdiff vimdiff gvimdiff xxdiff araxis p4merge bc | |
codecompare smerge | |
" | |
_git_difftool () | |
{ | |
__git_has_doubledash && return | |
case "$cur" in | |
--tool=*) | |
__gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin difftool "$__git_diff_common_options | |
--base --cached --ours --theirs | |
--pickaxe-all --pickaxe-regex | |
--relative --staged | |
" | |
return | |
;; | |
esac | |
__git_complete_revlist_file | |
} | |
__git_fetch_recurse_submodules="yes on-demand no" | |
_git_fetch () | |
{ | |
case "$cur" in | |
--recurse-submodules=*) | |
__gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}" | |
return | |
;; | |
--filter=*) | |
__gitcomp "blob:none blob:limit= sparse:oid=" "" "${cur##--filter=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin fetch | |
return | |
;; | |
esac | |
__git_complete_remote_or_refspec | |
} | |
__git_format_patch_extra_options=" | |
--full-index --not --all --no-prefix --src-prefix= | |
--dst-prefix= --notes | |
" | |
_git_format_patch () | |
{ | |
case "$cur" in | |
--thread=*) | |
__gitcomp " | |
deep shallow | |
" "" "${cur##--thread=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin format-patch "$__git_format_patch_extra_options" | |
return | |
;; | |
esac | |
__git_complete_revlist | |
} | |
_git_fsck () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin fsck | |
return | |
;; | |
esac | |
} | |
_git_gitk () | |
{ | |
_gitk | |
} | |
# Lists matching symbol names from a tag (as in ctags) file. | |
# 1: List symbol names matching this word. | |
# 2: The tag file to list symbol names from. | |
# 3: A prefix to be added to each listed symbol name (optional). | |
# 4: A suffix to be appended to each listed symbol name (optional). | |
__git_match_ctag () { | |
awk -v pfx="${3-}" -v sfx="${4-}" " | |
/^${1//\//\\/}/ { print pfx \$1 sfx } | |
" "$2" | |
} | |
# Complete symbol names from a tag file. | |
# Usage: __git_complete_symbol [<option>]... | |
# --tags=<file>: The tag file to list symbol names from instead of the | |
# default "tags". | |
# --pfx=<prefix>: A prefix to be added to each symbol name. | |
# --cur=<word>: The current symbol name to be completed. Defaults to | |
# the current word to be completed. | |
# --sfx=<suffix>: A suffix to be appended to each symbol name instead | |
# of the default space. | |
__git_complete_symbol () { | |
local tags=tags pfx="" cur_="${cur-}" sfx=" " | |
while test $# != 0; do | |
case "$1" in | |
--tags=*) tags="${1##--tags=}" ;; | |
--pfx=*) pfx="${1##--pfx=}" ;; | |
--cur=*) cur_="${1##--cur=}" ;; | |
--sfx=*) sfx="${1##--sfx=}" ;; | |
*) return 1 ;; | |
esac | |
shift | |
done | |
if test -r "$tags"; then | |
__gitcomp_direct "$(__git_match_ctag "$cur_" "$tags" "$pfx" "$sfx")" | |
fi | |
} | |
_git_grep () | |
{ | |
__git_has_doubledash && return | |
case "$cur" in | |
--*) | |
__gitcomp_builtin grep | |
return | |
;; | |
esac | |
case "$cword,$prev" in | |
2,*|*,-*) | |
__git_complete_symbol && return | |
;; | |
esac | |
__git_complete_refs | |
} | |
_git_help () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin help | |
return | |
;; | |
esac | |
if test -n "$GIT_TESTING_ALL_COMMAND_LIST" | |
then | |
__gitcomp "$GIT_TESTING_ALL_COMMAND_LIST $(__git --list-cmds=alias,list-guide) gitk" | |
else | |
__gitcomp "$(__git --list-cmds=main,nohelpers,alias,list-guide) gitk" | |
fi | |
} | |
_git_init () | |
{ | |
case "$cur" in | |
--shared=*) | |
__gitcomp " | |
false true umask group all world everybody | |
" "" "${cur##--shared=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin init | |
return | |
;; | |
esac | |
} | |
_git_ls_files () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin ls-files | |
return | |
;; | |
esac | |
# XXX ignore options like --modified and always suggest all cached | |
# files. | |
__git_complete_index_file "--cached" | |
} | |
_git_ls_remote () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin ls-remote | |
return | |
;; | |
esac | |
__gitcomp_nl "$(__git_remotes)" | |
} | |
_git_ls_tree () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin ls-tree | |
return | |
;; | |
esac | |
__git_complete_file | |
} | |
# Options that go well for log, shortlog and gitk | |
__git_log_common_options=" | |
--not --all | |
--branches --tags --remotes | |
--first-parent --merges --no-merges | |
--max-count= | |
--max-age= --since= --after= | |
--min-age= --until= --before= | |
--min-parents= --max-parents= | |
--no-min-parents --no-max-parents | |
" | |
# Options that go well for log and gitk (not shortlog) | |
__git_log_gitk_options=" | |
--dense --sparse --full-history | |
--simplify-merges --simplify-by-decoration | |
--left-right --notes --no-notes | |
" | |
# Options that go well for log and shortlog (not gitk) | |
__git_log_shortlog_options=" | |
--author= --committer= --grep= | |
--all-match --invert-grep | |
" | |
__git_log_pretty_formats="oneline short medium full fuller reference email raw format: tformat: mboxrd" | |
__git_log_date_formats="relative iso8601 iso8601-strict rfc2822 short local default raw unix format:" | |
_git_log () | |
{ | |
__git_has_doubledash && return | |
__git_find_repo_path | |
local merge="" | |
if [ -f "$__git_repo_path/MERGE_HEAD" ]; then | |
merge="--merge" | |
fi | |
case "$prev,$cur" in | |
-L,:*:*) | |
return # fall back to Bash filename completion | |
;; | |
-L,:*) | |
__git_complete_symbol --cur="${cur#:}" --sfx=":" | |
return | |
;; | |
-G,*|-S,*) | |
__git_complete_symbol | |
return | |
;; | |
esac | |
case "$cur" in | |
--pretty=*|--format=*) | |
__gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases) | |
" "" "${cur#*=}" | |
return | |
;; | |
--date=*) | |
__gitcomp "$__git_log_date_formats" "" "${cur##--date=}" | |
return | |
;; | |
--decorate=*) | |
__gitcomp "full short no" "" "${cur##--decorate=}" | |
return | |
;; | |
--diff-algorithm=*) | |
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}" | |
return | |
;; | |
--submodule=*) | |
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}" | |
return | |
;; | |
--no-walk=*) | |
__gitcomp "sorted unsorted" "" "${cur##--no-walk=}" | |
return | |
;; | |
--*) | |
__gitcomp " | |
$__git_log_common_options | |
$__git_log_shortlog_options | |
$__git_log_gitk_options | |
--root --topo-order --date-order --reverse | |
--follow --full-diff | |
--abbrev-commit --no-abbrev-commit --abbrev= | |
--relative-date --date= | |
--pretty= --format= --oneline | |
--show-signature | |
--cherry-mark | |
--cherry-pick | |
--graph | |
--decorate --decorate= --no-decorate | |
--walk-reflogs | |
--no-walk --no-walk= --do-walk | |
--parents --children | |
--expand-tabs --expand-tabs= --no-expand-tabs | |
--patch | |
$merge | |
$__git_diff_common_options | |
--pickaxe-all --pickaxe-regex | |
" | |
return | |
;; | |
-L:*:*) | |
return # fall back to Bash filename completion | |
;; | |
-L:*) | |
__git_complete_symbol --cur="${cur#-L:}" --sfx=":" | |
return | |
;; | |
-G*) | |
__git_complete_symbol --pfx="-G" --cur="${cur#-G}" | |
return | |
;; | |
-S*) | |
__git_complete_symbol --pfx="-S" --cur="${cur#-S}" | |
return | |
;; | |
esac | |
__git_complete_revlist | |
} | |
_git_merge () | |
{ | |
__git_complete_strategy && return | |
case "$cur" in | |
--*) | |
__gitcomp_builtin merge | |
return | |
esac | |
__git_complete_refs | |
} | |
_git_mergetool () | |
{ | |
case "$cur" in | |
--tool=*) | |
__gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}" | |
return | |
;; | |
--*) | |
__gitcomp "--tool= --prompt --no-prompt --gui --no-gui" | |
return | |
;; | |
esac | |
} | |
_git_merge_base () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin merge-base | |
return | |
;; | |
esac | |
__git_complete_refs | |
} | |
_git_mv () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin mv | |
return | |
;; | |
esac | |
if [ $(__git_count_arguments "mv") -gt 0 ]; then | |
# We need to show both cached and untracked files (including | |
# empty directories) since this may not be the last argument. | |
__git_complete_index_file "--cached --others --directory" | |
else | |
__git_complete_index_file "--cached" | |
fi | |
} | |
_git_notes () | |
{ | |
local subcommands='add append copy edit get-ref list merge prune remove show' | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
case "$subcommand,$cur" in | |
,--*) | |
__gitcomp_builtin notes | |
;; | |
,*) | |
case "$prev" in | |
--ref) | |
__git_complete_refs | |
;; | |
*) | |
__gitcomp "$subcommands --ref" | |
;; | |
esac | |
;; | |
*,--reuse-message=*|*,--reedit-message=*) | |
__git_complete_refs --cur="${cur#*=}" | |
;; | |
*,--*) | |
__gitcomp_builtin notes_$subcommand | |
;; | |
prune,*|get-ref,*) | |
# this command does not take a ref, do not complete it | |
;; | |
*) | |
case "$prev" in | |
-m|-F) | |
;; | |
*) | |
__git_complete_refs | |
;; | |
esac | |
;; | |
esac | |
} | |
_git_pull () | |
{ | |
__git_complete_strategy && return | |
case "$cur" in | |
--recurse-submodules=*) | |
__gitcomp "$__git_fetch_recurse_submodules" "" "${cur##--recurse-submodules=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin pull | |
return | |
;; | |
esac | |
__git_complete_remote_or_refspec | |
} | |
__git_push_recurse_submodules="check on-demand only" | |
__git_complete_force_with_lease () | |
{ | |
local cur_=$1 | |
case "$cur_" in | |
--*=) | |
;; | |
*:*) | |
__git_complete_refs --cur="${cur_#*:}" | |
;; | |
*) | |
__git_complete_refs --cur="$cur_" | |
;; | |
esac | |
} | |
_git_push () | |
{ | |
case "$prev" in | |
--repo) | |
__gitcomp_nl "$(__git_remotes)" | |
return | |
;; | |
--recurse-submodules) | |
__gitcomp "$__git_push_recurse_submodules" | |
return | |
;; | |
esac | |
case "$cur" in | |
--repo=*) | |
__gitcomp_nl "$(__git_remotes)" "" "${cur##--repo=}" | |
return | |
;; | |
--recurse-submodules=*) | |
__gitcomp "$__git_push_recurse_submodules" "" "${cur##--recurse-submodules=}" | |
return | |
;; | |
--force-with-lease=*) | |
__git_complete_force_with_lease "${cur##--force-with-lease=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin push | |
return | |
;; | |
esac | |
__git_complete_remote_or_refspec | |
} | |
_git_range_diff () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp " | |
--creation-factor= --no-dual-color | |
$__git_diff_common_options | |
" | |
return | |
;; | |
esac | |
__git_complete_revlist | |
} | |
__git_rebase_inprogress_options="--continue --skip --abort --quit --show-current-patch" | |
__git_rebase_interactive_inprogress_options="$__git_rebase_inprogress_options --edit-todo" | |
_git_rebase () | |
{ | |
__git_find_repo_path | |
if [ -f "$__git_repo_path"/rebase-merge/interactive ]; then | |
__gitcomp "$__git_rebase_interactive_inprogress_options" | |
return | |
elif [ -d "$__git_repo_path"/rebase-apply ] || \ | |
[ -d "$__git_repo_path"/rebase-merge ]; then | |
__gitcomp "$__git_rebase_inprogress_options" | |
return | |
fi | |
__git_complete_strategy && return | |
case "$cur" in | |
--whitespace=*) | |
__gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" | |
return | |
;; | |
--onto=*) | |
__git_complete_refs --cur="${cur##--onto=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin rebase "" \ | |
"$__git_rebase_interactive_inprogress_options" | |
return | |
esac | |
__git_complete_refs | |
} | |
_git_reflog () | |
{ | |
local subcommands="show delete expire" | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
if [ -z "$subcommand" ]; then | |
__gitcomp "$subcommands" | |
else | |
__git_complete_refs | |
fi | |
} | |
__git_send_email_confirm_options="always never auto cc compose" | |
__git_send_email_suppresscc_options="author self cc bodycc sob cccmd body all" | |
_git_send_email () | |
{ | |
case "$prev" in | |
--to|--cc|--bcc|--from) | |
__gitcomp "$(__git send-email --dump-aliases)" | |
return | |
;; | |
esac | |
case "$cur" in | |
--confirm=*) | |
__gitcomp " | |
$__git_send_email_confirm_options | |
" "" "${cur##--confirm=}" | |
return | |
;; | |
--suppress-cc=*) | |
__gitcomp " | |
$__git_send_email_suppresscc_options | |
" "" "${cur##--suppress-cc=}" | |
return | |
;; | |
--smtp-encryption=*) | |
__gitcomp "ssl tls" "" "${cur##--smtp-encryption=}" | |
return | |
;; | |
--thread=*) | |
__gitcomp " | |
deep shallow | |
" "" "${cur##--thread=}" | |
return | |
;; | |
--to=*|--cc=*|--bcc=*|--from=*) | |
__gitcomp "$(__git send-email --dump-aliases)" "" "${cur#--*=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin send-email "--annotate --bcc --cc --cc-cmd --chain-reply-to | |
--compose --confirm= --dry-run --envelope-sender | |
--from --identity | |
--in-reply-to --no-chain-reply-to --no-signed-off-by-cc | |
--no-suppress-from --no-thread --quiet --reply-to | |
--signed-off-by-cc --smtp-pass --smtp-server | |
--smtp-server-port --smtp-encryption= --smtp-user | |
--subject --suppress-cc= --suppress-from --thread --to | |
--validate --no-validate | |
$__git_format_patch_extra_options" | |
return | |
;; | |
esac | |
__git_complete_revlist | |
} | |
_git_stage () | |
{ | |
_git_add | |
} | |
_git_status () | |
{ | |
local complete_opt | |
local untracked_state | |
case "$cur" in | |
--ignore-submodules=*) | |
__gitcomp "none untracked dirty all" "" "${cur##--ignore-submodules=}" | |
return | |
;; | |
--untracked-files=*) | |
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}" | |
return | |
;; | |
--column=*) | |
__gitcomp " | |
always never auto column row plain dense nodense | |
" "" "${cur##--column=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin status | |
return | |
;; | |
esac | |
untracked_state="$(__git_get_option_value "-u" "--untracked-files=" \ | |
"$__git_untracked_file_modes" "status.showUntrackedFiles")" | |
case "$untracked_state" in | |
no) | |
# --ignored option does not matter | |
complete_opt= | |
;; | |
all|normal|*) | |
complete_opt="--cached --directory --no-empty-directory --others" | |
if [ -n "$(__git_find_on_cmdline "--ignored")" ]; then | |
complete_opt="$complete_opt --ignored --exclude=*" | |
fi | |
;; | |
esac | |
__git_complete_index_file "$complete_opt" | |
} | |
_git_switch () | |
{ | |
case "$cur" in | |
--conflict=*) | |
__gitcomp "diff3 merge" "" "${cur##--conflict=}" | |
;; | |
--*) | |
__gitcomp_builtin switch | |
;; | |
*) | |
# check if --track, --no-track, or --no-guess was specified | |
# if so, disable DWIM mode | |
local track_opt="--track" only_local_ref=n | |
if [ "$GIT_COMPLETION_CHECKOUT_NO_GUESS" = "1" ] || | |
[ -n "$(__git_find_on_cmdline "--track --no-track --no-guess")" ]; then | |
track_opt='' | |
fi | |
# explicit --guess enables DWIM mode regardless of | |
# $GIT_COMPLETION_CHECKOUT_NO_GUESS | |
if [ -n "$(__git_find_on_cmdline "--guess")" ]; then | |
track_opt='--track' | |
fi | |
if [ -z "$(__git_find_on_cmdline "-d --detach")" ]; then | |
only_local_ref=y | |
else | |
# --guess --detach is invalid combination, no | |
# dwim will be done when --detach is specified | |
track_opt= | |
fi | |
if [ $only_local_ref = y -a -z "$track_opt" ]; then | |
__gitcomp_direct "$(__git_heads "" "$cur" " ")" | |
else | |
__git_complete_refs $track_opt | |
fi | |
;; | |
esac | |
} | |
__git_config_get_set_variables () | |
{ | |
local prevword word config_file= c=$cword | |
while [ $c -gt 1 ]; do | |
word="${words[c]}" | |
case "$word" in | |
--system|--global|--local|--file=*) | |
config_file="$word" | |
break | |
;; | |
-f|--file) | |
config_file="$word $prevword" | |
break | |
;; | |
esac | |
prevword=$word | |
c=$((--c)) | |
done | |
__git config $config_file --name-only --list | |
} | |
__git_config_vars= | |
__git_compute_config_vars () | |
{ | |
test -n "$__git_config_vars" || | |
__git_config_vars="$(git help --config-for-completion | sort -u)" | |
} | |
# Completes possible values of various configuration variables. | |
# | |
# Usage: __git_complete_config_variable_value [<option>]... | |
# --varname=<word>: The name of the configuration variable whose value is | |
# to be completed. Defaults to the previous word on the | |
# command line. | |
# --cur=<word>: The current value to be completed. Defaults to the current | |
# word to be completed. | |
__git_complete_config_variable_value () | |
{ | |
local varname="$prev" cur_="$cur" | |
while test $# != 0; do | |
case "$1" in | |
--varname=*) varname="${1##--varname=}" ;; | |
--cur=*) cur_="${1##--cur=}" ;; | |
*) return 1 ;; | |
esac | |
shift | |
done | |
if [ "${BASH_VERSINFO[0]:-0}" -ge 4 ]; then | |
varname="${varname,,}" | |
else | |
varname="$(echo "$varname" |tr A-Z a-z)" | |
fi | |
case "$varname" in | |
branch.*.remote|branch.*.pushremote) | |
__gitcomp_nl "$(__git_remotes)" "" "$cur_" | |
return | |
;; | |
branch.*.merge) | |
__git_complete_refs --cur="$cur_" | |
return | |
;; | |
branch.*.rebase) | |
__gitcomp "false true merges preserve interactive" "" "$cur_" | |
return | |
;; | |
remote.pushdefault) | |
__gitcomp_nl "$(__git_remotes)" "" "$cur_" | |
return | |
;; | |
remote.*.fetch) | |
local remote="${varname#remote.}" | |
remote="${remote%.fetch}" | |
if [ -z "$cur_" ]; then | |
__gitcomp_nl "refs/heads/" "" "" "" | |
return | |
fi | |
__gitcomp_nl "$(__git_refs_remotes "$remote")" "" "$cur_" | |
return | |
;; | |
remote.*.push) | |
local remote="${varname#remote.}" | |
remote="${remote%.push}" | |
__gitcomp_nl "$(__git for-each-ref \ | |
--format='%(refname):%(refname)' refs/heads)" "" "$cur_" | |
return | |
;; | |
pull.twohead|pull.octopus) | |
__git_compute_merge_strategies | |
__gitcomp "$__git_merge_strategies" "" "$cur_" | |
return | |
;; | |
color.pager) | |
__gitcomp "false true" "" "$cur_" | |
return | |
;; | |
color.*.*) | |
__gitcomp " | |
normal black red green yellow blue magenta cyan white | |
bold dim ul blink reverse | |
" "" "$cur_" | |
return | |
;; | |
color.*) | |
__gitcomp "false true always never auto" "" "$cur_" | |
return | |
;; | |
diff.submodule) | |
__gitcomp "$__git_diff_submodule_formats" "" "$cur_" | |
return | |
;; | |
help.format) | |
__gitcomp "man info web html" "" "$cur_" | |
return | |
;; | |
log.date) | |
__gitcomp "$__git_log_date_formats" "" "$cur_" | |
return | |
;; | |
sendemail.aliasfiletype) | |
__gitcomp "mutt mailrc pine elm gnus" "" "$cur_" | |
return | |
;; | |
sendemail.confirm) | |
__gitcomp "$__git_send_email_confirm_options" "" "$cur_" | |
return | |
;; | |
sendemail.suppresscc) | |
__gitcomp "$__git_send_email_suppresscc_options" "" "$cur_" | |
return | |
;; | |
sendemail.transferencoding) | |
__gitcomp "7bit 8bit quoted-printable base64" "" "$cur_" | |
return | |
;; | |
*.*) | |
return | |
;; | |
esac | |
} | |
# Completes configuration sections, subsections, variable names. | |
# | |
# Usage: __git_complete_config_variable_name [<option>]... | |
# --cur=<word>: The current configuration section/variable name to be | |
# completed. Defaults to the current word to be completed. | |
# --sfx=<suffix>: A suffix to be appended to each fully completed | |
# configuration variable name (but not to sections or | |
# subsections) instead of the default space. | |
__git_complete_config_variable_name () | |
{ | |
local cur_="$cur" sfx | |
while test $# != 0; do | |
case "$1" in | |
--cur=*) cur_="${1##--cur=}" ;; | |
--sfx=*) sfx="${1##--sfx=}" ;; | |
*) return 1 ;; | |
esac | |
shift | |
done | |
case "$cur_" in | |
branch.*.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_##*.}" | |
__gitcomp "remote pushRemote merge mergeOptions rebase" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
branch.*) | |
local pfx="${cur%.*}." | |
cur_="${cur#*.}" | |
__gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")" | |
__gitcomp_nl_append $'autoSetupMerge\nautoSetupRebase\n' "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
guitool.*.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_##*.}" | |
__gitcomp " | |
argPrompt cmd confirm needsFile noConsole noRescan | |
prompt revPrompt revUnmerged title | |
" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
difftool.*.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_##*.}" | |
__gitcomp "cmd path" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
man.*.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_##*.}" | |
__gitcomp "cmd path" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
mergetool.*.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_##*.}" | |
__gitcomp "cmd path trustExitCode" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
pager.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_#*.}" | |
__git_compute_all_commands | |
__gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
remote.*.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_##*.}" | |
__gitcomp " | |
url proxy fetch push mirror skipDefaultUpdate | |
receivepack uploadpack tagOpt pushurl | |
" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
remote.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_#*.}" | |
__gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "." | |
__gitcomp_nl_append "pushDefault" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
url.*.*) | |
local pfx="${cur_%.*}." | |
cur_="${cur_##*.}" | |
__gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_" "$sfx" | |
return | |
;; | |
*.*) | |
__git_compute_config_vars | |
__gitcomp "$__git_config_vars" "" "$cur_" "$sfx" | |
;; | |
*) | |
__git_compute_config_vars | |
__gitcomp "$(echo "$__git_config_vars" | | |
awk -F . '{ | |
sections[$1] = 1 | |
} | |
END { | |
for (s in sections) | |
print s "." | |
} | |
')" "" "$cur_" | |
;; | |
esac | |
} | |
# Completes '='-separated configuration sections/variable names and values | |
# for 'git -c section.name=value'. | |
# | |
# Usage: __git_complete_config_variable_name_and_value [<option>]... | |
# --cur=<word>: The current configuration section/variable name/value to be | |
# completed. Defaults to the current word to be completed. | |
__git_complete_config_variable_name_and_value () | |
{ | |
local cur_="$cur" | |
while test $# != 0; do | |
case "$1" in | |
--cur=*) cur_="${1##--cur=}" ;; | |
*) return 1 ;; | |
esac | |
shift | |
done | |
case "$cur_" in | |
*=*) | |
__git_complete_config_variable_value \ | |
--varname="${cur_%%=*}" --cur="${cur_#*=}" | |
;; | |
*) | |
__git_complete_config_variable_name --cur="$cur_" --sfx='=' | |
;; | |
esac | |
} | |
_git_config () | |
{ | |
case "$prev" in | |
--get|--get-all|--unset|--unset-all) | |
__gitcomp_nl "$(__git_config_get_set_variables)" | |
return | |
;; | |
*.*) | |
__git_complete_config_variable_value | |
return | |
;; | |
esac | |
case "$cur" in | |
--*) | |
__gitcomp_builtin config | |
;; | |
*) | |
__git_complete_config_variable_name | |
;; | |
esac | |
} | |
_git_remote () | |
{ | |
local subcommands=" | |
add rename remove set-head set-branches | |
get-url set-url show prune update | |
" | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
if [ -z "$subcommand" ]; then | |
case "$cur" in | |
--*) | |
__gitcomp_builtin remote | |
;; | |
*) | |
__gitcomp "$subcommands" | |
;; | |
esac | |
return | |
fi | |
case "$subcommand,$cur" in | |
add,--*) | |
__gitcomp_builtin remote_add | |
;; | |
add,*) | |
;; | |
set-head,--*) | |
__gitcomp_builtin remote_set-head | |
;; | |
set-branches,--*) | |
__gitcomp_builtin remote_set-branches | |
;; | |
set-head,*|set-branches,*) | |
__git_complete_remote_or_refspec | |
;; | |
update,--*) | |
__gitcomp_builtin remote_update | |
;; | |
update,*) | |
__gitcomp "$(__git_remotes) $(__git_get_config_variables "remotes")" | |
;; | |
set-url,--*) | |
__gitcomp_builtin remote_set-url | |
;; | |
get-url,--*) | |
__gitcomp_builtin remote_get-url | |
;; | |
prune,--*) | |
__gitcomp_builtin remote_prune | |
;; | |
*) | |
__gitcomp_nl "$(__git_remotes)" | |
;; | |
esac | |
} | |
_git_replace () | |
{ | |
case "$cur" in | |
--format=*) | |
__gitcomp "short medium long" "" "${cur##--format=}" | |
return | |
;; | |
--*) | |
__gitcomp_builtin replace | |
return | |
;; | |
esac | |
__git_complete_refs | |
} | |
_git_rerere () | |
{ | |
local subcommands="clear forget diff remaining status gc" | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
if test -z "$subcommand" | |
then | |
__gitcomp "$subcommands" | |
return | |
fi | |
} | |
_git_reset () | |
{ | |
__git_has_doubledash && return | |
case "$cur" in | |
--*) | |
__gitcomp_builtin reset | |
return | |
;; | |
esac | |
__git_complete_refs | |
} | |
_git_restore () | |
{ | |
case "$cur" in | |
--conflict=*) | |
__gitcomp "diff3 merge" "" "${cur##--conflict=}" | |
;; | |
--source=*) | |
__git_complete_refs --cur="${cur##--source=}" | |
;; | |
--*) | |
__gitcomp_builtin restore | |
;; | |
esac | |
} | |
__git_revert_inprogress_options=$__git_sequencer_inprogress_options | |
_git_revert () | |
{ | |
__git_find_repo_path | |
if [ -f "$__git_repo_path"/REVERT_HEAD ]; then | |
__gitcomp "$__git_revert_inprogress_options" | |
return | |
fi | |
__git_complete_strategy && return | |
case "$cur" in | |
--*) | |
__gitcomp_builtin revert "" \ | |
"$__git_revert_inprogress_options" | |
return | |
;; | |
esac | |
__git_complete_refs | |
} | |
_git_rm () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin rm | |
return | |
;; | |
esac | |
__git_complete_index_file "--cached" | |
} | |
_git_shortlog () | |
{ | |
__git_has_doubledash && return | |
case "$cur" in | |
--*) | |
__gitcomp " | |
$__git_log_common_options | |
$__git_log_shortlog_options | |
--numbered --summary --email | |
" | |
return | |
;; | |
esac | |
__git_complete_revlist | |
} | |
_git_show () | |
{ | |
__git_has_doubledash && return | |
case "$cur" in | |
--pretty=*|--format=*) | |
__gitcomp "$__git_log_pretty_formats $(__git_pretty_aliases) | |
" "" "${cur#*=}" | |
return | |
;; | |
--diff-algorithm=*) | |
__gitcomp "$__git_diff_algorithms" "" "${cur##--diff-algorithm=}" | |
return | |
;; | |
--submodule=*) | |
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}" | |
return | |
;; | |
--*) | |
__gitcomp "--pretty= --format= --abbrev-commit --no-abbrev-commit | |
--oneline --show-signature --patch | |
--expand-tabs --expand-tabs= --no-expand-tabs | |
$__git_diff_common_options | |
" | |
return | |
;; | |
esac | |
__git_complete_revlist_file | |
} | |
_git_show_branch () | |
{ | |
case "$cur" in | |
--*) | |
__gitcomp_builtin show-branch | |
return | |
;; | |
esac | |
__git_complete_revlist | |
} | |
_git_sparse_checkout () | |
{ | |
local subcommands="list init set disable" | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
if [ -z "$subcommand" ]; then | |
__gitcomp "$subcommands" | |
return | |
fi | |
case "$subcommand,$cur" in | |
init,--*) | |
__gitcomp "--cone" | |
;; | |
set,--*) | |
__gitcomp "--stdin" | |
;; | |
*) | |
;; | |
esac | |
} | |
_git_stash () | |
{ | |
local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked' | |
local subcommands='push list show apply clear drop pop create branch' | |
local subcommand="$(__git_find_on_cmdline "$subcommands save")" | |
if [ -n "$(__git_find_on_cmdline "-p")" ]; then | |
subcommand="push" | |
fi | |
if [ -z "$subcommand" ]; then | |
case "$cur" in | |
--*) | |
__gitcomp "$save_opts" | |
;; | |
sa*) | |
if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then | |
__gitcomp "save" | |
fi | |
;; | |
*) | |
if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then | |
__gitcomp "$subcommands" | |
fi | |
;; | |
esac | |
else | |
case "$subcommand,$cur" in | |
push,--*) | |
__gitcomp "$save_opts --message" | |
;; | |
save,--*) | |
__gitcomp "$save_opts" | |
;; | |
apply,--*|pop,--*) | |
__gitcomp "--index --quiet" | |
;; | |
drop,--*) | |
__gitcomp "--quiet" | |
;; | |
list,--*) | |
__gitcomp "--name-status --oneline --patch-with-stat" | |
;; | |
show,--*|branch,--*) | |
;; | |
branch,*) | |
if [ $cword -eq 3 ]; then | |
__git_complete_refs | |
else | |
__gitcomp_nl "$(__git stash list \ | |
| sed -n -e 's/:.*//p')" | |
fi | |
;; | |
show,*|apply,*|drop,*|pop,*) | |
__gitcomp_nl "$(__git stash list \ | |
| sed -n -e 's/:.*//p')" | |
;; | |
*) | |
;; | |
esac | |
fi | |
} | |
_git_submodule () | |
{ | |
__git_has_doubledash && return | |
local subcommands="add status init deinit update set-branch set-url summary foreach sync absorbgitdirs" | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
if [ -z "$subcommand" ]; then | |
case "$cur" in | |
--*) | |
__gitcomp "--quiet" | |
;; | |
*) | |
__gitcomp "$subcommands" | |
;; | |
esac | |
return | |
fi | |
case "$subcommand,$cur" in | |
add,--*) | |
__gitcomp "--branch --force --name --reference --depth" | |
;; | |
status,--*) | |
__gitcomp "--cached --recursive" | |
;; | |
deinit,--*) | |
__gitcomp "--force --all" | |
;; | |
update,--*) | |
__gitcomp " | |
--init --remote --no-fetch | |
--recommend-shallow --no-recommend-shallow | |
--force --rebase --merge --reference --depth --recursive --jobs | |
" | |
;; | |
set-branch,--*) | |
__gitcomp "--default --branch" | |
;; | |
summary,--*) | |
__gitcomp "--cached --files --summary-limit" | |
;; | |
foreach,--*|sync,--*) | |
__gitcomp "--recursive" | |
;; | |
*) | |
;; | |
esac | |
} | |
_git_svn () | |
{ | |
local subcommands=" | |
init fetch clone rebase dcommit log find-rev | |
set-tree commit-diff info create-ignore propget | |
proplist show-ignore show-externals branch tag blame | |
migrate mkdirs reset gc | |
" | |
local subcommand="$(__git_find_on_cmdline "$subcommands")" | |
if [ -z "$subcommand" ]; then | |
__gitcomp "$subcommands" | |
else | |
local remote_opts="--username= --config-dir= --no-auth-cache" | |
local fc_opts=" | |
--follow-parent --authors-file= --repack= | |
--no-metadata --use-svm-props --use-svnsync-props | |
--log-window-size= --no-checkout --quiet | |
--repack-flags --use-log-author --localtime | |
--add-author-from | |
--recursive | |
--ignore-paths= --include-paths= $remote_opts | |
" | |
local init_opts=" | |
--template= --shared= --trunk= --tags= | |
--branches= --stdlayout --minimize-url | |
--no-metadata --use-svm-props --use-svnsync-props | |
--rewrite-root= --prefix= $remote_opts | |
" | |
local cmt_opts=" | |
--edit --rmdir --find-copies-harder --copy-similarity= | |
" | |
case "$subcommand,$cur" in | |
fetch,--*) | |
__gitcomp "--revision= --fetch-all $fc_opts" | |
;; | |
clone,--*) | |
__gitcomp "--revision= $fc_opts $init_opts" | |
;; | |
init,--*) | |
__gitcomp "$init_opts" | |
;; | |
dcommit,--*) | |
__gitcomp " | |
--merge --strategy= --verbose --dry-run | |
--fetch-all --no-rebase --commit-url | |
--revision --interactive $cmt_opts $fc_opts | |
" | |
;; | |
set-tree,--*) | |
__gitcomp "--stdin $cmt_opts $fc_opts" | |
;; | |
create-ignore,--*|propget,--*|proplist,--*|show-ignore,--*|\ | |
show-externals,--*|mkdirs,--*) | |
__gitcomp "--revision=" | |
;; | |
log,--*) | |
__gitcomp " | |
--limit= --revision= --verbose --incremental | |
--oneline --show-commit --non-recursive | |
--authors-file= --color | |
" | |
;; | |
rebase,--*) | |
__gitcomp " | |
--merge --verbose --strategy= --local | |
--fetch-all --dry-run $fc_opts | |
" | |
;; | |
commit-diff,--*) | |
__gitcomp "--message= --file= --revision= $cmt_opts" | |
;; | |
info,--*) | |
__gitcomp "--url" | |
;; | |
branch,--*) | |
__gitcomp "--dry-run --message --tag" | |
;; | |
tag,--*) | |
__gitcomp "--dry-run --message" | |
;; | |
blame,--*) | |
__gitcomp "--git-format" | |
;; | |
migrate,--*) | |
__gitcomp " | |
--config-dir= --ignore-paths= --minimize | |
--no-auth-cache --username= | |
" | |
;; | |
reset,--*) | |
__gitcomp "--revision= --parent" | |
;; | |
*) | |
;; | |
esac | |
fi | |
} | |
_git_tag () | |
{ | |
local i c=1 f=0 | |
while [ $c -lt $cword ]; do | |
i="${words[c]}" | |
case "$i" in | |
-d|--delete|-v|--verify) | |
__gitcomp_direct "$(__git_tags "" "$cur" " ")" | |
return | |
;; | |
-f) | |
f=1 | |
;; | |
esac | |
((c++)) | |
done | |
case "$prev" in | |
-m|-F) | |
;; | |
-*|tag) | |
if [ $f = 1 ]; then | |
__gitcomp_direct "$(__git_tags "" "$cur" " ")" | |
fi | |
;; | |
*) | |
__git_complete_refs | |
;; | |
esac | |
case "$cur" in | |
--*) | |
__gitcomp_builtin tag | |
;; | |
esac | |
} | |
_git_whatchanged () | |
{ | |
_git_log | |
} | |
__git_complete_worktree_paths () | |
{ | |
local IFS=$'\n' | |
__gitcomp_nl "$(git worktree list --porcelain | | |
# Skip the first entry: it's the path of the main worktree, | |
# which can't be moved, removed, locked, etc. | |
sed -n -e '2,$ s/^worktree //p')" | |
} | |
_git_worktree () | |
{ | |
local subcommands="add list lock move prune remove unlock" | |
local subcommand subcommand_idx | |
subcommand="$(__git_find_on_cmdline --show-idx "$subcommands")" | |
subcommand_idx="${subcommand% *}" | |
subcommand="${subcommand#* }" | |
case "$subcommand,$cur" in | |
,*) | |
__gitcomp "$subcommands" | |
;; | |
*,--*) | |
__gitcomp_builtin worktree_$subcommand | |
;; | |
add,*) # usage: git worktree add [<options>] <path> [<commit-ish>] | |
# Here we are not completing an --option, it's either the | |
# path or a ref. | |
case "$prev" in | |
-b|-B) # Complete refs for branch to be created/reseted. | |
__git_complete_refs | |
;; | |
-*) # The previous word is an -o|--option without an | |
# unstuck argument: have to complete the path for | |
# the new worktree, so don't list anything, but let | |
# Bash fall back to filename completion. | |
;; | |
*) # The previous word is not an --option, so it must | |
# be either the 'add' subcommand, the unstuck | |
# argument of an option (e.g. branch for -b|-B), or | |
# the path for the new worktree. | |
if [ $cword -eq $((subcommand_idx+1)) ]; then | |
# Right after the 'add' subcommand: have to | |
# complete the path, so fall back to Bash | |
# filename completion. | |
: | |
else | |
case "${words[cword-2]}" in | |
-b|-B) # After '-b <branch>': have to | |
# complete the path, so fall back | |
# to Bash filename completion. | |
;; | |
*) # After the path: have to complete | |
# the ref to be checked out. | |
__git_complete_refs | |
;; | |
esac | |
fi | |
;; | |
esac | |
;; | |
lock,*|remove,*|unlock,*) | |
__git_complete_worktree_paths | |
;; | |
move,*) | |
if [ $cword -eq $((subcommand_idx+1)) ]; then | |
# The first parameter must be an existing working | |
# tree to be moved. | |
__git_complete_worktree_paths | |
else | |
# The second parameter is the destination: it could | |
# be any path, so don't list anything, but let Bash | |
# fall back to filename completion. | |
: | |
fi | |
;; | |
esac | |
} | |
__git_complete_common () { | |
local command="$1" | |
case "$cur" in | |
--*) | |
__gitcomp_builtin "$command" | |
;; | |
esac | |
} | |
__git_cmds_with_parseopt_helper= | |
__git_support_parseopt_helper () { | |
test -n "$__git_cmds_with_parseopt_helper" || | |
__git_cmds_with_parseopt_helper="$(__git --list-cmds=parseopt)" | |
case " $__git_cmds_with_parseopt_helper " in | |
*" $1 "*) | |
return 0 | |
;; | |
*) | |
return 1 | |
;; | |
esac | |
} | |
__git_complete_command () { | |
local command="$1" | |
local completion_func="_git_${command//-/_}" | |
if ! declare -f $completion_func >/dev/null 2>/dev/null && | |
declare -f _completion_loader >/dev/null 2>/dev/null | |
then | |
_completion_loader "git-$command" | |
fi | |
if declare -f $completion_func >/dev/null 2>/dev/null | |
then | |
$completion_func | |
return 0 | |
elif __git_support_parseopt_helper "$command" | |
then | |
__git_complete_common "$command" | |
return 0 | |
else | |
return 1 | |
fi | |
} | |
__git_main () | |
{ | |
local i c=1 command __git_dir __git_repo_path | |
local __git_C_args C_args_count=0 | |
while [ $c -lt $cword ]; do | |
i="${words[c]}" | |
case "$i" in | |
--git-dir=*) __git_dir="${i#--git-dir=}" ;; | |
--git-dir) ((c++)) ; __git_dir="${words[c]}" ;; | |
--bare) __git_dir="." ;; | |
--help) command="help"; break ;; | |
-c|--work-tree|--namespace) ((c++)) ;; | |
-C) __git_C_args[C_args_count++]=-C | |
((c++)) | |
__git_C_args[C_args_count++]="${words[c]}" | |
;; | |
-*) ;; | |
*) command="$i"; break ;; | |
esac | |
((c++)) | |
done | |
if [ -z "$command" ]; then | |
case "$prev" in | |
--git-dir|-C|--work-tree) | |
# these need a path argument, let's fall back to | |
# Bash filename completion | |
return | |
;; | |
-c) | |
__git_complete_config_variable_name_and_value | |
return | |
;; | |
--namespace) | |
# we don't support completing these options' arguments | |
return | |
;; | |
esac | |
case "$cur" in | |
--*) __gitcomp " | |
--paginate | |
--no-pager | |
--git-dir= | |
--bare | |
--version | |
--exec-path | |
--exec-path= | |
--html-path | |
--man-path | |
--info-path | |
--work-tree= | |
--namespace= | |
--no-replace-objects | |
--help | |
" | |
;; | |
*) | |
if test -n "$GIT_TESTING_PORCELAIN_COMMAND_LIST" | |
then | |
__gitcomp "$GIT_TESTING_PORCELAIN_COMMAND_LIST" | |
else | |
__gitcomp "$(__git --list-cmds=list-mainporcelain,others,nohelpers,alias,list-complete,config)" | |
fi | |
;; | |
esac | |
return | |
fi | |
__git_complete_command "$command" && return | |
local expansion=$(__git_aliased_command "$command") | |
if [ -n "$expansion" ]; then | |
words[1]=$expansion | |
__git_complete_command "$expansion" | |
fi | |
} | |
__gitk_main () | |
{ | |
__git_has_doubledash && return | |
local __git_repo_path | |
__git_find_repo_path | |
local merge="" | |
if [ -f "$__git_repo_path/MERGE_HEAD" ]; then | |
merge="--merge" | |
fi | |
case "$cur" in | |
--*) | |
__gitcomp " | |
$__git_log_common_options | |
$__git_log_gitk_options | |
$merge | |
" | |
return | |
;; | |
esac | |
__git_complete_revlist | |
} | |
if [[ -n ${ZSH_VERSION-} ]] && | |
# Don't define these functions when sourced from 'git-completion.zsh', | |
# it has its own implementations. | |
[[ -z ${GIT_SOURCING_ZSH_COMPLETION-} ]]; then | |
echo "WARNING: this script is deprecated, please see git-completion.zsh" 1>&2 | |
autoload -U +X compinit && compinit | |
__gitcomp () | |
{ | |
emulate -L zsh | |
local cur_="${3-$cur}" | |
case "$cur_" in | |
--*=) | |
;; | |
*) | |
local c IFS=$' \t\n' | |
local -a array | |
for c in ${=1}; do | |
c="$c${4-}" | |
case $c in | |
--*=*|*.) ;; | |
*) c="$c " ;; | |
esac | |
array[${#array[@]}+1]="$c" | |
done | |
compset -P '*[=:]' | |
compadd -Q -S '' -p "${2-}" -a -- array && _ret=0 | |
;; | |
esac | |
} | |
__gitcomp_direct () | |
{ | |
emulate -L zsh | |
local IFS=$'\n' | |
compset -P '*[=:]' | |
compadd -Q -- ${=1} && _ret=0 | |
} | |
__gitcomp_nl () | |
{ | |
emulate -L zsh | |
local IFS=$'\n' | |
compset -P '*[=:]' | |
compadd -Q -S "${4- }" -p "${2-}" -- ${=1} && _ret=0 | |
} | |
__gitcomp_file_direct () | |
{ | |
emulate -L zsh | |
local IFS=$'\n' | |
compset -P '*[=:]' | |
compadd -f -- ${=1} && _ret=0 | |
} | |
__gitcomp_file () | |
{ | |
emulate -L zsh | |
local IFS=$'\n' | |
compset -P '*[=:]' | |
compadd -p "${2-}" -f -- ${=1} && _ret=0 | |
} | |
_git () | |
{ | |
local _ret=1 cur cword prev | |
cur=${words[CURRENT]} | |
prev=${words[CURRENT-1]} | |
let cword=CURRENT-1 | |
emulate ksh -c __${service}_main | |
let _ret && _default && _ret=0 | |
return _ret | |
} | |
compdef _git git gitk | |
return | |
fi | |
__git_func_wrap () | |
{ | |
local cur words cword prev | |
_get_comp_words_by_ref -n =: cur words cword prev | |
$1 | |
} | |
# Setup completion for certain functions defined above by setting common | |
# variables and workarounds. | |
# This is NOT a public function; use at your own risk. | |
__git_complete () | |
{ | |
local wrapper="__git_wrap${2}" | |
eval "$wrapper () { __git_func_wrap $2 ; }" | |
complete -o bashdefault -o default -o nospace -F $wrapper $1 2>/dev/null \ | |
|| complete -o default -o nospace -F $wrapper $1 | |
} | |
# wrapper for backwards compatibility | |
_git () | |
{ | |
__git_wrap__git_main | |
} | |
# wrapper for backwards compatibility | |
_gitk () | |
{ | |
__git_wrap__gitk_main | |
} | |
__git_complete git __git_main | |
__git_complete gitk __gitk_main | |
# The following are necessary only for Cygwin, and only are needed | |
# when the user has tab-completed the executable name and consequently | |
# included the '.exe' suffix. | |
# | |
if [ Cygwin = "$(uname -o 2>/dev/null)" ]; then | |
__git_complete git.exe __git_main | |
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/etc/bash_completion.d/ssh.sh | |
_ssh() | |
{ | |
local cur prev opts | |
COMPREPLY=() | |
cur="${COMP_WORDS[COMP_CWORD]}" | |
prev="${COMP_WORDS[COMP_CWORD-1]}" | |
opts=$(grep '^Host' ~/.ssh/config ~/.ssh/config.d/* 2>/dev/null | grep -v '[?*]' | cut -d ' ' -f 2-) | |
COMPREPLY=( $(compgen -W "$opts" -- ${cur}) ) | |
return 0 | |
} | |
complete -F _ssh ssh |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment