aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/completion/git-completion.bash
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/completion/git-completion.bash')
-rw-r--r--contrib/completion/git-completion.bash145
1 files changed, 124 insertions, 21 deletions
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index ba5c395d2d..e21a39b406 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -28,6 +28,8 @@
# 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 ; ... '".
+# Note that "git" is optional --- '!f() { : commit; ...}; f' would complete
+# just like the 'git commit' command.
#
# If you have a command that is not part of git, but you would still
# like completion, you can use __git_complete:
@@ -58,6 +60,12 @@
#
# When set to "1" suggest all options, including options which are
# typically hidden (e.g. '--allow-empty' for 'git commit').
+#
+# GIT_COMPLETION_IGNORE_CASE
+#
+# When set, uses for-each-ref '--ignore-case' to find refs that match
+# case insensitively, even on systems with case sensitive file systems
+# (e.g., completing tag name "FOO" on "git checkout f<TAB>").
case "$COMP_WORDBREAKS" in
*:*) : great ;;
@@ -114,6 +122,38 @@ __git ()
${__git_dir:+--git-dir="$__git_dir"} "$@" 2>/dev/null
}
+# 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.
+#
+# This is taken from git-prompt.sh.
+__git_eread ()
+{
+ test -r "$1" && IFS=$'\r\n' read -r "$2" <"$1"
+}
+
+# Runs git in $__git_repo_path to determine whether a pseudoref exists.
+# 1: The pseudo-ref to search
+__git_pseudoref_exists ()
+{
+ local ref=$1
+
+ # If the reftable is in use, we have to shell out to 'git rev-parse'
+ # to determine whether the ref exists instead of looking directly in
+ # the filesystem to determine whether the ref exists. Otherwise, use
+ # Bash builtins since executing Git commands are expensive on some
+ # platforms.
+ if __git_eread "$__git_repo_path/HEAD" head; then
+ b="${head#ref: }"
+ if [ "$b" == "refs/heads/.invalid" ]; then
+ __git -C "$__git_repo_path" rev-parse --verify --quiet "$ref" 2>/dev/null
+ return $?
+ fi
+ fi
+
+ [ -f "$__git_repo_path/$ref" ]
+}
+
# Removes backslash escaping, single quotes and double quotes from a word,
# stores the result in the variable $dequoted_word.
# 1: The word to dequote.
@@ -646,6 +686,7 @@ __git_heads ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/heads/$cur_*" "refs/heads/$cur_*/**"
}
@@ -659,6 +700,7 @@ __git_remote_heads ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/$cur_*" "refs/remotes/$cur_*/**"
}
@@ -669,6 +711,7 @@ __git_tags ()
local pfx="${1-}" cur_="${2-}" sfx="${3-}"
__git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/tags/$cur_*" "refs/tags/$cur_*/**"
}
@@ -688,6 +731,7 @@ __git_dwim_remote_heads ()
# but only output if the branch name is unique
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
--sort="refname:strip=3" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \
uniq -u
}
@@ -712,6 +756,7 @@ __git_refs ()
local format refs
local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}"
local match="${4-}"
+ local umatch="${4-}"
local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers
__git_find_repo_path
@@ -735,12 +780,19 @@ __git_refs ()
fi
fi
+ if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1"
+ then
+ # uppercase with tr instead of ${match,^^} for bash 3.2 compatibility
+ umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match")
+ fi
+
if [ "$list_refs_from" = path ]; then
if [[ "$cur_" == ^* ]]; then
pfx="$pfx^"
fer_pfx="$fer_pfx^"
cur_=${cur_#^}
match=${match#^}
+ umatch=${umatch#^}
fi
case "$cur_" in
refs|refs/*)
@@ -749,9 +801,9 @@ __git_refs ()
track=""
;;
*)
- for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do
+ for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD REVERT_HEAD BISECT_HEAD AUTO_MERGE; do
case "$i" in
- $match*)
+ $match*|$umatch*)
if [ -e "$dir/$i" ]; then
echo "$pfx$i$sfx"
fi
@@ -765,6 +817,7 @@ __git_refs ()
;;
esac
__git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"${refs[@]}"
if [ -n "$track" ]; then
__git_dwim_remote_heads "$pfx" "$match" "$sfx"
@@ -784,15 +837,16 @@ __git_refs ()
*)
if [ "$list_refs_from" = remote ]; then
case "HEAD" in
- $match*) echo "${pfx}HEAD$sfx" ;;
+ $match*|$umatch*) echo "${pfx}HEAD$sfx" ;;
esac
__git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \
+ ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \
"refs/remotes/$remote/$match*" \
"refs/remotes/$remote/$match*/**"
else
local query_symref
case "HEAD" in
- $match*) query_symref="HEAD" ;;
+ $match*|$umatch*) query_symref="HEAD" ;;
esac
__git ls-remote "$remote" $query_symref \
"refs/tags/$match*" "refs/heads/$match*" \
@@ -1162,7 +1216,7 @@ __git_aliased_command ()
:) : skip null command ;;
\'*) : skip opening quote after sh -c ;;
*)
- cur="$word"
+ cur="${word%;}"
break
esac
done
@@ -1587,7 +1641,7 @@ _git_checkout ()
if [ -n "$(__git_find_on_cmdline "-b -B -d --detach --orphan")" ]; then
__git_complete_refs --mode="refs"
- elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+ elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
__git_complete_refs --mode="remote-heads"
else
__git_complete_refs $dwim_opt --mode="refs"
@@ -1603,7 +1657,7 @@ __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
+ if __git_pseudoref_exists CHERRY_PICK_HEAD; then
__gitcomp "$__git_cherry_pick_inprogress_options"
return
fi
@@ -1657,6 +1711,11 @@ _git_clone ()
__git_untracked_file_modes="all no normal"
+__git_trailer_tokens ()
+{
+ __git config --name-only --get-regexp '^trailer\..*\.key$' | cut -d. -f 2- | rev | cut -d. -f2- | rev
+}
+
_git_commit ()
{
case "$prev" in
@@ -1681,6 +1740,10 @@ _git_commit ()
__gitcomp "$__git_untracked_file_modes" "" "${cur##--untracked-files=}"
return
;;
+ --trailer=*)
+ __gitcomp_nl "$(__git_trailer_tokens)" "" "${cur##--trailer=}" ":"
+ return
+ ;;
--*)
__gitcomp_builtin commit
return
@@ -1713,32 +1776,44 @@ __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_ws_error_highlight_opts="context old new all default"
+
+# Options for the diff machinery (diff, log, show, stash, range-diff, ...)
__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 --find-object --find-renames
+ --no-relative --relative
--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
+ --quiet --ext-diff --no-ext-diff --unified=
--no-prefix --src-prefix= --dst-prefix=
- --inter-hunk-context=
+ --inter-hunk-context= --function-context
--patience --histogram --minimal
--raw --word-diff --word-diff-regex=
--dirstat --dirstat= --dirstat-by-file
--dirstat-by-file= --cumulative
- --diff-algorithm=
+ --diff-algorithm= --default-prefix
--submodule --submodule= --ignore-submodules
--indent-heuristic --no-indent-heuristic
- --textconv --no-textconv
- --patch --no-patch
- --anchored=
+ --textconv --no-textconv --break-rewrites
+ --patch --no-patch --cc --combined-all-paths
+ --anchored= --compact-summary --ignore-matching-lines=
+ --irreversible-delete --line-prefix --no-stat
+ --output= --output-indicator-context=
+ --output-indicator-new= --output-indicator-old=
+ --ws-error-highlight=
+ --pickaxe-all --pickaxe-regex
"
-__git_diff_difftool_options="--cached --staged --pickaxe-all --pickaxe-regex
- --base --ours --theirs --no-index --relative --merge-base
+# Options for diff/difftool
+__git_diff_difftool_options="--cached --staged
+ --base --ours --theirs --no-index --merge-base
+ --ita-invisible-in-index --ita-visible-in-index
$__git_diff_common_options"
_git_diff ()
@@ -1762,6 +1837,10 @@ _git_diff ()
__gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}"
return
;;
+ --ws-error-highlight=*)
+ __gitcomp "$__git_ws_error_highlight_opts" "" "${cur##--ws-error-highlight=}"
+ return
+ ;;
--*)
__gitcomp "$__git_diff_difftool_options"
return
@@ -2004,6 +2083,12 @@ __git_log_shortlog_options="
--author= --committer= --grep=
--all-match --invert-grep
"
+# Options accepted by log and show
+__git_log_show_options="
+ --diff-merges --diff-merges= --no-diff-merges --dd --remerge-diff
+"
+
+__git_diff_merges_opts="off none on first-parent 1 separate m combined c dense-combined cc remerge r"
__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 human raw unix auto: format:"
@@ -2014,7 +2099,7 @@ _git_log ()
__git_find_repo_path
local merge=""
- if [ -f "$__git_repo_path/MERGE_HEAD" ]; then
+ if __git_pseudoref_exists MERGE_HEAD; then
merge="--merge"
fi
case "$prev,$cur" in
@@ -2052,15 +2137,24 @@ _git_log ()
__gitcomp "$__git_diff_submodule_formats" "" "${cur##--submodule=}"
return
;;
+ --ws-error-highlight=*)
+ __gitcomp "$__git_ws_error_highlight_opts" "" "${cur##--ws-error-highlight=}"
+ return
+ ;;
--no-walk=*)
__gitcomp "sorted unsorted" "" "${cur##--no-walk=}"
return
;;
+ --diff-merges=*)
+ __gitcomp "$__git_diff_merges_opts" "" "${cur##--diff-merges=}"
+ return
+ ;;
--*)
__gitcomp "
$__git_log_common_options
$__git_log_shortlog_options
$__git_log_gitk_options
+ $__git_log_show_options
--root --topo-order --date-order --reverse
--follow --full-diff
--abbrev-commit --no-abbrev-commit --abbrev=
@@ -2077,7 +2171,6 @@ _git_log ()
--expand-tabs --expand-tabs= --no-expand-tabs
$merge
$__git_diff_common_options
- --pickaxe-all --pickaxe-regex
"
return
;;
@@ -2464,7 +2557,7 @@ _git_switch ()
if [ -n "$(__git_find_on_cmdline "-c -C -d --detach")" ]; then
__git_complete_refs --mode="refs"
- elif [ -n "$(__git_find_on_cmdline "--track")" ]; then
+ elif [ -n "$(__git_find_on_cmdline "-t --track")" ]; then
__git_complete_refs --mode="remote-heads"
else
__git_complete_refs $dwim_opt --mode="heads"
@@ -2873,6 +2966,7 @@ _git_reset ()
_git_restore ()
{
+ __git_find_repo_path
case "$prev" in
-s)
__git_complete_refs
@@ -2891,7 +2985,7 @@ _git_restore ()
__gitcomp_builtin restore
;;
*)
- if __git rev-parse --verify --quiet HEAD >/dev/null; then
+ if __git_pseudoref_exists HEAD; then
__git_complete_index_file "--modified"
fi
esac
@@ -2902,7 +2996,7 @@ __git_revert_inprogress_options=$__git_sequencer_inprogress_options
_git_revert ()
{
__git_find_repo_path
- if [ -f "$__git_repo_path"/REVERT_HEAD ]; then
+ if __git_pseudoref_exists REVERT_HEAD; then
__gitcomp "$__git_revert_inprogress_options"
return
fi
@@ -2972,10 +3066,19 @@ _git_show ()
__gitcomp "$__git_color_moved_ws_opts" "" "${cur##--color-moved-ws=}"
return
;;
+ --ws-error-highlight=*)
+ __gitcomp "$__git_ws_error_highlight_opts" "" "${cur##--ws-error-highlight=}"
+ return
+ ;;
+ --diff-merges=*)
+ __gitcomp "$__git_diff_merges_opts" "" "${cur##--diff-merges=}"
+ return
+ ;;
--*)
__gitcomp "--pretty= --format= --abbrev-commit --no-abbrev-commit
--oneline --show-signature
--expand-tabs --expand-tabs= --no-expand-tabs
+ $__git_log_show_options
$__git_diff_common_options
"
return
@@ -3522,7 +3625,7 @@ __gitk_main ()
__git_find_repo_path
local merge=""
- if [ -f "$__git_repo_path/MERGE_HEAD" ]; then
+ if __git_pseudoref_exists MERGE_HEAD; then
merge="--merge"
fi
case "$cur" in