最近優達把《如何使用Git和GitHub》這門課設置爲免費課程,藉此機會我也去學習了一波,以便能加入全球最大的同性交友網站。如下內容,均爲聽課筆記。總共分爲三部分這是第一部分。 (請注意:在這篇文章中沒有講授怎樣建立一個版本庫,主要講解了幾個git中經常使用的命令以及一些基礎設置。建立版本庫內容在第二篇文章中連接:https://www.cnblogs.com/lizhe-Ning/p/9231677.html)html
首先這裏再明確一下,全部的版本控制系統,其實只能跟蹤文本文件的改動,好比TXT文件,網頁,全部的程序代碼等等,Git也不例外。版本控制系統能夠告訴你每次的改動,好比在第5行加了一個單詞「Linux」,在第8行刪了一個單詞「Windows」。而圖片、視頻這些二進制文件,雖然也能由版本控制系統管理,但無法跟蹤文件的變化,只能把二進制文件每次改動串起來,也就是隻知道圖片從100KB改爲了120KB,但到底改了啥,版本控制系統不知道,也無法知道。node
不幸的是,Microsoft的Word格式是二進制格式,所以,版本控制系統是無法跟蹤Word文件的改動的,若是要真正使用版本控制系統,就要以純文本方式編寫文件。若是想了解這方面內容建議閱讀http://blog.martinfenner.org/2014/08/18/introducing-rakali/或者使用https://www.simuldocs.com/,必須說明的是,我也沒用過,正在嘗試。還不知道怎麼樣。c++
由於文本是有編碼的,好比中文有經常使用的GBK編碼,日文有Shift_JIS編碼,若是沒有歷史遺留問題,強烈建議使用標準的UTF-8編碼,全部語言使用同一種編碼,既沒有衝突,又被全部平臺所支持。git
使用Windows的童鞋要特別注意:web
千萬不要使用Windows自帶的記事本編輯任何文本文件。緣由是Microsoft開發記事本的團隊使用了一個很是弱智的行爲來保存UTF-8編碼的文件,他們自做聰明地在每一個文件開頭添加了0xefbbbf(十六進制)的字符,你會遇到不少難以想象的問題,好比,網頁第一行可能會顯示一個「?」,明明正確的程序一編譯就報語法錯誤,等等,都是由記事本的弱智行爲帶來的。建議你下載Notepad++代替記事本,不但功能強大,並且免費!記得把Notepad++的默認編碼設置爲UTF-8 without BOM便可,將notepad++設置爲git默認的文本編輯器的方法在下面會講到,具體位置在代碼段一後面的一小段說明性文字中。redis
——以上內容部分摘自廖雪峯老師的教程,在此表示感謝。shell
在編程或者進行工程任務時,保存舊的版本也許是一個好習慣,尤爲是在糾正錯誤方面,不一樣版本之間造成對比,不一樣之處極可能有問題。
系統自帶的文件對照工具:express
git中一項很重要的功能就是文件的對照,在開始git以前先看一下系統自帶的文件對照工具。
不一樣系統中對比文件的不一樣用不一樣的工具,在Windows中使用FC(file compare),在mac和Linux中使用Diff(difference)。編程
注意:vim
Git的一些概念:
commit id
(版本號),和SVN不同,Git的commit id
不是1,2,3……遞增的數字,而是一個SHA1計算出來的一個很是大的數字,用十六進制表示,並且你看到的commit id
和個人確定不同,以你本身的爲準。爲何commit id
須要用這麼一大串數字表示呢?由於Git是分佈式的版本控制系統,後面咱們還要研究多人在同一個版本庫裏工做,若是你們都用1,2,3……做爲版本號,那確定就衝突了。每提交一個新版本,實際上Git就會把它們自動串成一條時間線。若是使用可視化工具查看Git歷史,就能夠更清楚地看到提交歷史的時間線可使用命令:git log --graph
Git的簡單使用
--stat選項會給出,每次提交所更改文件的統計數據。會顯示每一次更改所每一個文件內容變化數目。
注:如下設置均爲Windows下的設置,mac和Linux下設置方式可能會有所不一樣。建議觀看https://classroom.udacity.com/courses/ud775/lessons/2980038599/concepts/33331589510923課程進行學習後進行實踐。
同時必須指出這些命令實在Git Bash中使用的,爲了便於觀察、使用,須要對配置文件進行一些設置,在主目錄(通常是C:\Users\(本機用戶名))下找到名爲.bash_profile,可是一般狀況下,這個文件是隱藏的,在windows中上方選項卡中「查看」勾選「隱藏的項目」。若是沒有發現名爲.bash_profile的文件能夠新建一個記事本,在把他名字改爲.bash_profile。這是Git Bash的配置文件,每次啓動都會加載。用記事本打開並加入如下內容
代碼段一 .bash_profile文件添加內容
# Enable tab completion source ~/git-completion.bash # colors! green="\[\033[0;32m\]" blue="\[\033[0;34m\]" purple="\[\033[0;35m\]" reset="\[\033[0m\]" # Change command prompt source ~/git-prompt.sh export GIT_PS1_SHOWDIRTYSTATE=1 # '\u' adds the name of the current user to the prompt # '\$(__git_ps1)' adds git-related stuff # '\W' adds the name of the current directory export PS1="$purple\u$green\$(__git_ps1)$blue \W $ $reset" alias notepad="/E/Program\ Files\ \(x86\)/Notepad++/notepad++.exe"
第一段是一個自動填充功能,寫出前兩個字母按tab鍵能夠實現自動填充,填充的須要加載資源git-completion.bash,我將在下文代碼段二給出。第二段是顏色設置將用戶名設置爲紫色,當前所在目錄設置爲藍色,當前提交(commit)ID設置綠色,diff中「-」行是紅色,「+」行是綠色。第四段是改變一些命令,須要加載資源文件git-prompt.sh,我將在下文代碼段三中給出。最後一段是我本身寫的,我最經常使用的文本編輯器是notepad++,他安裝在E:\Program Files (x86)\Notepad++目錄下,爲了方便調用,我將notepad設置爲啓動notepad++的別名,每次只須要在Bash中輸入「notepad 文件名」,便可使用notepad打開相應文件。其餘文本編輯器也能夠進行類似設置。
同時在Git Bash中進行如下設置,雖然我如今還沒查明白這是幹嗎的,下節課可能就懂了吧。
git config --global core.editor "'E:/Program Files (X86)/Notepad++/notepad++.exe' -n -w" git config --global push.default upstream git config --global merge.conflictstyle diff3
如下這兩個文件必須放在主目錄下,建立方法同.bash_profile。
代碼段二 git-completion.bash中內容
# bash/zsh completion support for core Git. # # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org> # 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 # completion (e.g., completing "foo" when "origin/foo" exists). 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 <ian@caliban.org> # © 2009-2010, Bash Completion Maintainers # <bash-completion-devel@lists.alioth.debian.org> # # 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 --*=) ;; *) local c i=0 IFS=$' \t\n' for c in $1; do 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=" $(__git ${cmd/_/ } --git-completion-helper) $incl " 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 componens. __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 direcory # 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 cant 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 isnt 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_complete_revlist_file () { local pfx ls ref cur_="$cur" case "$cur_" in *..?*:*) return ;; ?*:*) ref="${cur_%%:*}" cur_="${cur_#*:}" case "$cur_" in ?*/*) pfx="${cur_%/*}" cur_="${cur_##*/}" ls="$ref:$pfx" pfx="$pfx/" ;; *) ls="$ref" ;; esac case "$COMP_WORDBREAKS" in *:*) : great ;; *) pfx="$ref:$pfx" ;; esac __gitcomp_nl "$(__git ls-tree "$ls" \ | sed '/^100... blob /{ s,^.* ,, s,$, , } /^120000 blob /{ s,^.* ,, s,$, , } /^040000 tree /{ s,^.* ,, 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 ;; -*) ;; *) 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 esac case "$cur" in --strategy=*) __gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}" 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 } # __git_find_on_cmdline requires 1 argument __git_find_on_cmdline () { local word subcommand c=1 while [ $c -lt $cword ]; do word="${words[c]}" for subcommand in $1; do if [ "$subcommand" = "$word" ]; then echo "$subcommand" 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_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 ;; --*) __gitcomp_builtin am "--no-utf8" \ "$__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 --*) __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 " --format= --list --verbose --prefix= --remote= --exec= --output " 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_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 "--no-color --no-abbrev --no-track --no-column " ;; *) 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 "--no-track --no-recurse-submodules" ;; *) # 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_cherry () { case "$cur" in --*) __gitcomp_builtin cherry return esac __git_complete_refs } __git_cherry_pick_inprogress_options="--continue --quit --abort" _git_cherry_pick () { __git_find_repo_path if [ -f "$__git_repo_path"/CHERRY_PICK_HEAD ]; then __gitcomp "$__git_cherry_pick_inprogress_options" return fi 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 "$cur" in --*) __gitcomp_builtin clone "--no-single-branch" 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 "--no-edit --verify" 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_diff_common_options="--stat --numstat --shortstat --summary --patch-with-stat --name-only --name-status --color --no-color --color-words --no-renames --check --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 " _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 ;; --*) __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 " _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 ;; --*) __gitcomp_builtin fetch "--no-tags" return ;; esac __git_complete_remote_or_refspec } __git_format_patch_options=" --stdout --attach --no-attach --thread --thread= --no-thread --numbered --start-number --numbered-files --keep-subject --signoff --signature --no-signature --in-reply-to= --cc= --full-index --binary --not --all --cover-letter --no-prefix --src-prefix= --dst-prefix= --inline --suffix= --ignore-if-in-upstream --subject-prefix= --output-directory --reroll-count --to= --quiet --notes " _git_format_patch () { case "$cur" in --thread=*) __gitcomp " deep shallow " "" "${cur##--thread=}" return ;; --*) __gitcomp "$__git_format_patch_options" return ;; esac __git_complete_revlist } _git_fsck () { case "$cur" in --*) __gitcomp_builtin fsck "--no-reflogs" 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 "--no-empty-directory" 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 email raw format:" __git_log_date_formats="relative iso8601 rfc2822 short local default raw" _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 ;; --*) __gitcomp " $__git_log_common_options $__git_log_shortlog_options $__git_log_gitk_options --root --topo-order --date-order --reverse --follow --full-diff --abbrev-commit --abbrev= --relative-date --date= --pretty= --format= --oneline --show-signature --cherry-mark --cherry-pick --graph --decorate --decorate= --walk-reflogs --parents --children $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 "--no-rerere-autoupdate --no-commit --no-edit --no-ff --no-log --no-progress --no-squash --no-stat --no-verify-signatures " return esac __git_complete_refs } _git_mergetool () { case "$cur" in --tool=*) __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}" return ;; --*) __gitcomp "--tool= --prompt --no-prompt" 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 "--no-autostash --no-commit --no-edit --no-ff --no-log --no-progress --no-rebase --no-squash --no-stat --no-tags --no-verify-signatures" 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_rebase () { __git_find_repo_path if [ -f "$__git_repo_path"/rebase-merge/interactive ]; then __gitcomp "--continue --skip --abort --quit --edit-todo --show-current-patch" return elif [ -d "$__git_repo_path"/rebase-apply ] || \ [ -d "$__git_repo_path"/rebase-merge ]; then __gitcomp "--continue --skip --abort --quit --show-current-patch" return fi __git_complete_strategy && return case "$cur" in --whitespace=*) __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" return ;; --*) __gitcomp " --onto --merge --strategy --interactive --rebase-merges --preserve-merges --stat --no-stat --committer-date-is-author-date --ignore-date --ignore-whitespace --whitespace= --autosquash --no-autosquash --fork-point --no-fork-point --autostash --no-autostash --verify --no-verify --keep-empty --root --force-rebase --no-ff --rerere-autoupdate --exec " 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 "--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_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 "--no-column" 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_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 () { case "$prev" in branch.*.remote|branch.*.pushremote) __gitcomp_nl "$(__git_remotes)" return ;; branch.*.merge) __git_complete_refs return ;; branch.*.rebase) __gitcomp "false true merges preserve interactive" return ;; remote.pushdefault) __gitcomp_nl "$(__git_remotes)" return ;; remote.*.fetch) local remote="${prev#remote.}" remote="${remote%.fetch}" if [ -z "$cur" ]; then __gitcomp_nl "refs/heads/" "" "" "" return fi __gitcomp_nl "$(__git_refs_remotes "$remote")" return ;; remote.*.push) local remote="${prev#remote.}" remote="${remote%.push}" __gitcomp_nl "$(__git for-each-ref \ --format='%(refname):%(refname)' refs/heads)" return ;; pull.twohead|pull.octopus) __git_compute_merge_strategies __gitcomp "$__git_merge_strategies" return ;; color.branch|color.diff|color.interactive|\ color.showbranch|color.status|color.ui) __gitcomp "always never auto" return ;; color.pager) __gitcomp "false true" return ;; color.*.*) __gitcomp " normal black red green yellow blue magenta cyan white bold dim ul blink reverse " return ;; diff.submodule) __gitcomp "log short" return ;; help.format) __gitcomp "man info web html" return ;; log.date) __gitcomp "$__git_log_date_formats" return ;; sendemail.aliasfiletype) __gitcomp "mutt mailrc pine elm gnus" return ;; sendemail.confirm) __gitcomp "$__git_send_email_confirm_options" return ;; sendemail.suppresscc) __gitcomp "$__git_send_email_suppresscc_options" return ;; sendemail.transferencoding) __gitcomp "7bit 8bit quoted-printable base64" return ;; --get|--get-all|--unset|--unset-all) __gitcomp_nl "$(__git_config_get_set_variables)" return ;; *.*) return ;; esac case "$cur" in --*) __gitcomp_builtin config return ;; branch.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp "remote pushremote merge mergeoptions rebase" "$pfx" "$cur_" return ;; branch.*) local pfx="${cur%.*}." cur_="${cur#*.}" __gitcomp_direct "$(__git_heads "$pfx" "$cur_" ".")" __gitcomp_nl_append $'autosetupmerge\nautosetuprebase\n' "$pfx" "$cur_" return ;; guitool.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp " argprompt cmd confirm needsfile noconsole norescan prompt revprompt revunmerged title " "$pfx" "$cur_" return ;; difftool.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp "cmd path" "$pfx" "$cur_" return ;; man.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp "cmd path" "$pfx" "$cur_" return ;; mergetool.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp "cmd path trustExitCode" "$pfx" "$cur_" return ;; pager.*) local pfx="${cur%.*}." cur_="${cur#*.}" __git_compute_all_commands __gitcomp_nl "$__git_all_commands" "$pfx" "$cur_" return ;; remote.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp " url proxy fetch push mirror skipDefaultUpdate receivepack uploadpack tagopt pushurl " "$pfx" "$cur_" return ;; remote.*) local pfx="${cur%.*}." cur_="${cur#*.}" __gitcomp_nl "$(__git_remotes)" "$pfx" "$cur_" "." __gitcomp_nl_append "pushdefault" "$pfx" "$cur_" return ;; url.*.*) local pfx="${cur%.*}." cur_="${cur##*.}" __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur_" return ;; esac __gitcomp " add.ignoreErrors advice.amWorkDir advice.commitBeforeMerge advice.detachedHead advice.implicitIdentity advice.pushAlreadyExists advice.pushFetchFirst advice.pushNeedsForce advice.pushNonFFCurrent advice.pushNonFFMatching advice.pushUpdateRejected advice.resolveConflict advice.rmHints advice.statusHints advice.statusUoption advice.ignoredHook alias. am.keepcr am.threeWay apply.ignorewhitespace apply.whitespace branch.autosetupmerge branch.autosetuprebase browser. clean.requireForce color.branch color.branch.current color.branch.local color.branch.plain color.branch.remote color.decorate.HEAD color.decorate.branch color.decorate.remoteBranch color.decorate.stash color.decorate.tag color.diff color.diff.commit color.diff.frag color.diff.func color.diff.meta color.diff.new color.diff.old color.diff.plain color.diff.whitespace color.grep color.grep.context color.grep.filename color.grep.function color.grep.linenumber color.grep.match color.grep.selected color.grep.separator color.interactive color.interactive.error color.interactive.header color.interactive.help color.interactive.prompt color.pager color.showbranch color.status color.status.added color.status.changed color.status.header color.status.localBranch color.status.nobranch color.status.remoteBranch color.status.unmerged color.status.untracked color.status.updated color.ui commit.cleanup commit.gpgSign commit.status commit.template commit.verbose core.abbrev core.askpass core.attributesfile core.autocrlf core.bare core.bigFileThreshold core.checkStat core.commentChar core.commitGraph core.compression core.createObject core.deltaBaseCacheLimit core.editor core.eol core.excludesfile core.fileMode core.fsyncobjectfiles core.gitProxy core.hideDotFiles core.hooksPath core.ignoreStat core.ignorecase core.logAllRefUpdates core.loosecompression core.notesRef core.packedGitLimit core.packedGitWindowSize core.packedRefsTimeout core.pager core.precomposeUnicode core.preferSymlinkRefs core.preloadindex core.protectHFS core.protectNTFS core.quotepath core.repositoryFormatVersion core.safecrlf core.sharedRepository core.sparseCheckout core.splitIndex core.sshCommand core.symlinks core.trustctime core.untrackedCache core.warnAmbiguousRefs core.whitespace core.worktree credential.helper credential.useHttpPath credential.username credentialCache.ignoreSIGHUP diff.autorefreshindex diff.external diff.ignoreSubmodules diff.mnemonicprefix diff.noprefix diff.renameLimit diff.renames diff.statGraphWidth diff.submodule diff.suppressBlankEmpty diff.tool diff.wordRegex diff.algorithm difftool. difftool.prompt fetch.recurseSubmodules fetch.unpackLimit format.attach format.cc format.coverLetter format.from format.headers format.numbered format.pretty format.signature format.signoff format.subjectprefix format.suffix format.thread format.to gc. gc.aggressiveDepth gc.aggressiveWindow gc.auto gc.autoDetach gc.autopacklimit gc.logExpiry gc.packrefs gc.pruneexpire gc.reflogexpire gc.reflogexpireunreachable gc.rerereresolved gc.rerereunresolved gc.worktreePruneExpire gitcvs.allbinary gitcvs.commitmsgannotation gitcvs.dbTableNamePrefix gitcvs.dbdriver gitcvs.dbname gitcvs.dbpass gitcvs.dbuser gitcvs.enabled gitcvs.logfile gitcvs.usecrlfattr guitool. gui.blamehistoryctx gui.commitmsgwidth gui.copyblamethreshold gui.diffcontext gui.encoding gui.fastcopyblame gui.matchtrackingbranch gui.newbranchtemplate gui.pruneduringfetch gui.spellingdictionary gui.trustmtime help.autocorrect help.browser help.format http.lowSpeedLimit http.lowSpeedTime http.maxRequests http.minSessions http.noEPSV http.postBuffer http.proxy http.sslCipherList http.sslVersion http.sslCAInfo http.sslCAPath http.sslCert http.sslCertPasswordProtected http.sslKey http.sslVerify http.useragent i18n.commitEncoding i18n.logOutputEncoding imap.authMethod imap.folder imap.host imap.pass imap.port imap.preformattedHTML imap.sslverify imap.tunnel imap.user init.templatedir instaweb.browser instaweb.httpd instaweb.local instaweb.modulepath instaweb.port interactive.singlekey log.date log.decorate log.showroot mailmap.file man. man.viewer merge. merge.conflictstyle merge.log merge.renameLimit merge.renormalize merge.stat merge.tool merge.verbosity mergetool. mergetool.keepBackup mergetool.keepTemporaries mergetool.prompt notes.displayRef notes.rewrite. notes.rewrite.amend notes.rewrite.rebase notes.rewriteMode notes.rewriteRef pack.compression pack.deltaCacheLimit pack.deltaCacheSize pack.depth pack.indexVersion pack.packSizeLimit pack.threads pack.window pack.windowMemory pager. pretty. pull.octopus pull.twohead push.default push.followTags rebase.autosquash rebase.stat receive.autogc receive.denyCurrentBranch receive.denyDeleteCurrent receive.denyDeletes receive.denyNonFastForwards receive.fsckObjects receive.unpackLimit receive.updateserverinfo remote.pushdefault remotes. repack.usedeltabaseoffset rerere.autoupdate rerere.enabled sendemail. sendemail.aliasesfile sendemail.aliasfiletype sendemail.bcc sendemail.cc sendemail.cccmd sendemail.chainreplyto sendemail.confirm sendemail.envelopesender sendemail.from sendemail.identity sendemail.multiedit sendemail.signedoffbycc sendemail.smtpdomain sendemail.smtpencryption sendemail.smtppass sendemail.smtpserver sendemail.smtpserveroption sendemail.smtpserverport sendemail.smtpuser sendemail.suppresscc sendemail.suppressfrom sendemail.thread sendemail.to sendemail.tocmd sendemail.validate sendemail.smtpbatchsize sendemail.smtprelogindelay showbranch.default status.relativePaths status.showUntrackedFiles status.submodulesummary submodule. tar.umask transfer.unpackLimit url. user.email user.name user.signingkey web.browser branch. remote. " } _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 "--no-tags" ;; 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_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 --*) __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_revert_inprogress_options="--continue --quit --abort" _git_revert () { __git_find_repo_path if [ -f "$__git_repo_path"/REVERT_HEAD ]; then __gitcomp "$__git_revert_inprogress_options" return fi case "$cur" in --*) __gitcomp_builtin revert "--no-edit" \ "$__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 --oneline --show-signature $__git_diff_common_options " return ;; esac __git_complete_revlist_file } _git_show_branch () { case "$cur" in --*) __gitcomp_builtin show-branch "--no-color" return ;; esac __git_complete_revlist } _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" ;; 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 summary foreach sync" 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 " ;; 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 --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_worktree () { local subcommands="add list lock move prune remove unlock" local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then __gitcomp "$subcommands" else case "$subcommand,$cur" in add,--*) __gitcomp_builtin worktree_add ;; list,--*) __gitcomp_builtin worktree_list ;; lock,--*) __gitcomp_builtin worktree_lock ;; prune,--*) __gitcomp_builtin worktree_prune ;; remove,--*) __gitcomp "--force" ;; *) ;; esac fi } __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|--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-} ]]; 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 -Q -f -- ${=1} && _ret=0 } __gitcomp_file () { emulate -L zsh local IFS=$'\n' compset -P '*[=:]' compadd -Q -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
代碼段三 git-prompt.sh中內容
# bash/zsh git prompt support # # Copyright (C) 2006,2007 Shawn O. Pearce <spearce@spearce.org> # 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" } # __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 if [ -f "$g/rebase-merge/interactive" ]; then r="|REBASE-i" else r="|REBASE-m" fi 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 [ -f "$g/CHERRY_PICK_HEAD" ]; then r="|CHERRY-PICKING" elif [ -f "$g/REVERT_HEAD" ]; then r="|REVERTING" 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 }
最後感謝優達學城,提供的課程以及配套輔助學習方法,工具。課程的網站是https://classroom.udacity.com/courses/ud775,有興趣的話你們能夠一塊兒去學習。課程編排仍是不錯的,每節課內容充實,時間精簡。