From 49e167ebfd4cb480d3f2f86ba72f39777aab0fa4 Mon Sep 17 00:00:00 2001 From: Tony Duckles Date: Tue, 1 Nov 2011 22:22:56 -0500 Subject: [PATCH] New bin/git* additions and .gitconfig tweaks --- .gitconfig | 43 ++-- bin/git-big-object-report | 35 +++ bin/git-cut-branch | 64 +++++ bin/git-find-object | 28 +++ bin/git-incoming | 55 +++++ bin/git-ls-object-refs | 27 +++ bin/git-outgoing | 41 ++++ bin/git-push-log | 38 +++ bin/git-rel | 11 +- bin/git-sh | 478 ++++++++++++++++++++++++++------------ 10 files changed, 656 insertions(+), 164 deletions(-) create mode 100755 bin/git-big-object-report create mode 100755 bin/git-cut-branch create mode 100755 bin/git-find-object create mode 100755 bin/git-incoming create mode 100755 bin/git-ls-object-refs create mode 100755 bin/git-outgoing create mode 100755 bin/git-push-log diff --git a/.gitconfig b/.gitconfig index c7a4aa0..a9358ab 100644 --- a/.gitconfig +++ b/.gitconfig @@ -3,26 +3,35 @@ email = tony@nynim.org [alias] - sh = !git-sh - grab = !githug-grab - thanks = !git-thanks - cv = !git-cv - track = !git-track - ll = log --pretty=oneline --abbrev-commit --max-count=15 - review = log -p --max-count=1 - fp = format-patch --stdout - ci = commit - st = status - br = branch - co = checkout - df = diff - lg = log -p - who = shortlog -s -- - brdate = !git-brdate - subtree = !git-subtree + browse = !hub browse + w = !hub browse + compare = !hub compare + cb = !git-cut-branch + sh = !git-sh + grab = !github-grab + thanks = !git-thanks + track = !git-track + ll = log --pretty=oneline --abbrev-commit --max-count=15 + review = log -p --max-count=1 + fp = format-patch --stdout + ci = commit + st = status + br = branch + co = checkout + cv = !git-cv + lg = log -p + who = shortlog -s -- + bd = !git-brdate + bv = !git branch --color -v | cut -c1-100 + incoming = !git-incoming + in = !git-incoming + outgoing = !git-outgoing + out = !git-outgoing + subtree = !git-subtree [core] filemode = true + logallrefupdates = true whitespace = space-before-tab, trailing-space excludesfile = ~/.gitignore_global diff --git a/bin/git-big-object-report b/bin/git-big-object-report new file mode 100755 index 0000000..b56c951 --- /dev/null +++ b/bin/git-big-object-report @@ -0,0 +1,35 @@ +#!/bin/sh +# Shows you the largest objects in your repo's pack file. +# Originally written for OSX by Antony Stubbs. +# http://stubbisms.wordpress.com/2009/07/10/git +# +# POSIX compatibility by Ryan Tomayko +set -e + +# set the internal field spereator to line break, so that we can +# iterate easily over the verify-pack output +IFS=$'\n'; + +git_dir=$(git rev-parse --git-dir) + +# list all objects including their size, sort by size, take top 10 +objects=$( + git verify-pack -v "$git_dir"/objects/pack/pack-*.idx | + grep -v chain | + sort -k3nr | + head +) + +printf "%7s %7s %-7s %-20s\n" SIZE PACK SHA1 LOCATION +for y in $objects +do + size=$((`echo $y | cut -f 5 -d ' '`/1024)) + pack_size=$((`echo $y | cut -f 6 -d ' '`/1024)) + sha1=$(echo $y | cut -f 1 -d ' ') + short=$(echo "$sha1" |cut -c1-7) + path=$(git rev-list --all --objects |grep $sha1 |cut -c42-) + + printf "%7d %7d %-7s %-20s\n" "$size" "$pack_size" "$short" "$path" +done + +echo "All sizes in KB. PACK = size of compressed object in pack file." diff --git a/bin/git-cut-branch b/bin/git-cut-branch new file mode 100755 index 0000000..ba36f9c --- /dev/null +++ b/bin/git-cut-branch @@ -0,0 +1,64 @@ +#!/bin/sh +#/ Usage: git-cut-branch +#/ Create a new branch named pointed at HEAD and reset the current branch +#/ to the head of its tracking branch. This is useful when working on master and +#/ you realize you should be on a topic branch. +set -e + +# bail out with message to stderr and exit status 1 +die() { + echo "$(basename $0):" "$@" 1>&2 + exit 1 +} + +# write a short sha for the given sha +shortsha() { + echo "$1" |cut -c1-7 +} + +# show usage +[ -z "$1" -o "$1" = "--help" ] && { + grep '^#/' "$0" |cut -c4- + exit 2 +} + +# first argument is the new branch name +branch="$1" + +# get the current branch for HEAD in refs/heads/ form +ref=$(git symbolic-ref -q HEAD) +sha=$(git rev-parse HEAD) +[ -n "$ref" ] || +die "you're not on a branch" + +# just the branch name please +current=$(echo "$ref" |sed 's@^refs/heads/@@') +[ -n "$current" ] || +die "you're in a weird place; get on a local branch" + +# figure out what branch we're currently tracking +remote=$(git config --get "branch.$current.remote" || true) +merge=$(git config --get "branch.$current.merge" | sed 's@refs/heads/@@') + +# build up a sane / name +if [ -n "$remote" -a -n "$merge" ] +then tracking="$remote/$merge" +elif [ -n "$merge" ] +then tracking="$merge" +else die "$current is not tracking anything" +fi + +# make sure there's no changes before we reset hard +if ! git diff-index --quiet --cached HEAD || ! git diff-files --quiet +then die "cannot cut branch with changes to index or working directory" +fi + +# reset the current branch to its tracking branch, create the new branch also +# tracking the original branch, and switch to it. +git branch "$branch" +git reset -q --hard "$tracking" +git checkout -q "$branch" +git branch --set-upstream "$branch" "$tracking" +git reset -q --hard "$sha" +echo "[$(shortsha "$sha")...$(shortsha $(git rev-parse $tracking))] $current" +echo "[0000000...$(shortsha $(git rev-parse HEAD))] $branch" diff --git a/bin/git-find-object b/bin/git-find-object new file mode 100755 index 0000000..7edddb2 --- /dev/null +++ b/bin/git-find-object @@ -0,0 +1,28 @@ +#!/bin/sh +#/ Usage: git-find-object ... +#/ Write first that includes object . Useful when trying to locate a +#/ missing object in a list of repositories. +#/ +#/ Ex: git-find-object deadbee /repos/*.git + +# shift off the SHA1 object id to look for +sha="$1" +shift + +# usage +[ "$sha" = "--help" ] && { + grep ^#/ |cut -c4- + exit 2 +} + +# run through each repo dir and write the path to the first one +# that includes the object +for dir in "$@" +do (cd "$dir" && git cat-file -e $sha 2>/dev/null) && { + echo "$dir" + exit 0 + } +done + +# if we make it here, the object wasn't found +exit 1 diff --git a/bin/git-incoming b/bin/git-incoming new file mode 100755 index 0000000..3c5b99b --- /dev/null +++ b/bin/git-incoming @@ -0,0 +1,55 @@ +#!/bin/sh +# Usage: git-incoming [--diff] [] [ []] +# Show commits on that do not exist on current branch. + +# bail out with message to stderr and exit status 1 +die() { + echo "$(basename $0):" "$@" 1>&2 + exit 1 +} + +# colors +SHA=$(git config --get-color 'color.branch.local') +ADD=$(git config --get-color 'color.diff.new') +REM=$(git config --get-color 'color.diff.old') +RESET=$(git config --get-color '' 'reset') + +# check for -d / --diff argument +diff=false +if [ "$1" = '-d' -o "$1" = '--diff' ] +then diff=true + shift +fi + +# use tracking branch if no upstream given +if [ $# -eq 0 ] +then + # get the current branch in refs/heads/ form + ref=$(git symbolic-ref -q HEAD) + test -n "$ref" || + die "you're not on a branch" + + # just the branch name please + branch=$(echo "$ref" | sed 's@^refs/heads/@@') + test -n "$branch" || + die "you're in a weird place; get on a local branch" + + # grab remote name for current branch + remote=$(git config --get "branch.$branch.remote" || true) + + # grab tracked branch name for current branch + merge=$(git config branch.$branch.merge) || + die "branch $branch isn't tracking a remote branch and no given" + + # make it so + set -- "$remote/$(echo "$merge" |sed 's@^refs/heads/@@')" +fi + +if $diff +then git diff HEAD..."$1" +else + git cherry -v HEAD "$@" | + cut -c1-9 -c43- | + sed -e "s/^\(.\) \(.......\)/\1 $SHA\2$RESET/" | + sed -e "s/^-/$REM-$RESET/" -e "s/^+/$ADD+$RESET/" +fi diff --git a/bin/git-ls-object-refs b/bin/git-ls-object-refs new file mode 100755 index 0000000..2d2d49f --- /dev/null +++ b/bin/git-ls-object-refs @@ -0,0 +1,27 @@ +#!/bin/sh +# Usage: git-ls-object-refs +# Find references to SHA1 in refs, commits, and trees. All of them. +o="$1" + +# rawdawgn' it +set +e + +# echo "refs:" +# git show-ref |grep "$o" +# echo + +git log --all --pretty=oneline --decorate |grep "$o" | +sed 's|^\([0-9a-f]\{40\}\)|commit referenced from at least one ref: \1|' + +for ref in $(git for-each-ref --format='%(refname)') +do + (git rev-list "$ref" | grep "$o") 2>&1 | + sed "s|^[0-9a-f]\{40\}$|commit referenced from $ref|" +done + +for p in $(git rev-list --all) +do + (git ls-tree -r "$p" |grep "$o") 2>&1 | + sed "s|^|object referenced from tree of commit $p:\n|" +done +echo diff --git a/bin/git-outgoing b/bin/git-outgoing new file mode 100755 index 0000000..b0d2d3d --- /dev/null +++ b/bin/git-outgoing @@ -0,0 +1,41 @@ +#!/bin/sh +# Usage: git-outgoing [] [ []] +# Show commits on current branch that do not exist on branch . + +# bail out with message to stderr and exit status 1 +die() { + echo "$(basename $0):" "$@" 1>&2 + exit 1 +} + +# colors +SHA=$(git config --get-color 'color.branch.local') +ADD=$(git config --get-color 'color.diff.new') +REM=$(git config --get-color 'color.diff.old') +RESET=$(git config --get-color '' 'reset') + +# get the current branch in refs/heads/ form +ref=$(git symbolic-ref -q HEAD) +test -n "$ref" || +die "you're not on a branch" + +# just the branch name please +branch=$(echo "$ref" | sed 's@^refs/heads/@@') +test -n "$branch" || +die "you're in a weird place; get on a local branch" + +# use tracking branch if no upstream given +if [ $# -eq 0 ] +then + remote=$(git config --get "branch.$branch.remote" || true) + + merge=$(git config branch.$branch.merge) || + die "branch $branch isn't tracking a remote branch and no given" + + set -- "$remote/$(echo "$merge" |sed 's@^refs/heads/@@')" +fi + +git cherry -v "$@" | +cut -c1-9 -c43- | +sed -e "s/^\(.\) \(.......\)/\1 $SHA\2$RESET/" | +sed -e "s/^-/$REM-$RESET/" -e "s/^+/$ADD+$RESET/" diff --git a/bin/git-push-log b/bin/git-push-log new file mode 100755 index 0000000..a189fb9 --- /dev/null +++ b/bin/git-push-log @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby +# Usage: git-push-log +# Show reflog information for all branch heads by date. This is useful on bare +# remotes to determine when / who pushed and when. +require 'time' + +# change into git reflog dir to make everything easier +ENV['GIT_DIR'] ||= `git rev-parse --git-dir`.chomp +Dir.chdir(ENV['GIT_DIR'] + '/logs/refs/heads') + +# find all reflog files +logs = Dir['**'].select { |f| File.file?(f) } + +# build master list of all reflog entries for all refs +records = [] +logs.each do |log| + entries = File.read(log).split("\n") + entries.each do |line| + before, after, rest = line.split(' ', 3) + push_info, message = rest.split("\t", 1) + if push_info =~ /^(.*?) (<.*>) (\d+) ([0-9+-]+)/ + name, email, timestamp, offset = $1, $2, $3.to_i, $4 + date = Time.at(timestamp) + end + records << [log, before, after, name, email, date] + end +end + +# sort and output reflog entries with some formatting +begin + records = records.sort_by { |r| r.last }.reverse + records.each do |ref, before, after, name, email, date| + printf "%-20s %7s:%7s %-30s %s\n", + date.iso8601, before[0,7], after[0,7], ref, email + end +rescue Errno::EPIPE + exit 1 +end diff --git a/bin/git-rel b/bin/git-rel index 7d1bf42..b157caf 100755 --- a/bin/git-rel +++ b/bin/git-rel @@ -32,9 +32,12 @@ ref="${1:-$(tracking_branch)}" git rev-list --left-right --abbrev-commit --abbrev $ref...HEAD | cut -c1 | -sed ' +sort | +uniq -c | +tr '\n' ',' | +sed " s/>/ahead/ s//dev/null - then echo "alias $key='${command#!}'" - else echo "gitalias $key='git $command'" + then echo "alias $key='git $key'" + else echo "gitalias $key=\"git $command\"" fi done )" @@ -281,13 +283,7 @@ complete -o default -o nospace -F _git help # 2) Added the following line to your .bashrc: # source ~/.git-completion.sh # -# 3) You may want to make sure the git executable is available -# in your PATH before this script is sourced, as some caching -# is performed while the script loads. If git isn't found -# at source time then all lookups will be done on demand, -# which may be slightly slower. -# -# 4) Consider changing your PS1 to also show the current branch: +# 3) Consider changing your PS1 to also show the current branch: # PS1='[\u@\h \W$(__git_ps1 " (%s)")]\$ ' # # The argument to __git_ps1 will be displayed only if you @@ -308,6 +304,24 @@ complete -o default -o nospace -F _git help # set GIT_PS1_SHOWUNTRACKEDFILES to a nonempty value. If there're # untracked files, then a '%' will be shown next to the branch name. # +# 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, and "<>" +# indicates you have diverged. 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 +# 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 +# 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. +# +# # To submit patches: # # *) Read Documentation/SubmittingPatches @@ -344,14 +358,133 @@ __gitdir () fi } +# 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="" + + # get some config options from git-config + while read 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+="\\|$value" + upstream=svn+git # default upstream is SVN if available, else git + ;; + esac + done < <(git config -z --get-regexp '^(svn-remote\..*\.url|bash\.showupstream)$' 2>/dev/null | tr '\0\n' '\n ') + + # parse configuration values + for option in ${GIT_PS1_SHOWUPSTREAM}; do + case "$option" in + git|svn) upstream="$option" ;; + verbose) verbose=1 ;; + legacy) legacy=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 svn_upstream=($(git log --first-parent -1 \ + --grep="^git-svn-id: \(${svn_url_pattern:2}\)" 2>/dev/null)) + if [[ 0 -ne ${#svn_upstream[@]} ]]; then + svn_upstream=${svn_upstream[ ${#svn_upstream[@]} - 2 ]} + svn_upstream=${svn_upstream%@*} + for ((n=1; "$n" <= "${#svn_remote[@]}"; ++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 + "<"*) let ++behind + ;; + *) let ++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 + fi + +} + + # __git_ps1 accepts 0 or 1 arguments (i.e., format string) # returns text to add to bash PS1 prompt (includes branch name) __git_ps1 () { local g="$(__gitdir)" if [ -n "$g" ]; then - local r - local b + local r="" + local b="" if [ -f "$g/rebase-merge/interactive" ]; then r="|REBASE-i" b="$(cat "$g/rebase-merge/head-name")" @@ -393,11 +526,12 @@ __git_ps1 () } fi - local w - local i - local s - local u - local c + local w="" + local i="" + local s="" + local u="" + local c="" + local p="" if [ "true" = "$(git rev-parse --is-inside-git-dir 2>/dev/null)" ]; then if [ "true" = "$(git rev-parse --is-bare-repository 2>/dev/null)" ]; then @@ -408,11 +542,9 @@ __git_ps1 () elif [ "true" = "$(git rev-parse --is-inside-work-tree 2>/dev/null)" ]; then if [ -n "${GIT_PS1_SHOWDIRTYSTATE-}" ]; then if [ "$(git config --bool bash.showDirtyState)" != "false" ]; then - git diff --no-ext-diff --ignore-submodules \ - --quiet --exit-code || w="*" + git diff --no-ext-diff --quiet --exit-code || w="*" if git rev-parse --quiet --verify HEAD >/dev/null; then - git diff-index --cached --quiet \ - --ignore-submodules HEAD -- || i="+" + git diff-index --cached --quiet HEAD -- || i="+" else i="#" fi @@ -427,13 +559,14 @@ __git_ps1 () u="%" fi fi - fi - if [ -n "${1-}" ]; then - printf "$1" "$c${b##refs/heads/}$w$i$s$u$r" - else - printf " (%s)" "$c${b##refs/heads/}$w$i$s$u$r" + if [ -n "${GIT_PS1_SHOWUPSTREAM-}" ]; then + __git_ps1_show_upstream + fi fi + + local f="$w$i$s$u" + printf "${1:- (%s)}" "$c${b##refs/heads/}${f:+ $f}$r$p" fi } @@ -521,7 +654,9 @@ __git_refs () refs="${cur%/*}" ;; *) - if [ -e "$dir/HEAD" ]; then echo HEAD; fi + for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD; do + if [ -e "$dir/$i" ]; then echo $i; fi + done format="refname:short" refs="refs/tags refs/heads refs/remotes" ;; @@ -584,12 +719,8 @@ __git_remotes () done } -__git_merge_strategies () +__git_list_merge_strategies () { - if [ -n "${__git_merge_strategylist-}" ]; then - echo "$__git_merge_strategylist" - return - fi git merge -s help 2>&1 | sed -n -e '/[Aa]vailable strategies are: /,/^$/{ s/\.$// @@ -599,8 +730,17 @@ __git_merge_strategies () p }' } -__git_merge_strategylist= -__git_merge_strategylist=$(__git_merge_strategies 2>/dev/null) + +__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 () +{ + : ${__git_merge_strategies:=$(__git_list_merge_strategies)} +} __git_complete_file () { @@ -676,16 +816,27 @@ __git_complete_remote_or_refspec () local cur="${COMP_WORDS[COMP_CWORD]}" local i c=1 remote="" pfx="" lhs=1 no_complete_refspec=0 - # adjust args upward when completing git * - [ "$cmd" = "git" ] && { + # git-sh hack: adjust args upward when completing git * + if [ "$cmd" = "git" ] + then cmd="${COMP_WORDS[1]}" c=2 - } + fi while [ $c -lt $COMP_CWORD ]; do i="${COMP_WORDS[c]}" case "$i" in - --all|--mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;; + --mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;; + --all) + case "$cmd" in + push) no_complete_refspec=1 ;; + fetch) + COMPREPLY=() + return + ;; + *) ;; + esac + ;; -*) ;; *) remote="$i"; break ;; esac @@ -741,27 +892,24 @@ __git_complete_remote_or_refspec () __git_complete_strategy () { + __git_compute_merge_strategies case "${COMP_WORDS[COMP_CWORD-1]}" in -s|--strategy) - __gitcomp "$(__git_merge_strategies)" + __gitcomp "$__git_merge_strategies" return 0 esac local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --strategy=*) - __gitcomp "$(__git_merge_strategies)" "" "${cur##--strategy=}" + __gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}" return 0 ;; esac return 1 } -__git_all_commands () +__git_list_all_commands () { - if [ -n "${__git_all_commandlist-}" ]; then - echo "$__git_all_commandlist" - return - fi local i IFS=" "$'\n' for i in $(git help -a|egrep '^ [a-zA-Z0-9]') do @@ -771,17 +919,18 @@ __git_all_commands () esac done } -__git_all_commandlist= -__git_all_commandlist="$(__git_all_commands 2>/dev/null)" -__git_porcelain_commands () +__git_all_commands= +__git_compute_all_commands () +{ + : ${__git_all_commands:=$(__git_list_all_commands)} +} + +__git_list_porcelain_commands () { - if [ -n "${__git_porcelain_commandlist-}" ]; then - echo "$__git_porcelain_commandlist" - return - fi local i IFS=" "$'\n' - for i in "help" $(__git_all_commands) + __git_compute_all_commands + for i in "help" $__git_all_commands do case $i in *--*) : helper pattern;; @@ -833,6 +982,7 @@ __git_porcelain_commands () read-tree) : plumbing;; receive-pack) : plumbing;; reflog) : plumbing;; + remote-*) : transport;; repo-config) : deprecated;; rerere) : plumbing;; rev-list) : plumbing;; @@ -862,8 +1012,13 @@ __git_porcelain_commands () esac done } -__git_porcelain_commandlist= -__git_porcelain_commandlist="$(__git_porcelain_commands 2>/dev/null)" + +__git_porcelain_commands= +__git_compute_porcelain_commands () +{ + __git_compute_all_commands + : ${__git_porcelain_commands:=$(__git_list_porcelain_commands)} +} __git_aliases () { @@ -884,10 +1039,19 @@ __git_aliased_command () local word cmdline=$(git --git-dir="$(__gitdir)" \ config --get "alias.$1") for word in $cmdline; do - if [ "${word##-*}" ]; then - echo $word + case "$word" in + \!gitk|gitk) + echo "gitk" return - fi + ;; + \!*) : shell command alias ;; + -*) : option ;; + *=*) : setting env ;; + git) : git itself ;; + *) + echo "$word" + return + esac done } @@ -926,7 +1090,7 @@ _git_am () { local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)" if [ -d "$dir"/rebase-apply ]; then - __gitcomp "--skip --resolved --abort" + __gitcomp "--skip --continue --resolved --abort" return fi case "$cur" in @@ -1045,6 +1209,7 @@ _git_branch () __gitcomp " --color --no-color --verbose --abbrev= --no-abbrev --track --no-track --contains --merged --no-merged + --set-upstream " ;; *) @@ -1060,19 +1225,16 @@ _git_branch () _git_bundle () { local cmd="${COMP_WORDS[1]}" - case "$COMP_CWORD" in - 2) + + case "${COMP_WORDS[COMP_CWORD-1]}" in + bundle) __gitcomp "create list-heads verify unbundle" ;; - 3) - # looking for a file + create) + __git_complete_revlist ;; - *) - case "$cmd" in - create) - __git_complete_revlist - ;; - esac + list-heads|verify|unbundle|*) + # looking for a file ;; esac } @@ -1089,7 +1251,7 @@ _git_checkout () --*) __gitcomp " --quiet --ours --theirs --track --no-track --merge - --conflict= --patch + --conflict= --orphan --patch " ;; *) @@ -1161,11 +1323,31 @@ _git_commit () local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in + --cleanup=*) + __gitcomp "default strip verbatim whitespace + " "" "${cur##--cleanup=}" + return + ;; + --reuse-message=*) + __gitcomp "$(__git_refs)" "" "${cur##--reuse-message=}" + return + ;; + --reedit-message=*) + __gitcomp "$(__git_refs)" "" "${cur##--reedit-message=}" + return + ;; + --untracked-files=*) + __gitcomp "all no normal" "" "${cur##--untracked-files=}" + return + ;; --*) __gitcomp " --all --author= --signoff --verify --no-verify --edit --amend --include --only --interactive - --dry-run + --dry-run --reuse-message= --reedit-message= + --reset-author --file= --message= --template= + --cleanup= --untracked-files --untracked-files= + --verbose --quiet " return esac @@ -1220,11 +1402,13 @@ _git_diff () } __git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis + tkdiff vimdiff gvimdiff xxdiff araxis p4merge " _git_difftool () { + __git_has_doubledash && return + local cur="${COMP_WORDS[COMP_CWORD]}" case "$cur" in --tool=*) @@ -1232,16 +1416,20 @@ _git_difftool () return ;; --*) - __gitcomp "--tool=" + __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex + --base --ours --theirs + --no-renames --diff-filter= --find-copies-harder + --relative --ignore-submodules + --tool=" return ;; esac - COMPREPLY=() + __git_complete_file } __git_fetch_options=" --quiet --verbose --append --upload-pack --force --keep --depth= - --tags --no-tags + --tags --no-tags --all --prune --dry-run " _git_fetch () @@ -1273,7 +1461,7 @@ _git_format_patch () --numbered --start-number --numbered-files --keep-subject - --signoff + --signoff --signature --no-signature --in-reply-to= --cc= --full-index --binary --not --all @@ -1315,6 +1503,11 @@ _git_gc () COMPREPLY=() } +_git_gitk () +{ + _gitk +} + _git_grep () { __git_has_doubledash && return @@ -1336,7 +1529,8 @@ _git_grep () return ;; esac - COMPREPLY=() + + __gitcomp "$(__git_refs)" } _git_help () @@ -1348,7 +1542,8 @@ _git_help () return ;; esac - __gitcomp "$(__git_all_commands) + __git_compute_all_commands + __gitcomp "$__git_all_commands attributes cli core-tutorial cvs-migration diffcore gitk glossary hooks ignore modules repository-layout tutorial tutorial-2 @@ -1484,7 +1679,7 @@ _git_log () __git_merge_options=" --no-commit --no-stat --log --no-log --squash --strategy - --commit --stat --no-squash --ff --no-ff + --commit --stat --no-squash --ff --no-ff --ff-only " _git_merge () @@ -1538,6 +1733,24 @@ _git_name_rev () __gitcomp "--tags --all --stdin" } +_git_notes () +{ + local subcommands="edit show" + if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then + __gitcomp "$subcommands" + return + fi + + case "${COMP_WORDS[COMP_CWORD-1]}" in + -m|-F) + COMPREPLY=() + ;; + *) + __gitcomp "$(__git_refs)" + ;; + esac +} + _git_pull () { __git_complete_strategy && return @@ -1589,8 +1802,19 @@ _git_rebase () fi __git_complete_strategy && return case "$cur" in + --whitespace=*) + __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" + return + ;; --*) - __gitcomp "--onto --merge --strategy --interactive" + __gitcomp " + --onto --merge --strategy --interactive + --preserve-merges --stat --no-stat + --committer-date-is-author-date --ignore-date + --ignore-whitespace --whitespace= + --autosquash + " + return esac __gitcomp "$(__git_refs)" @@ -1636,6 +1860,11 @@ _git_send_email () COMPREPLY=() } +_git_stage () +{ + _git_add +} + __git_config_get_set_variables () { local prevword word config_file= c=$COMP_CWORD @@ -1694,7 +1923,8 @@ _git_config () return ;; pull.twohead|pull.octopus) - __gitcomp "$(__git_merge_strategies)" + __git_compute_merge_strategies + __gitcomp "$__git_merge_strategies" return ;; color.branch|color.diff|color.interactive|\ @@ -1795,7 +2025,8 @@ _git_config () pager.*) local pfx="${cur%.*}." cur="${cur#*.}" - __gitcomp "$(__git_all_commands)" "$pfx" "$cur" + __git_compute_all_commands + __gitcomp "$__git_all_commands" "$pfx" "$cur" return ;; remote.*.*) @@ -1904,6 +2135,7 @@ _git_config () format.headers format.numbered format.pretty + format.signature format.signoff format.subjectprefix format.suffix @@ -2237,7 +2469,7 @@ _git_svn () 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 + migrate mkdirs reset gc " local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then @@ -2284,7 +2516,7 @@ _git_svn () __gitcomp "--stdin $cmt_opts $fc_opts" ;; create-ignore,--*|propget,--*|proplist,--*|show-ignore,--*|\ - show-externals,--*) + show-externals,--*|mkdirs,--*) __gitcomp "--revision=" ;; log,--*) @@ -2321,6 +2553,9 @@ _git_svn () --no-auth-cache --username= " ;; + reset,--*) + __gitcomp "--revision= --parent" + ;; *) COMPREPLY=() ;; @@ -2362,6 +2597,11 @@ _git_tag () esac } +_git_whatchanged () +{ + _git_log +} + _git () { local i c=1 command __git_dir @@ -2392,68 +2632,20 @@ _git () --help " ;; - *) __gitcomp "$(__git_porcelain_commands) $(__git_aliases)" ;; + *) __git_compute_porcelain_commands + __gitcomp "$__git_porcelain_commands $(__git_aliases)" ;; esac return fi + local completion_func="_git_${command//-/_}" + declare -F $completion_func >/dev/null && $completion_func && return + local expansion=$(__git_aliased_command "$command") - [ "$expansion" ] && command="$expansion" - - case "$command" in - am) _git_am ;; - add) _git_add ;; - apply) _git_apply ;; - archive) _git_archive ;; - bisect) _git_bisect ;; - bundle) _git_bundle ;; - branch) _git_branch ;; - checkout) _git_checkout ;; - cherry) _git_cherry ;; - cherry-pick) _git_cherry_pick ;; - clean) _git_clean ;; - clone) _git_clone ;; - commit) _git_commit ;; - config) _git_config ;; - describe) _git_describe ;; - diff) _git_diff ;; - difftool) _git_difftool ;; - fetch) _git_fetch ;; - format-patch) _git_format_patch ;; - fsck) _git_fsck ;; - gc) _git_gc ;; - grep) _git_grep ;; - help) _git_help ;; - init) _git_init ;; - log) _git_log ;; - ls-files) _git_ls_files ;; - ls-remote) _git_ls_remote ;; - ls-tree) _git_ls_tree ;; - merge) _git_merge;; - mergetool) _git_mergetool;; - merge-base) _git_merge_base ;; - mv) _git_mv ;; - name-rev) _git_name_rev ;; - pull) _git_pull ;; - push) _git_push ;; - rebase) _git_rebase ;; - remote) _git_remote ;; - replace) _git_replace ;; - reset) _git_reset ;; - revert) _git_revert ;; - rm) _git_rm ;; - send-email) _git_send_email ;; - shortlog) _git_shortlog ;; - show) _git_show ;; - show-branch) _git_show_branch ;; - stash) _git_stash ;; - stage) _git_add ;; - submodule) _git_submodule ;; - svn) _git_svn ;; - tag) _git_tag ;; - whatchanged) _git_log ;; - *) COMPREPLY=() ;; - esac + if [ -n "$expansion" ]; then + completion_func="_git_${expansion//-/_}" + declare -F $completion_func >/dev/null && $completion_func + fi } _gitk () -- 2.47.1