From 4e855e3ed09008f066ceb0a7da42f5c9358b5e96 Mon Sep 17 00:00:00 2001 From: Tony Duckles Date: Sun, 17 Nov 2013 10:17:43 -0600 Subject: [PATCH] bin/: A bit of housekeeping Remove unused commands. Rename some git-* commands to have verbose names and use ~/.gitconfig aliases to maintain short-names. --- .gitconfig | 12 +- bin/ack-wrapper | 44 - bin/{git-brdate => git-branch-dates} | 4 +- bin/{git-cv => git-cherry-view} | 0 bin/git-sh | 2746 -------------------------- bin/github-grab | 22 - bin/hub | 2482 ----------------------- bin/latest-ack | 4 - bin/latest-hub | 8 - 9 files changed, 6 insertions(+), 5316 deletions(-) delete mode 100755 bin/ack-wrapper rename bin/{git-brdate => git-branch-dates} (58%) rename bin/{git-cv => git-cherry-view} (100%) delete mode 100755 bin/git-sh delete mode 100755 bin/github-grab delete mode 100755 bin/hub delete mode 100755 bin/latest-ack delete mode 100755 bin/latest-hub diff --git a/.gitconfig b/.gitconfig index fb91a05..192bcbe 100644 --- a/.gitconfig +++ b/.gitconfig @@ -10,19 +10,15 @@ co = checkout tags = tag -n1 -l # Log helpers - ll = log --pretty='format:%C(yellow)%h%Creset %s%C(green bold)%d%Creset %C(black bold)(by %an, %ar)%Creset' + ll = log --pretty='format:%C(yellow)%h%Creset %s%C(green bold)%d%Creset %C(black bold)(by %an, %ar)%Creset' graph = log --all --graph --topo-order --pretty='format:%C(yellow)%h%Creset %s %C(black bold)(by %an)%Creset%C(green bold)%d%Creset%n' # Remote helpers - track = !git-track - incoming = !git-incoming in = !git-incoming - outgoing = !git-outgoing out = !git-outgoing # Branch helpers - bd = !git-brdate + bd = !git-branch-dates bv = !git branch --color -vv - cv = !git-cv - subtree = !git-subtree + cv = !git-cherry-view # Diff helpers df = diff --patience dfc = diff --patience --cached @@ -35,8 +31,6 @@ sup = !git-subup pull # Misc root = rev-parse --show-toplevel - sh = !git-sh - thanks = !git-thanks who = shortlog -s -- fp = format-patch --stdout diff --git a/bin/ack-wrapper b/bin/ack-wrapper deleted file mode 100755 index a542bc6..0000000 --- a/bin/ack-wrapper +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -# Wrapper around 'ack' to crawl all directories from `pwd` to / (or $HOME) -# looking for a "local" .ackrc file. Useful for setting project-level -# --ignore-dir settings. - -# Search for "local" .ackrc file in CWD or any parents -HOME=~ -ackrc="" -match="" -dir=$(pwd) -while [ "${dir}" != "/" -a "${match}" = "" ]; do - if [ -e "${dir}/.ackrc" ]; then - if [ "${dir}" != "${HOME}" ]; then - match=1 - echo "(Include: ${dir}/.ackrc)" - ackrc=$(egrep "^[^#]" "${dir}/.ackrc" | tr '\n' ' ') - else - match=0 - fi - else - dir=$(dirname "${dir}") - fi -done - -# Add quote-wrapping for any additional args to ensure proper passing to -# real 'ack'. -for arg in "$@"; do - if [ -z "${ackrc}" ]; then - ackrc="'${arg}'" - else - ackrc="${ackrc} '${arg}'" - fi -done - -# Build command to eval -cmd="command ack ${ackrc}" -if [ ! -t 0 ]; then - # If stdin is a pipe, use cat to redirect stdin to stdout and pipe - # that data into ack. - cmd="cat | ${cmd}" -fi - -# Eval the final command -eval "${cmd}" diff --git a/bin/git-brdate b/bin/git-branch-dates similarity index 58% rename from bin/git-brdate rename to bin/git-branch-dates index b5a2ee1..7922302 100755 --- a/bin/git-brdate +++ b/bin/git-branch-dates @@ -3,4 +3,6 @@ # Show git branches by date - useful for showing active branches # http://www.commandlinefu.com/commands/view/2345/show-git-branches-by-date-useful-for-showing-active-branches -for k in `git branch|perl -pe s/^..//`;do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k|head -n 1`\\t$k;done|sort -r +for k in `git branch | perl -pe s/^..//`; do + echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k | head -n 1`\\t$k +done | sort -r diff --git a/bin/git-cv b/bin/git-cherry-view similarity index 100% rename from bin/git-cv rename to bin/git-cherry-view diff --git a/bin/git-sh b/bin/git-sh deleted file mode 100755 index fecb333..0000000 --- a/bin/git-sh +++ /dev/null @@ -1,2746 +0,0 @@ -#!/usr/bin/env bash -# -# A customized bash environment suitable for git work. -# -# Copyright (C) 2008 Ryan Tomayko -# Copyright (C) 2008 Aristotle Pagaltzis -# -# 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 of the License, 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, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# Distributed under the GNU General Public License, version 2.0. - -# use to install the sh alias -[[ $1 = '--configure' && $# = 1 ]] && { - set -e - git config --global alias.sh '!git-sh' - echo "alias 'sh' added to ~/.gitconfig" - exit 0 -} - -# we expect to be sourced into an interactive shell. when executed as a -# command, kick off a new shell and source us. -[ "$0" = 'bash' ] || -exec /usr/bin/env bash --rcfile "$0" "$@" - -# source the user's .bashrc file -[ -r ~/.bashrc ] && { - pushd ~ > /dev/null - . .bashrc - popd > /dev/null -} - - -# ALIASES + COMPLETION ========================================================= - -# gitcomp -# -# Complete command named like standard git command named -# . must be a valid git command with completion. -# -# Examples: -# gitcomplete ci commit -# gitcomplete c checkout -gitcomplete() { - local alias="$1" command="$2" - complete -o default -o nospace -F _git_${command//-/_} $alias -} - -# gitalias =' [...]' -# -# Define a new shell alias (as with the alias builtin) named -# and enable command completion based on . must be -# a standard non-abbreviated git command name that has completion support. -# -# Examples: -# gitalias c=checkout -# gitalias ci='commit -v' -# gitalias r='rebase --interactive HEAD~10' -gitalias() { - local alias="${1%%=*}" command="${1#*=}" - local prog="${command##git }" - prog="${prog%% *}" - alias $alias="$command" - gitcomplete "$alias" "$prog" -} - -# create aliases and configure bash completion for most porcelain commands - -_git_cmd_cfg=( - 'add alias' - 'am alias stdcmpl' - 'annotate alias' - 'apply alias stdcmpl' - 'archive alias' - 'bisect alias stdcmpl' - 'blame alias' - 'branch alias stdcmpl' - 'bundle alias stdcmpl' - 'cat-file alias' - 'checkout alias stdcmpl' - 'cherry alias stdcmpl' - 'cherry-pick alias stdcmpl' - 'clean alias' - 'clone alias' - 'commit alias stdcmpl' - 'config alias stdcmpl' - 'describe alias stdcmpl' - 'diff alias stdcmpl' - 'difftool alias' - 'fetch alias stdcmpl' - 'format-patch alias stdcmpl' - 'fsck alias' - 'gc alias stdcmpl' - 'gui alias' - 'hash-object alias' - 'init alias' - 'instaweb alias' - 'log alias logcmpl' - 'lost-found alias' - 'ls-files alias' - 'ls-remote alias stdcmpl' - 'ls-tree alias stdcmpl' - 'merge alias stdcmpl' - 'merge-base alias stdcmpl' - 'mergetool alias' - 'mv alias' - 'name-rev stdcmpl' - 'patch-id alias' - 'peek-remote alias' - 'prune alias' - 'pull alias stdcmpl' - 'push alias stdcmpl' - 'quiltimport alias' - 'rebase alias stdcmpl' - 'reflog alias' - 'remote alias stdcmpl' - 'repack alias' - 'repo-config alias' - 'request-pull alias' - 'reset alias stdcmpl' - 'rev-list alias' - 'rev-parse alias' - 'revert alias' - 'rm alias' - 'send-email alias' - 'send-pack alias' - 'shortlog alias stdcmpl' - 'show alias stdcmpl' - 'show-branch alias logcmpl' - 'stash alias stdcmpl' - 'status alias' - 'stripspace alias' - 'submodule alias stdcmpl' - 'svn alias stdcmpl' - 'symbolic-ref alias' - 'tag alias stdcmpl' - 'tar-tree alias' - 'var alias' - 'whatchanged alias logcmpl' -) - -for cfg in "${_git_cmd_cfg[@]}" ; do - read cmd opts <<< $cfg - for opt in $opts ; do - case $opt in - alias) alias $cmd="git $cmd" ;; - stdcmpl) complete -o default -o nospace -F _git_${cmd//-/_} $cmd ;; - logcmpl) complete -o default -o nospace -F _git_log $cmd ;; - esac - done -done - -# Create aliases for everything defined in the gitconfig [alias] section. -_git_import_aliases () { - eval "$( - git config --get-regexp 'alias\..*' | - sed 's/^alias\.//' | - while read key command - do - if expr -- "$command" : '!' >/dev/null - then echo "alias $key='git $key'" - else echo "gitalias $key=\"git $command\"" - fi - done - )" -} - -# PROMPT ======================================================================= - -PS1='`_git_headname`!`_git_workdir``_git_dirty`> ' - -ANSI_RESET="\001$(git config --get-color "" "reset")\002" - -# detect whether the tree is in a dirty state. returns -_git_dirty() { - if git status 2>/dev/null | fgrep -q '(working directory clean)'; then - return 0 - fi - local dirty_marker="`git config gitsh.dirty || echo ' *'`" - _git_apply_color "$dirty_marker" "color.sh.dirty" "red" -} - -# detect the current branch; use 7-sha when not on branch -_git_headname() { - local br=`git symbolic-ref -q HEAD 2>/dev/null` - [ -n "$br" ] && - br=${br#refs/heads/} || - br=`git rev-parse --short HEAD 2>/dev/null` - _git_apply_color "$br" "color.sh.branch" "yellow reverse" -} - -# detect working directory relative to working tree root -_git_workdir() { - subdir=`git rev-parse --show-prefix 2>/dev/null` - subdir="${subdir%/}" - workdir="${PWD%/$subdir}" - _git_apply_color "${workdir/*\/}${subdir:+/$subdir}" "color.sh.workdir" "blue bold" -} - -# determine whether color should be enabled. this checks git's color.ui -# option and then color.sh. -_git_color_enabled() { - [ `git config --get-colorbool color.sh true` = "true" ] -} - -# apply a color to the first argument -_git_apply_color() { - local output="$1" color="$2" default="$3" - if _git_color_enabled ; then - color=`_git_color "$color" "$default"` - echo -ne "${color}${output}${ANSI_RESET}" - else - echo -ne "$output" - fi -} - -# retrieve an ANSI color escape sequence from git config -_git_color() { - local color - color=`git config --get-color "$1" "$2" 2>/dev/null` - [ -n "$color" ] && echo -ne "\001$color\002" -} - -# HELP ======================================================================== - -_help_display() { - local name value - # show git's inbuilt help, after some tweaking... - git --help | grep -v "See 'git help" - - # show aliases defined in ~/.gitconfig - echo "Command aliases:" - git config --get-regexp 'alias\..*' | - sed 's/^alias\.//' | - sort | - while read name value - do printf " %-10s %-65s\n" "$name" "$value" - done - - printf "\nSee 'help COMMAND' for more information on a specific command.\n" -} - -help() { - local _git_pager=$(git config core.pager) - if [ $# = 1 ]; - then git help $1 - else (_help_display | ${_git_pager:-${PAGER:-less}}) - fi -} -complete -o default -o nospace -F _git help - -# vim: tw=80 noexpandtab -#!bash -# -# bash completion support for core Git. -# -# Copyright (C) 2006,2007 Shawn O. Pearce -# 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' -# *) tree paths within 'ref:path/to/file' expressions -# *) common --long-options -# -# To use these routines: -# -# 1) Copy this file to somewhere (e.g. ~/.git-completion.sh). -# 2) Added the following line to your .bashrc: -# source ~/.git-completion.sh -# -# 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 -# are currently in a git repository. The %s token will be -# the name of the current branch. -# -# 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. -# -# 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 -# *) Send all patches to the current maintainer: -# -# "Shawn O. Pearce" -# -# *) Always CC the Git mailing list: -# -# git@vger.kernel.org -# - -case "$COMP_WORDBREAKS" in -*:*) : great ;; -*) COMP_WORDBREAKS="$COMP_WORDBREAKS:" -esac - -# __gitdir accepts 0 or 1 arguments (i.e., location) -# returns location of .git repo -__gitdir () -{ - if [ -z "${1-}" ]; then - if [ -n "${__git_dir-}" ]; then - echo "$__git_dir" - elif [ -d .git ]; then - echo .git - else - git rev-parse --git-dir 2>/dev/null - fi - elif [ -d "$1/.git" ]; then - echo "$1/.git" - else - echo "$1" - 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="" - if [ -f "$g/rebase-merge/interactive" ]; then - r="|REBASE-i" - b="$(cat "$g/rebase-merge/head-name")" - elif [ -d "$g/rebase-merge" ]; then - r="|REBASE-m" - b="$(cat "$g/rebase-merge/head-name")" - else - if [ -d "$g/rebase-apply" ]; then - if [ -f "$g/rebase-apply/rebasing" ]; then - 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/BISECT_LOG" ]; then - r="|BISECTING" - fi - - b="$(git symbolic-ref HEAD 2>/dev/null)" || { - - b="$( - case "${GIT_PS1_DESCRIBE_STYLE-}" in - (contains) - git describe --contains HEAD ;; - (branch) - git describe --contains --all HEAD ;; - (describe) - git describe HEAD ;; - (* | default) - git describe --exact-match HEAD ;; - esac 2>/dev/null)" || - - b="$(cut -c1-7 "$g/HEAD" 2>/dev/null)..." || - b="unknown" - b="($b)" - } - fi - - 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 - c="BARE:" - else - b="GIT_DIR!" - fi - 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 --quiet --exit-code || w="*" - if git rev-parse --quiet --verify HEAD >/dev/null; then - git diff-index --cached --quiet HEAD -- || i="+" - else - i="#" - fi - fi - fi - if [ -n "${GIT_PS1_SHOWSTASHSTATE-}" ]; then - git rev-parse --verify refs/stash >/dev/null 2>&1 && s="$" - fi - - if [ -n "${GIT_PS1_SHOWUNTRACKEDFILES-}" ]; then - if [ -n "$(git ls-files --others --exclude-standard)" ]; then - u="%" - fi - fi - - 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 -} - -# __gitcomp_1 requires 2 arguments -__gitcomp_1 () -{ - local c IFS=' '$'\t'$'\n' - for c in $1; do - case "$c$2" in - --*=*) printf %s$'\n' "$c$2" ;; - *.) printf %s$'\n' "$c$2" ;; - *) printf %s$'\n' "$c$2 " ;; - esac - done -} - -# __gitcomp accepts 1, 2, 3, or 4 arguments -# generates completion reply with compgen -__gitcomp () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - if [ $# -gt 2 ]; then - cur="$3" - fi - case "$cur" in - --*=) - COMPREPLY=() - ;; - *) - local IFS=$'\n' - COMPREPLY=($(compgen -P "${2-}" \ - -W "$(__gitcomp_1 "${1-}" "${4-}")" \ - -- "$cur")) - ;; - esac -} - -# __git_heads accepts 0 or 1 arguments (to pass to __gitdir) -__git_heads () -{ - local cmd i is_hash=y dir="$(__gitdir "${1-}")" - if [ -d "$dir" ]; then - git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ - refs/heads - return - fi - for i in $(git ls-remote "${1-}" 2>/dev/null); do - case "$is_hash,$i" in - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;; - n,*) is_hash=y; echo "$i" ;; - esac - done -} - -# __git_tags accepts 0 or 1 arguments (to pass to __gitdir) -__git_tags () -{ - local cmd i is_hash=y dir="$(__gitdir "${1-}")" - if [ -d "$dir" ]; then - git --git-dir="$dir" for-each-ref --format='%(refname:short)' \ - refs/tags - return - fi - for i in $(git ls-remote "${1-}" 2>/dev/null); do - case "$is_hash,$i" in - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;; - n,*) is_hash=y; echo "$i" ;; - esac - done -} - -# __git_refs accepts 0 or 1 arguments (to pass to __gitdir) -__git_refs () -{ - local i is_hash=y dir="$(__gitdir "${1-}")" - local cur="${COMP_WORDS[COMP_CWORD]}" format refs - if [ -d "$dir" ]; then - case "$cur" in - refs|refs/*) - format="refname" - refs="${cur%/*}" - ;; - *) - 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" - ;; - esac - git --git-dir="$dir" for-each-ref --format="%($format)" \ - $refs - return - fi - for i in $(git ls-remote "$dir" 2>/dev/null); do - case "$is_hash,$i" in - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/tags/*) is_hash=y; echo "${i#refs/tags/}" ;; - n,refs/heads/*) is_hash=y; echo "${i#refs/heads/}" ;; - n,refs/remotes/*) is_hash=y; echo "${i#refs/remotes/}" ;; - n,*) is_hash=y; echo "$i" ;; - esac - done -} - -# __git_refs2 requires 1 argument (to pass to __git_refs) -__git_refs2 () -{ - local i - for i in $(__git_refs "$1"); do - echo "$i:$i" - done -} - -# __git_refs_remotes requires 1 argument (to pass to ls-remote) -__git_refs_remotes () -{ - local cmd i is_hash=y - for i in $(git ls-remote "$1" 2>/dev/null); do - case "$is_hash,$i" in - n,refs/heads/*) - is_hash=y - echo "$i:refs/remotes/$1/${i#refs/heads/}" - ;; - y,*) is_hash=n ;; - n,*^{}) is_hash=y ;; - n,refs/tags/*) is_hash=y;; - n,*) is_hash=y; ;; - esac - done -} - -__git_remotes () -{ - local i ngoff IFS=$'\n' d="$(__gitdir)" - shopt -q nullglob || ngoff=1 - shopt -s nullglob - for i in "$d/remotes"/*; do - echo ${i#$d/remotes/} - done - [ "$ngoff" ] && shopt -u nullglob - for i in $(git --git-dir="$d" config --get-regexp 'remote\..*\.url' 2>/dev/null); do - i="${i#remote.}" - echo "${i/.url*/}" - done -} - -__git_list_merge_strategies () -{ - 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 () -{ - : ${__git_merge_strategies:=$(__git_list_merge_strategies)} -} - -__git_complete_file () -{ - local pfx ls ref cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - ?*:*) - 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 - - local IFS=$'\n' - COMPREPLY=($(compgen -P "$pfx" \ - -W "$(git --git-dir="$(__gitdir)" ls-tree "$ls" \ - | sed '/^100... blob /{ - s,^.* ,, - s,$, , - } - /^120000 blob /{ - s,^.* ,, - s,$, , - } - /^040000 tree /{ - s,^.* ,, - s,$,/, - } - s/^.* //')" \ - -- "$cur")) - ;; - *) - __gitcomp "$(__git_refs)" - ;; - esac -} - -__git_complete_revlist () -{ - local pfx cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - *...*) - pfx="${cur%...*}..." - cur="${cur#*...}" - __gitcomp "$(__git_refs)" "$pfx" "$cur" - ;; - *..*) - pfx="${cur%..*}.." - cur="${cur#*..}" - __gitcomp "$(__git_refs)" "$pfx" "$cur" - ;; - *) - __gitcomp "$(__git_refs)" - ;; - esac -} - -__git_complete_remote_or_refspec () -{ - local cmd="${COMP_WORDS[0]}" - local cur="${COMP_WORDS[COMP_CWORD]}" - local i c=1 remote="" pfx="" lhs=1 no_complete_refspec=0 - - # 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 - --mirror) [ "$cmd" = "push" ] && no_complete_refspec=1 ;; - --all) - case "$cmd" in - push) no_complete_refspec=1 ;; - fetch) - COMPREPLY=() - return - ;; - *) ;; - esac - ;; - -*) ;; - *) remote="$i"; break ;; - esac - c=$((++c)) - done - if [ -z "$remote" ]; then - __gitcomp "$(__git_remotes)" - return - fi - if [ $no_complete_refspec = 1 ]; then - COMPREPLY=() - 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 - __gitcomp "$(__git_refs2 "$remote")" "$pfx" "$cur" - else - __gitcomp "$(__git_refs)" "$pfx" "$cur" - fi - ;; - pull) - if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur" - else - __gitcomp "$(__git_refs)" "$pfx" "$cur" - fi - ;; - push) - if [ $lhs = 1 ]; then - __gitcomp "$(__git_refs)" "$pfx" "$cur" - else - __gitcomp "$(__git_refs "$remote")" "$pfx" "$cur" - fi - ;; - esac -} - -__git_complete_strategy () -{ - __git_compute_merge_strategies - case "${COMP_WORDS[COMP_CWORD-1]}" in - -s|--strategy) - __gitcomp "$__git_merge_strategies" - return 0 - esac - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --strategy=*) - __gitcomp "$__git_merge_strategies" "" "${cur##--strategy=}" - return 0 - ;; - esac - return 1 -} - -__git_list_all_commands () -{ - local i IFS=" "$'\n' - for i in $(git help -a|egrep '^ [a-zA-Z0-9]') - do - case $i in - *--*) : helper pattern;; - *) echo $i;; - esac - done -} - -__git_all_commands= -__git_compute_all_commands () -{ - : ${__git_all_commands:=$(__git_list_all_commands)} -} - -__git_list_porcelain_commands () -{ - local i IFS=" "$'\n' - __git_compute_all_commands - for i in "help" $__git_all_commands - do - case $i in - *--*) : helper pattern;; - applymbox) : ask gittus;; - applypatch) : ask gittus;; - archimport) : import;; - cat-file) : plumbing;; - check-attr) : plumbing;; - check-ref-format) : plumbing;; - checkout-index) : plumbing;; - commit-tree) : plumbing;; - count-objects) : infrequent;; - cvsexportcommit) : export;; - cvsimport) : import;; - cvsserver) : daemon;; - daemon) : daemon;; - diff-files) : plumbing;; - diff-index) : plumbing;; - diff-tree) : plumbing;; - fast-import) : import;; - fast-export) : export;; - fsck-objects) : plumbing;; - fetch-pack) : plumbing;; - fmt-merge-msg) : plumbing;; - for-each-ref) : plumbing;; - hash-object) : plumbing;; - http-*) : transport;; - index-pack) : plumbing;; - init-db) : deprecated;; - local-fetch) : plumbing;; - lost-found) : infrequent;; - ls-files) : plumbing;; - ls-remote) : plumbing;; - ls-tree) : plumbing;; - mailinfo) : plumbing;; - mailsplit) : plumbing;; - merge-*) : plumbing;; - mktree) : plumbing;; - mktag) : plumbing;; - pack-objects) : plumbing;; - pack-redundant) : plumbing;; - pack-refs) : plumbing;; - parse-remote) : plumbing;; - patch-id) : plumbing;; - peek-remote) : plumbing;; - prune) : plumbing;; - prune-packed) : plumbing;; - quiltimport) : import;; - read-tree) : plumbing;; - receive-pack) : plumbing;; - reflog) : plumbing;; - remote-*) : transport;; - repo-config) : deprecated;; - rerere) : plumbing;; - rev-list) : plumbing;; - rev-parse) : plumbing;; - runstatus) : plumbing;; - sh-setup) : internal;; - shell) : daemon;; - show-ref) : plumbing;; - send-pack) : plumbing;; - show-index) : plumbing;; - ssh-*) : transport;; - stripspace) : plumbing;; - symbolic-ref) : plumbing;; - tar-tree) : deprecated;; - unpack-file) : plumbing;; - unpack-objects) : plumbing;; - update-index) : plumbing;; - update-ref) : plumbing;; - update-server-info) : daemon;; - upload-archive) : plumbing;; - upload-pack) : plumbing;; - write-tree) : plumbing;; - var) : infrequent;; - verify-pack) : infrequent;; - verify-tag) : plumbing;; - *) echo $i;; - esac - done -} - -__git_porcelain_commands= -__git_compute_porcelain_commands () -{ - __git_compute_all_commands - : ${__git_porcelain_commands:=$(__git_list_porcelain_commands)} -} - -__git_aliases () -{ - local i IFS=$'\n' - for i in $(git --git-dir="$(__gitdir)" config --get-regexp "alias\..*" 2>/dev/null); do - case "$i" in - alias.*) - i="${i#alias.}" - echo "${i/ */}" - ;; - esac - done -} - -# __git_aliased_command requires 1 argument -__git_aliased_command () -{ - local word cmdline=$(git --git-dir="$(__gitdir)" \ - 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 ;; - *) - echo "$word" - return - esac - done -} - -# __git_find_on_cmdline requires 1 argument -__git_find_on_cmdline () -{ - local word subcommand c=1 - - while [ $c -lt $COMP_CWORD ]; do - word="${COMP_WORDS[c]}" - for subcommand in $1; do - if [ "$subcommand" = "$word" ]; then - echo "$subcommand" - return - fi - done - c=$((++c)) - done -} - -__git_has_doubledash () -{ - local c=1 - while [ $c -lt $COMP_CWORD ]; do - if [ "--" = "${COMP_WORDS[c]}" ]; then - return 0 - fi - c=$((++c)) - done - return 1 -} - -__git_whitespacelist="nowarn warn error error-all fix" - -_git_am () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)" - if [ -d "$dir"/rebase-apply ]; then - __gitcomp "--skip --continue --resolved --abort" - return - fi - case "$cur" in - --whitespace=*) - __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" - return - ;; - --*) - __gitcomp " - --3way --committer-date-is-author-date --ignore-date - --ignore-whitespace --ignore-space-change - --interactive --keep --no-utf8 --signoff --utf8 - --whitespace= --scissors - " - return - esac - COMPREPLY=() -} - -_git_apply () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --whitespace=*) - __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" - return - ;; - --*) - __gitcomp " - --stat --numstat --summary --check --index - --cached --index-info --reverse --reject --unidiff-zero - --apply --no-add --exclude= - --ignore-whitespace --ignore-space-change - --whitespace= --inaccurate-eof --verbose - " - return - esac - COMPREPLY=() -} - -_git_add () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - --interactive --refresh --patch --update --dry-run - --ignore-errors --intent-to-add - " - return - esac - COMPREPLY=() -} - -_git_archive () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --format=*) - __gitcomp "$(git archive --list)" "" "${cur##--format=}" - return - ;; - --remote=*) - __gitcomp "$(__git_remotes)" "" "${cur##--remote=}" - return - ;; - --*) - __gitcomp " - --format= --list --verbose - --prefix= --remote= --exec= - " - 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 - __gitcomp "$subcommands" - return - fi - - case "$subcommand" in - bad|good|reset|skip) - __gitcomp "$(__git_refs)" - ;; - *) - COMPREPLY=() - ;; - esac -} - -_git_branch () -{ - local i c=1 only_local_ref="n" has_r="n" - - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" - case "$i" in - -d|-m) only_local_ref="y" ;; - -r) has_r="y" ;; - esac - c=$((++c)) - done - - case "${COMP_WORDS[COMP_CWORD]}" in - --*) - __gitcomp " - --color --no-color --verbose --abbrev= --no-abbrev - --track --no-track --contains --merged --no-merged - --set-upstream - " - ;; - *) - if [ $only_local_ref = "y" -a $has_r = "n" ]; then - __gitcomp "$(__git_heads)" - else - __gitcomp "$(__git_refs)" - fi - ;; - esac -} - -_git_bundle () -{ - local cmd="${COMP_WORDS[1]}" - - case "${COMP_WORDS[COMP_CWORD-1]}" in - bundle) - __gitcomp "create list-heads verify unbundle" - ;; - create) - __git_complete_revlist - ;; - list-heads|verify|unbundle|*) - # looking for a file - ;; - esac -} - -_git_checkout () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --conflict=*) - __gitcomp "diff3 merge" "" "${cur##--conflict=}" - ;; - --*) - __gitcomp " - --quiet --ours --theirs --track --no-track --merge - --conflict= --orphan --patch - " - ;; - *) - __gitcomp "$(__git_refs)" - ;; - esac -} - -_git_cherry () -{ - __gitcomp "$(__git_refs)" -} - -_git_cherry_pick () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--edit --no-commit" - ;; - *) - __gitcomp "$(__git_refs)" - ;; - esac -} - -_git_clean () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--dry-run --quiet" - return - ;; - esac - COMPREPLY=() -} - -_git_clone () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - --local - --no-hardlinks - --shared - --reference - --quiet - --no-checkout - --bare - --mirror - --origin - --upload-pack - --template= - --depth - " - return - ;; - esac - COMPREPLY=() -} - -_git_commit () -{ - __git_has_doubledash && return - - 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 --reuse-message= --reedit-message= - --reset-author --file= --message= --template= - --cleanup= --untracked-files --untracked-files= - --verbose --quiet - " - return - esac - COMPREPLY=() -} - -_git_describe () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - --all --tags --contains --abbrev= --candidates= - --exact-match --debug --long --match --always - " - return - esac - __gitcomp "$(__git_refs)" -} - -__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 - --text --ignore-space-at-eol --ignore-space-change - --ignore-all-space --exit-code --quiet --ext-diff - --no-ext-diff - --no-prefix --src-prefix= --dst-prefix= - --inter-hunk-context= - --patience - --raw - --dirstat --dirstat= --dirstat-by-file - --dirstat-by-file= --cumulative -" - -_git_diff () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex - --base --ours --theirs - $__git_diff_common_options - " - return - ;; - esac - __git_complete_file -} - -__git_mergetools_common="diffuse ecmerge emerge kdiff3 meld opendiff - tkdiff vimdiff gvimdiff xxdiff araxis p4merge -" - -_git_difftool () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --tool=*) - __gitcomp "$__git_mergetools_common kompare" "" "${cur##--tool=}" - return - ;; - --*) - __gitcomp "--cached --staged --pickaxe-all --pickaxe-regex - --base --ours --theirs - --no-renames --diff-filter= --find-copies-harder - --relative --ignore-submodules - --tool=" - return - ;; - esac - __git_complete_file -} - -__git_fetch_options=" - --quiet --verbose --append --upload-pack --force --keep --depth= - --tags --no-tags --all --prune --dry-run -" - -_git_fetch () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "$__git_fetch_options" - return - ;; - esac - __git_complete_remote_or_refspec -} - -_git_format_patch () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --thread=*) - __gitcomp " - deep shallow - " "" "${cur##--thread=}" - return - ;; - --*) - __gitcomp " - --stdout --attach --no-attach --thread --thread= - --output-directory - --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= - " - return - ;; - esac - __git_complete_revlist -} - -_git_fsck () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - --tags --root --unreachable --cache --no-reflogs --full - --strict --verbose --lost-found - " - return - ;; - esac - COMPREPLY=() -} - -_git_gc () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--prune --aggressive" - return - ;; - esac - COMPREPLY=() -} - -_git_gitk () -{ - _gitk -} - -_git_grep () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - --cached - --text --ignore-case --word-regexp --invert-match - --full-name - --extended-regexp --basic-regexp --fixed-strings - --files-with-matches --name-only - --files-without-match - --max-depth - --count - --and --or --not --all-match - " - return - ;; - esac - - __gitcomp "$(__git_refs)" -} - -_git_help () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--all --info --man --web" - return - ;; - esac - __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 - workflows - " -} - -_git_init () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --shared=*) - __gitcomp " - false true umask group all world everybody - " "" "${cur##--shared=}" - return - ;; - --*) - __gitcomp "--quiet --bare --template= --shared --shared=" - return - ;; - esac - COMPREPLY=() -} - -_git_ls_files () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--cached --deleted --modified --others --ignored - --stage --directory --no-empty-directory --unmerged - --killed --exclude= --exclude-from= - --exclude-per-directory= --exclude-standard - --error-unmatch --with-tree= --full-name - --abbrev --ignored --exclude-per-directory - " - return - ;; - esac - COMPREPLY=() -} - -_git_ls_remote () -{ - __gitcomp "$(__git_remotes)" -} - -_git_ls_tree () -{ - __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= -" -# 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 -" -# Options that go well for log and shortlog (not gitk) -__git_log_shortlog_options=" - --author= --committer= --grep= - --all-match -" - -__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 - - local cur="${COMP_WORDS[COMP_CWORD]}" - local g="$(git rev-parse --git-dir 2>/dev/null)" - local merge="" - if [ -f "$g/MERGE_HEAD" ]; then - merge="--merge" - fi - case "$cur" in - --pretty=*) - __gitcomp "$__git_log_pretty_formats - " "" "${cur##--pretty=}" - return - ;; - --format=*) - __gitcomp "$__git_log_pretty_formats - " "" "${cur##--format=}" - return - ;; - --date=*) - __gitcomp "$__git_log_date_formats" "" "${cur##--date=}" - return - ;; - --decorate=*) - __gitcomp "long short" "" "${cur##--decorate=}" - 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 - --cherry-pick - --graph - --decorate --decorate= - --walk-reflogs - --parents --children - $merge - $__git_diff_common_options - --pickaxe-all --pickaxe-regex - " - return - ;; - esac - __git_complete_revlist -} - -__git_merge_options=" - --no-commit --no-stat --log --no-log --squash --strategy - --commit --stat --no-squash --ff --no-ff --ff-only -" - -_git_merge () -{ - __git_complete_strategy && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "$__git_merge_options" - return - esac - __gitcomp "$(__git_refs)" -} - -_git_mergetool () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --tool=*) - __gitcomp "$__git_mergetools_common tortoisemerge" "" "${cur##--tool=}" - return - ;; - --*) - __gitcomp "--tool=" - return - ;; - esac - COMPREPLY=() -} - -_git_merge_base () -{ - __gitcomp "$(__git_refs)" -} - -_git_mv () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--dry-run" - return - ;; - esac - COMPREPLY=() -} - -_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 - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - --rebase --no-rebase - $__git_merge_options - $__git_fetch_options - " - return - ;; - esac - __git_complete_remote_or_refspec -} - -_git_push () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "${COMP_WORDS[COMP_CWORD-1]}" in - --repo) - __gitcomp "$(__git_remotes)" - return - esac - case "$cur" in - --repo=*) - __gitcomp "$(__git_remotes)" "" "${cur##--repo=}" - return - ;; - --*) - __gitcomp " - --all --mirror --tags --dry-run --force --verbose - --receive-pack= --repo= - " - return - ;; - esac - __git_complete_remote_or_refspec -} - -_git_rebase () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" dir="$(__gitdir)" - if [ -d "$dir"/rebase-apply ] || [ -d "$dir"/rebase-merge ]; then - __gitcomp "--continue --skip --abort" - return - fi - __git_complete_strategy && return - case "$cur" in - --whitespace=*) - __gitcomp "$__git_whitespacelist" "" "${cur##--whitespace=}" - return - ;; - --*) - __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)" -} - -__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 () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - 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 - ;; - --*) - __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 - --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" - return - ;; - esac - COMPREPLY=() -} - -_git_stage () -{ - _git_add -} - -__git_config_get_set_variables () -{ - local prevword word config_file= c=$COMP_CWORD - while [ $c -gt 1 ]; do - word="${COMP_WORDS[c]}" - case "$word" in - --global|--system|--file=*) - config_file="$word" - break - ;; - -f|--file) - config_file="$word $prevword" - break - ;; - esac - prevword=$word - c=$((--c)) - done - - git --git-dir="$(__gitdir)" config $config_file --list 2>/dev/null | - while read line - do - case "$line" in - *.*=*) - echo "${line/=*/}" - ;; - esac - done -} - -_git_config () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - local prv="${COMP_WORDS[COMP_CWORD-1]}" - case "$prv" in - branch.*.remote) - __gitcomp "$(__git_remotes)" - return - ;; - branch.*.merge) - __gitcomp "$(__git_refs)" - return - ;; - remote.*.fetch) - local remote="${prv#remote.}" - remote="${remote%.fetch}" - __gitcomp "$(__git_refs_remotes "$remote")" - return - ;; - remote.*.push) - local remote="${prv#remote.}" - remote="${remote%.push}" - __gitcomp "$(git --git-dir="$(__gitdir)" \ - 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 - ;; - help.format) - __gitcomp "man info web html" - return - ;; - log.date) - __gitcomp "$__git_log_date_formats" - return - ;; - sendemail.aliasesfiletype) - __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 - ;; - --get|--get-all|--unset|--unset-all) - __gitcomp "$(__git_config_get_set_variables)" - return - ;; - *.*) - COMPREPLY=() - return - ;; - esac - case "$cur" in - --*) - __gitcomp " - --global --system --file= - --list --replace-all - --get --get-all --get-regexp - --add --unset --unset-all - --remove-section --rename-section - " - return - ;; - branch.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" - __gitcomp "remote merge mergeoptions rebase" "$pfx" "$cur" - return - ;; - branch.*) - local pfx="${cur%.*}." - cur="${cur#*.}" - __gitcomp "$(__git_heads)" "$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 "$__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 "$(__git_remotes)" "$pfx" "$cur" "." - return - ;; - url.*.*) - local pfx="${cur%.*}." - cur="${cur##*.}" - __gitcomp "insteadOf pushInsteadOf" "$pfx" "$cur" - return - ;; - esac - __gitcomp " - add.ignore-errors - alias. - apply.ignorewhitespace - apply.whitespace - branch.autosetupmerge - branch.autosetuprebase - clean.requireForce - color.branch - color.branch.current - color.branch.local - color.branch.plain - color.branch.remote - color.diff - color.diff.commit - color.diff.frag - color.diff.meta - color.diff.new - color.diff.old - color.diff.plain - color.diff.whitespace - color.grep - color.grep.external - color.grep.match - color.interactive - 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.nobranch - color.status.untracked - color.status.updated - color.ui - commit.template - core.autocrlf - core.bare - core.compression - core.createObject - core.deltaBaseCacheLimit - core.editor - core.excludesfile - core.fileMode - core.fsyncobjectfiles - core.gitProxy - core.ignoreCygwinFSTricks - core.ignoreStat - core.logAllRefUpdates - core.loosecompression - core.packedGitLimit - core.packedGitWindowSize - core.pager - core.preferSymlinkRefs - core.preloadindex - core.quotepath - core.repositoryFormatVersion - core.safecrlf - core.sharedRepository - core.symlinks - core.trustctime - core.warnAmbiguousRefs - core.whitespace - core.worktree - diff.autorefreshindex - diff.external - diff.mnemonicprefix - diff.renameLimit - diff.renameLimit. - diff.renames - diff.suppressBlankEmpty - diff.tool - diff.wordRegex - difftool. - difftool.prompt - fetch.unpackLimit - format.attach - format.cc - format.headers - format.numbered - format.pretty - format.signature - format.signoff - format.subjectprefix - format.suffix - format.thread - gc.aggressiveWindow - gc.auto - gc.autopacklimit - gc.packrefs - gc.pruneexpire - gc.reflogexpire - gc.reflogexpireunreachable - gc.rerereresolved - gc.rerereunresolved - 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.noEPSV - http.proxy - http.sslCAInfo - http.sslCAPath - http.sslCert - http.sslKey - http.sslVerify - i18n.commitEncoding - i18n.logOutputEncoding - imap.folder - imap.host - imap.pass - imap.port - imap.preformattedHTML - imap.sslverify - imap.tunnel - imap.user - instaweb.browser - instaweb.httpd - instaweb.local - instaweb.modulepath - instaweb.port - interactive.singlekey - log.date - log.showroot - mailmap.file - man. - man.viewer - merge.conflictstyle - merge.log - merge.renameLimit - merge.stat - merge.tool - merge.verbosity - mergetool. - mergetool.keepBackup - mergetool.prompt - pack.compression - pack.deltaCacheLimit - pack.deltaCacheSize - pack.depth - pack.indexVersion - pack.packSizeLimit - pack.threads - pack.window - pack.windowMemory - pager. - pull.octopus - pull.twohead - push.default - rebase.stat - receive.denyCurrentBranch - receive.denyDeletes - receive.denyNonFastForwards - receive.fsckObjects - receive.unpackLimit - repack.usedeltabaseoffset - rerere.autoupdate - rerere.enabled - sendemail.aliasesfile - sendemail.aliasesfiletype - sendemail.bcc - sendemail.cc - sendemail.cccmd - sendemail.chainreplyto - sendemail.confirm - sendemail.envelopesender - sendemail.multiedit - sendemail.signedoffbycc - sendemail.smtpencryption - sendemail.smtppass - sendemail.smtpserver - sendemail.smtpserverport - sendemail.smtpuser - sendemail.suppresscc - sendemail.suppressfrom - sendemail.thread - sendemail.to - sendemail.validate - showbranch.default - status.relativePaths - status.showUntrackedFiles - tar.umask - transfer.unpackLimit - url. - user.email - user.name - user.signingkey - web.browser - branch. remote. - " -} - -_git_remote () -{ - local subcommands="add rename rm show prune update set-head" - local subcommand="$(__git_find_on_cmdline "$subcommands")" - if [ -z "$subcommand" ]; then - __gitcomp "$subcommands" - return - fi - - case "$subcommand" in - rename|rm|show|prune) - __gitcomp "$(__git_remotes)" - ;; - update) - local i c='' IFS=$'\n' - for i in $(git --git-dir="$(__gitdir)" config --get-regexp "remotes\..*" 2>/dev/null); do - i="${i#remotes.}" - c="$c ${i/ */}" - done - __gitcomp "$c" - ;; - *) - COMPREPLY=() - ;; - esac -} - -_git_replace () -{ - __gitcomp "$(__git_refs)" -} - -_git_reset () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--merge --mixed --hard --soft --patch" - return - ;; - esac - __gitcomp "$(__git_refs)" -} - -_git_revert () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--edit --mainline --no-edit --no-commit --signoff" - return - ;; - esac - __gitcomp "$(__git_refs)" -} - -_git_rm () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--cached --dry-run --ignore-unmatch --quiet" - return - ;; - esac - COMPREPLY=() -} - -_git_shortlog () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - $__git_log_common_options - $__git_log_shortlog_options - --numbered --summary - " - return - ;; - esac - __git_complete_revlist -} - -_git_show () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --pretty=*) - __gitcomp "$__git_log_pretty_formats - " "" "${cur##--pretty=}" - return - ;; - --format=*) - __gitcomp "$__git_log_pretty_formats - " "" "${cur##--format=}" - return - ;; - --*) - __gitcomp "--pretty= --format= --abbrev-commit --oneline - $__git_diff_common_options - " - return - ;; - esac - __git_complete_file -} - -_git_show_branch () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp " - --all --remotes --topo-order --current --more= - --list --independent --merge-base --no-name - --color --no-color - --sha1-name --sparse --topics --reflog - " - return - ;; - esac - __git_complete_revlist -} - -_git_stash () -{ - local cur="${COMP_WORDS[COMP_CWORD]}" - local save_opts='--keep-index --no-keep-index --quiet --patch' - local subcommands='save list show apply clear drop pop create branch' - local subcommand="$(__git_find_on_cmdline "$subcommands")" - if [ -z "$subcommand" ]; then - case "$cur" in - --*) - __gitcomp "$save_opts" - ;; - *) - if [ -z "$(__git_find_on_cmdline "$save_opts")" ]; then - __gitcomp "$subcommands" - else - COMPREPLY=() - fi - ;; - esac - else - case "$subcommand,$cur" in - save,--*) - __gitcomp "$save_opts" - ;; - apply,--*|pop,--*) - __gitcomp "--index --quiet" - ;; - show,--*|drop,--*|branch,--*) - COMPREPLY=() - ;; - show,*|apply,*|drop,*|pop,*|branch,*) - __gitcomp "$(git --git-dir="$(__gitdir)" stash list \ - | sed -n -e 's/:.*//p')" - ;; - *) - COMPREPLY=() - ;; - esac - fi -} - -_git_submodule () -{ - __git_has_doubledash && return - - local subcommands="add status init update summary foreach sync" - if [ -z "$(__git_find_on_cmdline "$subcommands")" ]; then - local cur="${COMP_WORDS[COMP_CWORD]}" - case "$cur" in - --*) - __gitcomp "--quiet --cached" - ;; - *) - __gitcomp "$subcommands" - ;; - esac - return - fi -} - -_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 - --ignore-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= --use-log-author - --add-author-from $remote_opts - " - local cmt_opts=" - --edit --rmdir --find-copies-harder --copy-similarity= - " - - local cur="${COMP_WORDS[COMP_CWORD]}" - 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 $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" - ;; - *) - COMPREPLY=() - ;; - esac - fi -} - -_git_tag () -{ - local i c=1 f=0 - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" - case "$i" in - -d|-v) - __gitcomp "$(__git_tags)" - return - ;; - -f) - f=1 - ;; - esac - c=$((++c)) - done - - case "${COMP_WORDS[COMP_CWORD-1]}" in - -m|-F) - COMPREPLY=() - ;; - -*|tag) - if [ $f = 1 ]; then - __gitcomp "$(__git_tags)" - else - COMPREPLY=() - fi - ;; - *) - __gitcomp "$(__git_refs)" - ;; - esac -} - -_git_whatchanged () -{ - _git_log -} - -_git () -{ - local i c=1 command __git_dir - - while [ $c -lt $COMP_CWORD ]; do - i="${COMP_WORDS[c]}" - case "$i" in - --git-dir=*) __git_dir="${i#--git-dir=}" ;; - --bare) __git_dir="." ;; - --version|-p|--paginate) ;; - --help) command="help"; break ;; - *) command="$i"; break ;; - esac - c=$((++c)) - done - - if [ -z "$command" ]; then - case "${COMP_WORDS[COMP_CWORD]}" in - --*) __gitcomp " - --paginate - --no-pager - --git-dir= - --bare - --version - --exec-path - --html-path - --work-tree= - --help - " - ;; - *) __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") - if [ -n "$expansion" ]; then - completion_func="_git_${expansion//-/_}" - declare -F $completion_func >/dev/null && $completion_func - fi -} - -_gitk () -{ - __git_has_doubledash && return - - local cur="${COMP_WORDS[COMP_CWORD]}" - local g="$(__gitdir)" - local merge="" - if [ -f "$g/MERGE_HEAD" ]; then - merge="--merge" - fi - case "$cur" in - --*) - __gitcomp " - $__git_log_common_options - $__git_log_gitk_options - $merge - " - return - ;; - esac - __git_complete_revlist -} - -complete -o bashdefault -o default -o nospace -F _git git 2>/dev/null \ - || complete -o default -o nospace -F _git git -complete -o bashdefault -o default -o nospace -F _gitk gitk 2>/dev/null \ - || complete -o default -o nospace -F _gitk gitk - -# 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 -complete -o bashdefault -o default -o nospace -F _git git.exe 2>/dev/null \ - || complete -o default -o nospace -F _git git.exe -fi -#!/bin/bash -# These are the standard set of aliases enabled by default in all -# git-sh sessions. Aliases defined in the gitconfig [alias] section override -# these. - -gitalias a='git add' -gitalias b='git branch' -gitalias c='git checkout' -gitalias d='git diff' -gitalias f='git fetch --prune' -gitalias k='git cherry-pick' -gitalias l='git log --pretty=oneline --abbrev-commit' -gitalias n='git commit --verbose --amend' -gitalias r='git remote' -gitalias s='git commit --dry-run --short' -gitalias t='git diff --cached' - -# git add and the staging area -gitalias a='git add' -gitalias aa='git add --update' # mnemonic: "add all" -gitalias stage='git add' -gitalias ap='git add --patch' -gitalias p='git diff --cached' # mnemonic: "patch" -gitalias ps='git diff --cached --stat' # mnemonic: "patch stat" -gitalias unstage='git reset HEAD' - -# commits and history -gitalias ci='git commit --verbose' -gitalias ca='git commit --verbose --all' -gitalias amend='git commit --verbose --amend' -gitalias n='git commit --verbose --amend' -gitalias k='git cherry-pick' -gitalias re='git rebase --interactive' -gitalias pop='git reset --soft HEAD^' -gitalias peek='git log -p --max-count=1' - -# git fetch -gitalias f='git fetch' -gitalias pm='git pull' # mnemonic: pull merge -gitalias pr='git pull --rebase' # mnemonic: pull rebase - -# git diff -gitalias d='git diff' -gitalias ds='git diff --stat' # mnemonic: "diff stat" - -# git reset -gitalias hard='git reset --hard' -gitalias soft='git reset --soft' -gitalias scrap='git checkout HEAD' - -# CONFIG ============================================================== - -# load gitconfig [alias] section as top-level aliases. -_git_import_aliases - -# source the system-wide rc file -[ -r /etc/gitshrc ] && . /etc/gitshrc - -# source the user's rc file -[ -r ~/.gitshrc ] && . ~/.gitshrc diff --git a/bin/github-grab b/bin/github-grab deleted file mode 100755 index a51acc1..0000000 --- a/bin/github-grab +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -[ $# -eq 0 ] && { - echo "usage: github-grab username [repo]" - exit 1 -} - -username="$1" - -if [ -n "$2" ] ; then - repo="$2" -else - repo=$(basename $(pwd)) -fi - -command="git remote add $username git://github.com/$username/$repo.git" -echo $command -$command - -command="git fetch $username" -echo $command -$command diff --git a/bin/hub b/bin/hub deleted file mode 100755 index 9f3cdaa..0000000 --- a/bin/hub +++ /dev/null @@ -1,2482 +0,0 @@ -#!/usr/bin/env ruby -# -# This file is generated code. DO NOT send patches for it. -# -# Original source files with comments are at: -# https://github.com/defunkt/hub -# - -module Hub - Version = VERSION = '1.10.3' -end - -module Hub - class Args < Array - attr_accessor :executable - - def initialize(*args) - super - @executable = ENV["GIT"] || "git" - @after = nil - @skip = @noop = false - @original_args = args.first - @chain = [nil] - end - - def after(cmd_or_args = nil, args = nil, &block) - @chain.insert(-1, normalize_callback(cmd_or_args, args, block)) - end - - def before(cmd_or_args = nil, args = nil, &block) - @chain.insert(@chain.index(nil), normalize_callback(cmd_or_args, args, block)) - end - - def chained? - @chain.size > 1 - end - - def commands - chain = @chain.dup - chain[chain.index(nil)] = self.to_exec - chain - end - - def skip! - @skip = true - end - - def skip? - @skip - end - - def noop! - @noop = true - end - - def noop? - @noop - end - - def to_exec(args = self) - Array(executable) + args - end - - def add_exec_flags(flags) - self.executable = Array(executable).concat(flags) - end - - def words - reject { |arg| arg.index('-') == 0 } - end - - def flags - self - words - end - - def changed? - chained? or self != @original_args - end - - def has_flag?(*flags) - pattern = flags.flatten.map { |f| Regexp.escape(f) }.join('|') - !grep(/^#{pattern}(?:=|$)/).empty? - end - - private - - def normalize_callback(cmd_or_args, args, block) - if block - block - elsif args - [cmd_or_args].concat args - elsif Array === cmd_or_args - self.to_exec cmd_or_args - elsif cmd_or_args - cmd_or_args - else - raise ArgumentError, "command or block required" - end - end - end -end - -module Hub - class SshConfig - CONFIG_FILES = %w(~/.ssh/config /etc/ssh_config /etc/ssh/ssh_config) - - def initialize files = nil - @settings = Hash.new {|h,k| h[k] = {} } - Array(files || CONFIG_FILES).each do |path| - file = File.expand_path path - parse_file file if File.exist? file - end - end - - def get_value hostname, key - key = key.to_s.downcase - @settings.each do |pattern, settings| - if pattern.match? hostname and found = settings[key] - return found - end - end - yield - end - - class HostPattern - def initialize pattern - @pattern = pattern.to_s.downcase - end - - def to_s() @pattern end - def ==(other) other.to_s == self.to_s end - - def matcher - @matcher ||= - if '*' == @pattern - Proc.new { true } - elsif @pattern !~ /[?*]/ - lambda { |hostname| hostname.to_s.downcase == @pattern } - else - re = self.class.pattern_to_regexp @pattern - lambda { |hostname| re =~ hostname } - end - end - - def match? hostname - matcher.call hostname - end - - def self.pattern_to_regexp pattern - escaped = Regexp.escape(pattern) - escaped.gsub!('\*', '.*') - escaped.gsub!('\?', '.') - /^#{escaped}$/i - end - end - - def parse_file file - host_patterns = [HostPattern.new('*')] - - IO.foreach(file) do |line| - case line - when /^\s*(#|$)/ then next - when /^\s*(\S+)\s*=/ - key, value = $1, $' - else - key, value = line.strip.split(/\s+/, 2) - end - - next if value.nil? - key.downcase! - value = $1 if value =~ /^"(.*)"$/ - value.chomp! - - if 'host' == key - host_patterns = value.split(/\s+/).map {|p| HostPattern.new p } - else - record_setting key, value, host_patterns - end - end - end - - def record_setting key, value, patterns - patterns.each do |pattern| - @settings[pattern][key] ||= value - end - end - end -end - -require 'uri' -require 'yaml' -require 'forwardable' -require 'fileutils' - -module Hub - class GitHubAPI - attr_reader :config, :oauth_app_url - - def initialize config, options - @config = config - @oauth_app_url = options.fetch(:app_url) - end - - module Exceptions - def self.===(exception) - exception.class.ancestors.map {|a| a.to_s }.include? 'Net::HTTPExceptions' - end - end - - def api_host host - host = host.downcase - 'github.com' == host ? 'api.github.com' : host - end - - def repo_info project - get "https://%s/repos/%s/%s" % - [api_host(project.host), project.owner, project.name] - end - - def repo_exists? project - repo_info(project).success? - end - - def fork_repo project - res = post "https://%s/repos/%s/%s/forks" % - [api_host(project.host), project.owner, project.name] - res.error! unless res.success? - end - - def create_repo project, options = {} - is_org = project.owner != config.username(api_host(project.host)) - params = { :name => project.name, :private => !!options[:private] } - params[:description] = options[:description] if options[:description] - params[:homepage] = options[:homepage] if options[:homepage] - - if is_org - res = post "https://%s/orgs/%s/repos" % [api_host(project.host), project.owner], params - else - res = post "https://%s/user/repos" % api_host(project.host), params - end - res.error! unless res.success? - res.data - end - - def pullrequest_info project, pull_id - res = get "https://%s/repos/%s/%s/pulls/%d" % - [api_host(project.host), project.owner, project.name, pull_id] - res.error! unless res.success? - res.data - end - - def create_pullrequest options - project = options.fetch(:project) - params = { - :base => options.fetch(:base), - :head => options.fetch(:head) - } - - if options[:issue] - params[:issue] = options[:issue] - else - params[:title] = options[:title] if options[:title] - params[:body] = options[:body] if options[:body] - end - - res = post "https://%s/repos/%s/%s/pulls" % - [api_host(project.host), project.owner, project.name], params - - res.error! unless res.success? - res.data - end - - module HttpMethods - module ResponseMethods - def status() code.to_i end - def data?() content_type =~ /\bjson\b/ end - def data() @data ||= JSON.parse(body) end - def error_message?() data? and data['errors'] || data['message'] end - def error_message() error_sentences || data['message'] end - def success?() Net::HTTPSuccess === self end - def error_sentences - data['errors'].map do |err| - case err['code'] - when 'custom' then err['message'] - when 'missing_field' then "field '%s' is missing" % err['field'] - end - end.compact if data['errors'] - end - end - - def get url, &block - perform_request url, :Get, &block - end - - def post url, params = nil - perform_request url, :Post do |req| - if params - req.body = JSON.dump params - req['Content-Type'] = 'application/json;charset=utf-8' - end - yield req if block_given? - req['Content-Length'] = byte_size req.body - end - end - - def byte_size str - if str.respond_to? :bytesize then str.bytesize - elsif str.respond_to? :length then str.length - else 0 - end - end - - def post_form url, params - post(url) {|req| req.set_form_data params } - end - - def perform_request url, type - url = URI.parse url unless url.respond_to? :host - - require 'net/https' - req = Net::HTTP.const_get(type).new request_uri(url) - http = configure_connection(req, url) do |host_url| - create_connection host_url - end - - apply_authentication(req, url) - yield req if block_given? - - begin - res = http.start { http.request(req) } - res.extend ResponseMethods - return res - rescue SocketError => err - raise Context::FatalError, "error with #{type.to_s.upcase} #{url} (#{err.message})" - end - end - - def request_uri url - str = url.request_uri - str = '/api/v3' << str if url.host != 'api.github.com' - str - end - - def configure_connection req, url - if ENV['HUB_TEST_HOST'] - req['Host'] = url.host - url = url.dup - url.scheme = 'http' - url.host, test_port = ENV['HUB_TEST_HOST'].split(':') - url.port = test_port.to_i if test_port - end - yield url - end - - def apply_authentication req, url - user = url.user || config.username(url.host) - pass = config.password(url.host, user) - req.basic_auth user, pass - end - - def create_connection url - use_ssl = 'https' == url.scheme - - proxy_args = [] - if proxy = config.proxy_uri(use_ssl) - proxy_args << proxy.host << proxy.port - if proxy.userinfo - require 'cgi' - proxy_args.concat proxy.userinfo.split(':', 2).map {|a| CGI.unescape a } - end - end - - http = Net::HTTP.new(url.host, url.port, *proxy_args) - - if http.use_ssl = use_ssl - http.verify_mode = OpenSSL::SSL::VERIFY_NONE - end - return http - end - end - - module OAuth - def apply_authentication req, url - if (req.path =~ /\/authorizations$/) - super - else - user = url.user || config.username(url.host) - token = config.oauth_token(url.host, user) { - obtain_oauth_token url.host, user - } - req['Authorization'] = "token #{token}" - end - end - - def obtain_oauth_token host, user - res = get "https://#{user}@#{host}/authorizations" - res.error! unless res.success? - - if found = res.data.find {|auth| auth['app']['url'] == oauth_app_url } - found['token'] - else - res = post "https://#{user}@#{host}/authorizations", - :scopes => %w[repo], :note => 'hub', :note_url => oauth_app_url - res.error! unless res.success? - res.data['token'] - end - end - end - - include HttpMethods - include OAuth - - class FileStore - extend Forwardable - def_delegator :@data, :[], :get - def_delegator :@data, :[]=, :set - - def initialize filename - @filename = filename - @data = Hash.new {|d, host| d[host] = [] } - load if File.exist? filename - end - - def fetch_user host - unless entry = get(host).first - user = yield - return nil if user.nil? or user.empty? - entry = entry_for_user(host, user) - end - entry['user'] - end - - def fetch_value host, user, key - entry = entry_for_user host, user - entry[key.to_s] || begin - value = yield - if value and !value.empty? - entry[key.to_s] = value - save - value - else - raise "no value" - end - end - end - - def entry_for_user host, username - entries = get(host) - entries.find {|e| e['user'] == username } or - (entries << {'user' => username}).last - end - - def load - existing_data = File.read(@filename) - @data.update YAML.load(existing_data) unless existing_data.strip.empty? - end - - def save - FileUtils.mkdir_p File.dirname(@filename) - File.open(@filename, 'w', 0600) {|f| f << YAML.dump(@data) } - end - end - - class Configuration - def initialize store - @data = store - @password_cache = {} - end - - def normalize_host host - host = host.downcase - 'api.github.com' == host ? 'github.com' : host - end - - def username host - return ENV['GITHUB_USER'] unless ENV['GITHUB_USER'].to_s.empty? - host = normalize_host host - @data.fetch_user host do - if block_given? then yield - else prompt "#{host} username" - end - end - end - - def api_token host, user - host = normalize_host host - @data.fetch_value host, user, :api_token do - if block_given? then yield - else prompt "#{host} API token for #{user}" - end - end - end - - def password host, user - return ENV['GITHUB_PASSWORD'] unless ENV['GITHUB_PASSWORD'].to_s.empty? - host = normalize_host host - @password_cache["#{user}@#{host}"] ||= prompt_password host, user - end - - def oauth_token host, user, &block - @data.fetch_value normalize_host(host), user, :oauth_token, &block - end - - def prompt what - print "#{what}: " - $stdin.gets.chomp - end - - def prompt_password host, user - print "#{host} password for #{user} (never stored): " - if $stdin.tty? - password = askpass - puts '' - password - else - $stdin.gets.chomp - end - end - - def askpass - tty_state = `stty -g` - system 'stty raw -echo -icanon isig' if $?.success? - pass = '' - while char = $stdin.getbyte and !(char == 13 or char == 10) - if char == 127 or char == 8 - pass[-1,1] = '' unless pass.empty? - else - pass << char.chr - end - end - pass - ensure - system "stty #{tty_state}" unless tty_state.empty? - end - - def proxy_uri(with_ssl) - env_name = "HTTP#{with_ssl ? 'S' : ''}_PROXY" - if proxy = ENV[env_name] || ENV[env_name.downcase] and !proxy.empty? - proxy = "http://#{proxy}" unless proxy.include? '://' - URI.parse proxy - end - end - end - end -end - -require 'shellwords' -require 'forwardable' -require 'uri' - -module Hub - module Context - extend Forwardable - - NULL = defined?(File::NULL) ? File::NULL : File.exist?('/dev/null') ? '/dev/null' : 'NUL' - - class GitReader - attr_reader :executable - - def initialize(executable = nil, &read_proc) - @executable = executable || 'git' - read_proc ||= lambda { |cache, cmd| - result = %x{#{command_to_string(cmd)} 2>#{NULL}}.chomp - cache[cmd] = $?.success? && !result.empty? ? result : nil - } - @cache = Hash.new(&read_proc) - end - - def add_exec_flags(flags) - @executable = Array(executable).concat(flags) - end - - def read_config(cmd, all = false) - config_cmd = ['config', (all ? '--get-all' : '--get'), *cmd] - config_cmd = config_cmd.join(' ') unless cmd.respond_to? :join - read config_cmd - end - - def read(cmd) - @cache[cmd] - end - - def stub_config_value(key, value, get = '--get') - stub_command_output "config #{get} #{key}", value - end - - def stub_command_output(cmd, value) - @cache[cmd] = value.nil? ? nil : value.to_s - end - - def stub!(values) - @cache.update values - end - - private - - def to_exec(args) - args = Shellwords.shellwords(args) if args.respond_to? :to_str - Array(executable) + Array(args) - end - - def command_to_string(cmd) - full_cmd = to_exec(cmd) - full_cmd.respond_to?(:shelljoin) ? full_cmd.shelljoin : full_cmd.join(' ') - end - end - - module GitReaderMethods - extend Forwardable - - def_delegator :git_reader, :read_config, :git_config - def_delegator :git_reader, :read, :git_command - - def self.extended(base) - base.extend Forwardable - base.def_delegators :'self.class', :git_config, :git_command - end - end - - class Error < RuntimeError; end - class FatalError < Error; end - - private - - def git_reader - @git_reader ||= GitReader.new ENV['GIT'] - end - - include GitReaderMethods - private :git_config, :git_command - - def local_repo(fatal = true) - @local_repo ||= begin - if is_repo? - LocalRepo.new git_reader, current_dir - elsif fatal - raise FatalError, "Not a git repository" - end - end - end - - repo_methods = [ - :current_branch, - :current_project, :upstream_project, - :repo_owner, :repo_host, - :remotes, :remotes_group, :origin_remote - ] - def_delegator :local_repo, :name, :repo_name - def_delegators :local_repo, *repo_methods - private :repo_name, *repo_methods - - def master_branch - if local_repo(false) - local_repo.master_branch - else - Branch.new nil, 'refs/heads/master' - end - end - - class LocalRepo < Struct.new(:git_reader, :dir) - include GitReaderMethods - - def name - if project = main_project - project.name - else - File.basename(dir) - end - end - - def repo_owner - if project = main_project - project.owner - end - end - - def repo_host - project = main_project and project.host - end - - def main_project - remote = origin_remote and remote.project - end - - def upstream_project - if branch = current_branch and upstream = branch.upstream and upstream.remote? - remote = remote_by_name upstream.remote_name - remote.project - end - end - - def current_project - upstream_project || main_project - end - - def current_branch - if branch = git_command('symbolic-ref -q HEAD') - Branch.new self, branch - end - end - - def master_branch - Branch.new self, 'refs/heads/master' - end - - def remotes - @remotes ||= begin - list = git_command('remote').to_s.split("\n") - main = list.delete('origin') and list.unshift(main) - list.map { |name| Remote.new self, name } - end - end - - def remotes_group(name) - git_config "remotes.#{name}" - end - - def origin_remote - remotes.first - end - - def remote_by_name(remote_name) - remotes.find {|r| r.name == remote_name } - end - - def known_hosts - hosts = git_config('hub.host', :all).to_s.split("\n") - hosts << default_host - hosts << "ssh.#{default_host}" - end - - def self.default_host - ENV['GITHUB_HOST'] || main_host - end - - def self.main_host - 'github.com' - end - - extend Forwardable - def_delegators :'self.class', :default_host, :main_host - - def ssh_config - @ssh_config ||= SshConfig.new - end - end - - class GithubProject < Struct.new(:local_repo, :owner, :name, :host) - def self.from_url(url, local_repo) - if local_repo.known_hosts.include? url.host - _, owner, name = url.path.split('/', 4) - GithubProject.new(local_repo, owner, name.sub(/\.git$/, ''), url.host) - end - end - - attr_accessor :repo_data - - def initialize(*args) - super - self.name = self.name.tr(' ', '-') - self.host ||= (local_repo || LocalRepo).default_host - self.host = host.sub(/^ssh\./i, '') if 'ssh.github.com' == host.downcase - end - - def private? - repo_data ? repo_data.fetch('private') : - host != (local_repo || LocalRepo).main_host - end - - def owned_by(new_owner) - new_project = dup - new_project.owner = new_owner - new_project - end - - def name_with_owner - "#{owner}/#{name}" - end - - def ==(other) - name_with_owner == other.name_with_owner - end - - def remote - local_repo.remotes.find { |r| r.project == self } - end - - def web_url(path = nil) - project_name = name_with_owner - if project_name.sub!(/\.wiki$/, '') - unless '/wiki' == path - path = if path =~ %r{^/commits/} then '/_history' - else path.to_s.sub(/\w+/, '_\0') - end - path = '/wiki' + path - end - end - "https://#{host}/" + project_name + path.to_s - end - - def git_url(options = {}) - if options[:https] then "https://#{host}/" - elsif options[:private] or private? then "git@#{host}:" - else "git://#{host}/" - end + name_with_owner + '.git' - end - end - - class GithubURL < URI::HTTPS - extend Forwardable - - attr_reader :project - def_delegator :project, :name, :project_name - def_delegator :project, :owner, :project_owner - - def self.resolve(url, local_repo) - u = URI(url) - if %[http https].include? u.scheme and project = GithubProject.from_url(u, local_repo) - self.new(u.scheme, u.userinfo, u.host, u.port, u.registry, - u.path, u.opaque, u.query, u.fragment, project) - end - rescue URI::InvalidURIError - nil - end - - def initialize(*args) - @project = args.pop - super(*args) - end - - def project_path - path.split('/', 4)[3] - end - end - - class Branch < Struct.new(:local_repo, :name) - alias to_s name - - def short_name - name.sub(%r{^refs/(remotes/)?.+?/}, '') - end - - def master? - short_name == 'master' - end - - def upstream - if branch = local_repo.git_command("rev-parse --symbolic-full-name #{short_name}@{upstream}") - Branch.new local_repo, branch - end - end - - def remote? - name.index('refs/remotes/') == 0 - end - - def remote_name - name =~ %r{^refs/remotes/([^/]+)} and $1 or - raise Error, "can't get remote name from #{name.inspect}" - end - end - - class Remote < Struct.new(:local_repo, :name) - alias to_s name - - def ==(other) - other.respond_to?(:to_str) ? name == other.to_str : super - end - - def project - urls.each_value { |url| - if valid = GithubProject.from_url(url, local_repo) - return valid - end - } - nil - end - - def urls - return @urls if defined? @urls - @urls = {} - local_repo.git_command('remote -v').to_s.split("\n").map do |line| - next if line !~ /^(.+?)\t(.+) \((.+)\)$/ - remote, uri, type = $1, $2, $3 - next if remote != self.name - if uri =~ %r{^[\w-]+://} or uri =~ %r{^([^/]+?):} - uri = "ssh://#{$1}/#{$'}" if $1 - begin - @urls[type] = uri_parse(uri) - rescue URI::InvalidURIError - end - end - end - @urls - end - - def uri_parse uri - uri = URI.parse uri - uri.host = local_repo.ssh_config.get_value(uri.host, 'hostname') { uri.host } - uri.user = local_repo.ssh_config.get_value(uri.host, 'user') { uri.user } - uri - end - end - - - def github_project(name, owner = nil) - if owner and owner.index('/') - owner, name = owner.split('/', 2) - elsif name and name.index('/') - owner, name = name.split('/', 2) - else - name ||= repo_name - owner ||= github_user - end - - if local_repo(false) and main_project = local_repo.main_project - project = main_project.dup - project.owner = owner - project.name = name - project - else - GithubProject.new(local_repo(false), owner, name) - end - end - - def git_url(owner = nil, name = nil, options = {}) - project = github_project(name, owner) - project.git_url({:https => https_protocol?}.update(options)) - end - - def resolve_github_url(url) - GithubURL.resolve(url, local_repo) if url =~ /^https?:/ - end - - def http_clone? - git_config('--bool hub.http-clone') == 'true' - end - - def https_protocol? - git_config('hub.protocol') == 'https' or http_clone? - end - - def git_alias_for(name) - git_config "alias.#{name}" - end - - def rev_list(a, b) - git_command("rev-list --cherry-pick --right-only --no-merges #{a}...#{b}") - end - - PWD = Dir.pwd - - def current_dir - PWD - end - - def git_dir - git_command 'rev-parse -q --git-dir' - end - - def is_repo? - !!git_dir - end - - def git_editor - editor = git_command 'var GIT_EDITOR' - editor = ENV[$1] if editor =~ /^\$(\w+)$/ - editor = File.expand_path editor if (editor =~ /^[~.]/ or editor.index('/')) and editor !~ /["']/ - editor.shellsplit - end - - module System - def browser_launcher - browser = ENV['BROWSER'] || ( - osx? ? 'open' : windows? ? %w[cmd /c start] : - %w[xdg-open cygstart x-www-browser firefox opera mozilla netscape].find { |comm| which comm } - ) - - abort "Please set $BROWSER to a web launcher to use this command." unless browser - Array(browser) - end - - def osx? - require 'rbconfig' - RbConfig::CONFIG['host_os'].to_s.include?('darwin') - end - - def windows? - require 'rbconfig' - RbConfig::CONFIG['host_os'] =~ /msdos|mswin|djgpp|mingw|windows/ - end - - def which(cmd) - exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] - ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| - exts.each { |ext| - exe = "#{path}/#{cmd}#{ext}" - return exe if File.executable? exe - } - end - return nil - end - - def command?(name) - !which(name).nil? - end - end - - include System - extend System - end -end - -require 'strscan' -require 'forwardable' - -class Hub::JSON - def self.parse(data) new(data).parse end - - WSP = /\s+/ - OBJ = /[{\[]/; HEN = /\}/; AEN = /\]/ - COL = /\s*:\s*/; KEY = /\s*,\s*/ - NUM = /-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/ - BOL = /true|false/; NUL = /null/ - - extend Forwardable - - attr_reader :scanner - alias_method :s, :scanner - def_delegators :scanner, :scan, :matched - private :s, :scan, :matched - - def initialize data - @scanner = StringScanner.new data.to_s - end - - def parse - space - object - end - - private - - def space() scan WSP end - - def endkey() scan(KEY) or space end - - def object - matched == '{' ? hash : array if scan(OBJ) - end - - def value - object or string or - scan(NUL) ? nil : - scan(BOL) ? matched.size == 4: - scan(NUM) ? eval(matched) : - error - end - - def hash - obj = {} - space - repeat_until(HEN) { k = string; scan(COL); obj[k] = value; endkey } - obj - end - - def array - ary = [] - space - repeat_until(AEN) { ary << value; endkey } - ary - end - - SPEC = {'b' => "\b", 'f' => "\f", 'n' => "\n", 'r' => "\r", 't' => "\t"} - UNI = 'u'; CODE = /[a-fA-F0-9]{4}/ - STR = /"/; STE = '"' - ESC = '\\' - - def string - if scan(STR) - str, esc = '', false - while c = s.getch - if esc - str << (c == UNI ? (s.scan(CODE) || error).to_i(16).chr : SPEC[c] || c) - esc = false - else - case c - when ESC then esc = true - when STE then break - else str << c - end - end - end - str - end - end - - def error - raise "parse error at: #{scan(/.{1,10}/m).inspect}" - end - - def repeat_until reg - until scan(reg) - pos = s.pos - yield - error unless s.pos > pos - end - end - - module Generator - def generate(obj) - raise ArgumentError unless obj.is_a? Array or obj.is_a? Hash - generate_type(obj) - end - alias dump generate - - private - - def generate_type(obj) - type = obj.is_a?(Numeric) ? :Numeric : obj.class.name - begin send(:"generate_#{type}", obj) - rescue NoMethodError; raise ArgumentError, "can't serialize #{type}" - end - end - - ESC_MAP = Hash.new {|h,k| k }.update \ - "\r" => 'r', - "\n" => 'n', - "\f" => 'f', - "\t" => 't', - "\b" => 'b' - - def generate_String(str) - escaped = str.gsub(/[\r\n\f\t\b"\\]/) { "\\#{ESC_MAP[$&]}"} - %("#{escaped}") - end - - def generate_simple(obj) obj.inspect end - alias generate_Numeric generate_simple - alias generate_TrueClass generate_simple - alias generate_FalseClass generate_simple - - def generate_Symbol(sym) generate_String(sym.to_s) end - - def generate_NilClass(*) 'null' end - - def generate_Array(ary) '[%s]' % ary.map {|o| generate_type(o) }.join(', ') end - - def generate_Hash(hash) - '{%s}' % hash.map { |key, value| - "#{generate_String(key.to_s)}: #{generate_type(value)}" - }.join(', ') - end - end - - extend Generator -end - -module Hub - module Commands - instance_methods.each { |m| undef_method(m) unless m =~ /(^__|send|to\?$)/ } - extend self - - extend Context - - NAME_RE = /[\w.][\w.-]*/ - OWNER_RE = /[a-zA-Z0-9-]+/ - NAME_WITH_OWNER_RE = /^(?:#{NAME_RE}|#{OWNER_RE}\/#{NAME_RE})$/ - - CUSTOM_COMMANDS = %w[alias create browse compare fork pull-request] - - def run(args) - slurp_global_flags(args) - - args.unshift 'help' if args.empty? - - cmd = args[0] - if expanded_args = expand_alias(cmd) - cmd = expanded_args[0] - expanded_args.concat args[1..-1] - end - - respect_help_flags(expanded_args || args) if custom_command? cmd - - cmd = cmd.gsub(/(\w)-/, '\1_') - if method_defined?(cmd) and cmd != 'run' - args.replace expanded_args if expanded_args - send(cmd, args) - end - rescue Errno::ENOENT - if $!.message.include? "No such file or directory - git" - abort "Error: `git` command not found" - else - raise - end - rescue Context::FatalError => err - abort "fatal: #{err.message}" - end - - def pull_request(args) - args.shift - options = { } - force = explicit_owner = false - base_project = local_repo.main_project - head_project = local_repo.current_project - - unless base_project - abort "Aborted: the origin remote doesn't point to a GitHub repository." - end - - from_github_ref = lambda do |ref, context_project| - if ref.index(':') - owner, ref = ref.split(':', 2) - project = github_project(context_project.name, owner) - end - [project || context_project, ref] - end - - while arg = args.shift - case arg - when '-f' - force = true - when '-b' - base_project, options[:base] = from_github_ref.call(args.shift, base_project) - when '-h' - head = args.shift - explicit_owner = !!head.index(':') - head_project, options[:head] = from_github_ref.call(head, head_project) - when '-i' - options[:issue] = args.shift - else - if url = resolve_github_url(arg) and url.project_path =~ /^issues\/(\d+)/ - options[:issue] = $1 - base_project = url.project - elsif !options[:title] then options[:title] = arg - else - abort "invalid argument: #{arg}" - end - end - end - - options[:project] = base_project - options[:base] ||= master_branch.short_name - - if tracked_branch = options[:head].nil? && current_branch.upstream - if !tracked_branch.remote? - tracked_branch = nil - elsif base_project == head_project and tracked_branch.short_name == options[:base] - $stderr.puts "Aborted: head branch is the same as base (#{options[:base].inspect})" - warn "(use `-h ` to specify an explicit pull request head)" - abort - end - end - options[:head] ||= (tracked_branch || current_branch).short_name - - user = github_user(head_project.host) - if head_project.owner != user and !tracked_branch and !explicit_owner - head_project = head_project.owned_by(user) - end - - remote_branch = "#{head_project.remote}/#{options[:head]}" - options[:head] = "#{head_project.owner}:#{options[:head]}" - - if !force and tracked_branch and local_commits = rev_list(remote_branch, nil) - $stderr.puts "Aborted: #{local_commits.split("\n").size} commits are not yet pushed to #{remote_branch}" - warn "(use `-f` to force submit a pull request anyway)" - abort - end - - if args.noop? - puts "Would request a pull to #{base_project.owner}:#{options[:base]} from #{options[:head]}" - exit - end - - unless options[:title] or options[:issue] - base_branch = "#{base_project.remote}/#{options[:base]}" - commits = rev_list(base_branch, remote_branch).to_s.split("\n") - - case commits.size - when 0 - default_message = commit_summary = nil - when 1 - format = '%w(78,0,0)%s%n%+b' - default_message = git_command "show -s --format='#{format}' #{commits.first}" - commit_summary = nil - else - format = '%h (%aN, %ar)%n%w(78,3,3)%s%n%+b' - default_message = nil - commit_summary = git_command "log --no-color --format='%s' --cherry %s...%s" % - [format, base_branch, remote_branch] - end - - options[:title], options[:body] = pullrequest_editmsg(commit_summary) { |msg| - msg.puts default_message if default_message - msg.puts "" - msg.puts "# Requesting a pull to #{base_project.owner}:#{options[:base]} from #{options[:head]}" - msg.puts "#" - msg.puts "# Write a message for this pull request. The first block" - msg.puts "# of text is the title and the rest is description." - } - end - - pull = api_client.create_pullrequest(options) - - args.executable = 'echo' - args.replace [pull['html_url']] - rescue GitHubAPI::Exceptions - display_api_exception("creating pull request", $!.response) - exit 1 - end - - def clone(args) - ssh = args.delete('-p') - has_values = /^(--(upload-pack|template|depth|origin|branch|reference)|-[ubo])$/ - - idx = 1 - while idx < args.length - arg = args[idx] - if arg.index('-') == 0 - idx += 1 if arg =~ has_values - else - if arg =~ NAME_WITH_OWNER_RE and !File.directory?(arg) - name, owner = arg, nil - owner, name = name.split('/', 2) if name.index('/') - project = github_project(name, owner || github_user) - ssh ||= args[0] != 'submodule' && project.owner == github_user(project.host) { } - args[idx] = project.git_url(:private => ssh, :https => https_protocol?) - end - break - end - idx += 1 - end - end - - def submodule(args) - return unless index = args.index('add') - args.delete_at index - - branch = args.index('-b') || args.index('--branch') - if branch - args.delete_at branch - branch_name = args.delete_at branch - end - - clone(args) - - if branch_name - args.insert branch, '-b', branch_name - end - args.insert index, 'add' - end - - def remote(args) - if %w[add set-url].include?(args[1]) - name = args.last - if name =~ /^(#{OWNER_RE})$/ || name =~ /^(#{OWNER_RE})\/(#{NAME_RE})$/ - user, repo = $1, $2 || repo_name - end - end - return unless user # do not touch arguments - - ssh = args.delete('-p') - - if args.words[2] == 'origin' && args.words[3].nil? - user, repo = github_user, repo_name - elsif args.words[-2] == args.words[1] - idx = args.index( args.words[-1] ) - args[idx] = user - else - args.pop - end - - args << git_url(user, repo, :private => ssh) - end - - def fetch(args) - if args.include?('--multiple') - names = args.words[1..-1] - elsif remote_name = args.words[1] - if remote_name =~ /^\w+(,\w+)+$/ - index = args.index(remote_name) - args.delete(remote_name) - names = remote_name.split(',') - args.insert(index, *names) - args.insert(index, '--multiple') - else - names = [remote_name] - end - else - names = [] - end - - projects = names.map { |name| - unless name =~ /\W/ or remotes.include?(name) or remotes_group(name) - project = github_project(nil, name) - repo_info = api_client.repo_info(project) - if repo_info.success? - project.repo_data = repo_info.data - project - end - end - }.compact - - if projects.any? - projects.each do |project| - args.before ['remote', 'add', project.owner, project.git_url(:https => https_protocol?)] - end - end - end - - def checkout(args) - _, url_arg, new_branch_name = args.words - if url = resolve_github_url(url_arg) and url.project_path =~ /^pull\/(\d+)/ - pull_id = $1 - pull_data = api_client.pullrequest_info(url.project, pull_id) - - args.delete new_branch_name - user, branch = pull_data['head']['label'].split(':', 2) - abort "Error: #{user}'s fork is not available anymore" unless pull_data['head']['repo'] - new_branch_name ||= "#{user}-#{branch}" - - if remotes.include? user - args.before ['remote', 'set-branches', '--add', user, branch] - args.before ['fetch', user, "+refs/heads/#{branch}:refs/remotes/#{user}/#{branch}"] - else - url = github_project(url.project_name, user).git_url(:private => pull_data['head']['repo']['private'], - :https => https_protocol?) - args.before ['remote', 'add', '-f', '-t', branch, user, url] - end - idx = args.index url_arg - args.delete_at idx - args.insert idx, '--track', '-B', new_branch_name, "#{user}/#{branch}" - end - end - - def merge(args) - _, url_arg = args.words - if url = resolve_github_url(url_arg) and url.project_path =~ /^pull\/(\d+)/ - pull_id = $1 - pull_data = api_client.pullrequest_info(url.project, pull_id) - - user, branch = pull_data['head']['label'].split(':', 2) - abort "Error: #{user}'s fork is not available anymore" unless pull_data['head']['repo'] - - url = github_project(url.project_name, user).git_url(:private => pull_data['head']['repo']['private'], - :https => https_protocol?) - - merge_head = "#{user}/#{branch}" - args.before ['fetch', url, "+refs/heads/#{branch}:refs/remotes/#{merge_head}"] - - idx = args.index url_arg - args.delete_at idx - args.insert idx, merge_head, '--no-ff', '-m', - "Merge pull request ##{pull_id} from #{merge_head}\n\n#{pull_data['title']}" - end - end - - def cherry_pick(args) - unless args.include?('-m') or args.include?('--mainline') - ref = args.words.last - if url = resolve_github_url(ref) and url.project_path =~ /^commit\/([a-f0-9]{7,40})/ - sha = $1 - project = url.project - elsif ref =~ /^(#{OWNER_RE})@([a-f0-9]{7,40})$/ - owner, sha = $1, $2 - project = local_repo.main_project.owned_by(owner) - end - - if project - args[args.index(ref)] = sha - - if remote = project.remote and remotes.include? remote - args.before ['fetch', remote.to_s] - else - args.before ['remote', 'add', '-f', project.owner, project.git_url(:https => https_protocol?)] - end - end - end - end - - def am(args) - if url = args.find { |a| a =~ %r{^https?://(gist\.)?github\.com/} } - idx = args.index(url) - gist = $1 == 'gist.' - url = url.sub(/#.+/, '') - url = url.sub(%r{(/pull/\d+)/\w*$}, '\1') unless gist - ext = gist ? '.txt' : '.patch' - url += ext unless File.extname(url) == ext - patch_file = File.join(ENV['TMPDIR'] || '/tmp', "#{gist ? 'gist-' : ''}#{File.basename(url)}") - args.before 'curl', ['-#LA', "hub #{Hub::Version}", url, '-o', patch_file] - args[idx] = patch_file - end - end - - alias_method :apply, :am - - def init(args) - if args.delete('-g') - project = github_project(File.basename(current_dir)) - url = project.git_url(:private => true, :https => https_protocol?) - args.after ['remote', 'add', 'origin', url] - end - end - - def fork(args) - unless project = local_repo.main_project - abort "Error: repository under 'origin' remote is not a GitHub project" - end - forked_project = project.owned_by(github_user(project.host)) - - existing_repo = api_client.repo_info(forked_project) - if existing_repo.success? - parent_data = existing_repo.data['parent'] - parent_url = parent_data && resolve_github_url(parent_data['html_url']) - if !parent_url or parent_url.project != project - abort "Error creating fork: %s already exists on %s" % - [ forked_project.name_with_owner, forked_project.host ] - end - else - api_client.fork_repo(project) unless args.noop? - end - - if args.include?('--no-remote') - exit - else - url = forked_project.git_url(:private => true, :https => https_protocol?) - args.replace %W"remote add -f #{forked_project.owner} #{url}" - args.after 'echo', ['new remote:', forked_project.owner] - end - rescue GitHubAPI::Exceptions - display_api_exception("creating fork", $!.response) - exit 1 - end - - def create(args) - if !is_repo? - abort "'create' must be run from inside a git repository" - else - owner = github_user - args.shift - options = {} - options[:private] = true if args.delete('-p') - new_repo_name = nil - - until args.empty? - case arg = args.shift - when '-d' - options[:description] = args.shift - when '-h' - options[:homepage] = args.shift - else - if arg =~ /^[^-]/ and new_repo_name.nil? - new_repo_name = arg - owner, new_repo_name = new_repo_name.split('/', 2) if new_repo_name.index('/') - else - abort "invalid argument: #{arg}" - end - end - end - new_repo_name ||= repo_name - new_project = github_project(new_repo_name, owner) - - if api_client.repo_exists?(new_project) - warn "#{new_project.name_with_owner} already exists on #{new_project.host}" - action = "set remote origin" - else - action = "created repository" - unless args.noop? - repo_data = api_client.create_repo(new_project, options) - new_project = github_project(repo_data['full_name']) - end - end - - url = new_project.git_url(:private => true, :https => https_protocol?) - - if remotes.first != 'origin' - args.replace %W"remote add -f origin #{url}" - else - args.replace %W"remote -v" - end - - args.after 'echo', ["#{action}:", new_project.name_with_owner] - end - rescue GitHubAPI::Exceptions - display_api_exception("creating repository", $!.response) - exit 1 - end - - def push(args) - return if args[1].nil? || !args[1].index(',') - - refs = args.words[2..-1] - remotes = args[1].split(',') - args[1] = remotes.shift - - if refs.empty? - refs = [current_branch.short_name] - args.concat refs - end - - remotes.each do |name| - args.after ['push', name, *refs] - end - end - - def browse(args) - args.shift - browse_command(args) do - dest = args.shift - dest = nil if dest == '--' - - if dest - project = github_project dest - branch = master_branch - else - project = current_project - branch = current_branch && current_branch.upstream || master_branch - end - - abort "Usage: hub browse [/]" unless project - - path = case subpage = args.shift - when 'commits' - "/commits/#{branch.short_name}" - when 'tree', NilClass - "/tree/#{branch.short_name}" if branch and !branch.master? - else - "/#{subpage}" - end - - project.web_url(path) - end - end - - def compare(args) - args.shift - browse_command(args) do - if args.empty? - branch = current_branch.upstream - if branch and not branch.master? - range = branch.short_name - project = current_project - else - abort "Usage: hub compare [USER] [...]" - end - else - sha_or_tag = /(\w{1,2}|\w[\w.-]+\w)/ - range = args.pop.sub(/^#{sha_or_tag}\.\.#{sha_or_tag}$/, '\1...\2') - project = if owner = args.pop then github_project(nil, owner) - else current_project - end - end - - project.web_url "/compare/#{range}" - end - end - - def hub(args) - return help(args) unless args[1] == 'standalone' - require 'hub/standalone' - Hub::Standalone.build $stdout - exit - rescue LoadError - abort "hub is already running in standalone mode." - rescue Errno::EPIPE - exit # ignore broken pipe - end - - def alias(args) - shells = %w[bash zsh sh ksh csh fish] - - script = !!args.delete('-s') - shell = args[1] || ENV['SHELL'] - abort "hub alias: unknown shell" if shell.nil? or shell.empty? - shell = File.basename shell - - unless shells.include? shell - $stderr.puts "hub alias: unsupported shell" - warn "supported shells: #{shells.join(' ')}" - abort - end - - if script - puts "alias git=hub" - if 'zsh' == shell - puts "if type compdef >/dev/null; then" - puts " compdef hub=git" - puts "fi" - end - else - profile = case shell - when 'bash' then '~/.bash_profile' - when 'zsh' then '~/.zshrc' - when 'ksh' then '~/.profile' - else - 'your profile' - end - - puts "# Wrap git automatically by adding the following to #{profile}:" - puts - puts 'eval "$(hub alias -s)"' - end - - exit - end - - def version(args) - args.after 'echo', ['hub version', Version] - end - alias_method "--version", :version - - def help(args) - command = args.words[1] - - if command == 'hub' - puts hub_manpage - exit - elsif command.nil? && !args.has_flag?('-a', '--all') - ENV['GIT_PAGER'] = '' unless args.has_flag?('-p', '--paginate') # Use `cat`. - puts improved_help_text - exit - end - end - alias_method "--help", :help - - private - - def api_client - @api_client ||= begin - config_file = ENV['HUB_CONFIG'] || '~/.config/hub' - file_store = GitHubAPI::FileStore.new File.expand_path(config_file) - file_config = GitHubAPI::Configuration.new file_store - GitHubAPI.new file_config, :app_url => 'http://defunkt.io/hub/' - end - end - - def github_user host = nil, &block - host ||= (local_repo(false) || Context::LocalRepo).default_host - api_client.config.username(host, &block) - end - - def custom_command? cmd - CUSTOM_COMMANDS.include? cmd - end - - def respect_help_flags args - return if args.size > 2 - case args[1] - when '-h' - pattern = /(git|hub) #{Regexp.escape args[0].gsub('-', '\-')}/ - hub_raw_manpage.each_line { |line| - if line =~ pattern - $stderr.print "Usage: " - $stderr.puts line.gsub(/\\f./, '').gsub('\-', '-') - abort - end - } - abort "Error: couldn't find usage help for #{args[0]}" - when '--help' - puts hub_manpage - exit - end - end - - def improved_help_text - <<-help -usage: git [--version] [--exec-path[=]] [--html-path] [--man-path] [--info-path] - [-p|--paginate|--no-pager] [--no-replace-objects] [--bare] - [--git-dir=] [--work-tree=] [--namespace=] - [-c name=value] [--help] - [] - -Basic Commands: - init Create an empty git repository or reinitialize an existing one - add Add new or modified files to the staging area - rm Remove files from the working directory and staging area - mv Move or rename a file, a directory, or a symlink - status Show the status of the working directory and staging area - commit Record changes to the repository - -History Commands: - log Show the commit history log - diff Show changes between commits, commit and working tree, etc - show Show information about commits, tags or files - -Branching Commands: - branch List, create, or delete branches - checkout Switch the active branch to another branch - merge Join two or more development histories (branches) together - tag Create, list, delete, sign or verify a tag object - -Remote Commands: - clone Clone a remote repository into a new directory - fetch Download data, tags and branches from a remote repository - pull Fetch from and merge with another repository or a local branch - push Upload data, tags and branches to a remote repository - remote View and manage a set of remote repositories - -Advanced Commands: - reset Reset your staging area or working directory to another point - rebase Re-apply a series of patches in one branch onto another - bisect Find by binary search the change that introduced a bug - grep Print files with lines matching a pattern in your codebase - -GitHub Commands: - pull-request Open a pull request on GitHub - fork Make a fork of a remote repository on GitHub and add as remote - create Create this repository on GitHub and add GitHub as origin - browse Open a GitHub page in the default browser - compare Open a compare page on GitHub - -See 'git help ' for more information on a specific command. -help - end - - def slurp_global_flags(args) - flags = %w[ --noop -c -p --paginate --no-pager --no-replace-objects --bare --version --help ] - flags2 = %w[ --exec-path= --git-dir= --work-tree= ] - - globals = [] - locals = [] - - while args[0] && (flags.include?(args[0]) || flags2.any? {|f| args[0].index(f) == 0 }) - flag = args.shift - case flag - when '--noop' - args.noop! - when '--version', '--help' - args.unshift flag.sub('--', '') - when '-c' - config_pair = args.shift - key, value = config_pair.split('=', 2) - git_reader.stub_config_value(key, value) - - globals << flag << config_pair - when '-p', '--paginate', '--no-pager' - locals << flag - else - globals << flag - end - end - - git_reader.add_exec_flags(globals) - args.add_exec_flags(globals) - args.add_exec_flags(locals) - end - - def browse_command(args) - url_only = args.delete('-u') - warn "Warning: the `-p` flag has no effect anymore" if args.delete('-p') - url = yield - - args.executable = url_only ? 'echo' : browser_launcher - args.push url - end - - def hub_manpage - abort "** Can't find groff(1)" unless command?('groff') - - require 'open3' - out = nil - Open3.popen3(groff_command) do |stdin, stdout, _| - stdin.puts hub_raw_manpage - stdin.close - out = stdout.read.strip - end - out - end - - def groff_command - "groff -Wall -mtty-char -mandoc -Tascii" - end - - def hub_raw_manpage - if File.exists? file = File.dirname(__FILE__) + '/../../man/hub.1' - File.read(file) - else - DATA.read - end - end - - def puts(*args) - page_stdout - super - end - - def page_stdout - return if not $stdout.tty? or windows? - - read, write = IO.pipe - - if Kernel.fork - $stdin.reopen(read) - read.close - write.close - - ENV['LESS'] = 'FSRX' - - Kernel.select [STDIN] - - pager = ENV['GIT_PAGER'] || - `git config --get-all core.pager`.split.first || ENV['PAGER'] || - 'less -isr' - - pager = 'cat' if pager.empty? - - exec pager rescue exec "/bin/sh", "-c", pager - else - $stdout.reopen(write) - $stderr.reopen(write) if $stderr.tty? - read.close - write.close - end - rescue NotImplementedError - end - - def pullrequest_editmsg(changes) - message_file = File.join(git_dir, 'PULLREQ_EDITMSG') - File.open(message_file, 'w') { |msg| - yield msg - if changes - msg.puts "#\n# Changes:\n#" - msg.puts changes.gsub(/^/, '# ').gsub(/ +$/, '') - end - } - edit_cmd = Array(git_editor).dup - edit_cmd << '-c' << 'set ft=gitcommit' if edit_cmd[0] =~ /^[mg]?vim$/ - edit_cmd << message_file - system(*edit_cmd) - abort "can't open text editor for pull request message" unless $?.success? - title, body = read_editmsg(message_file) - abort "Aborting due to empty pull request title" unless title - [title, body] - end - - def read_editmsg(file) - title, body = '', '' - File.open(file, 'r') { |msg| - msg.each_line do |line| - next if line.index('#') == 0 - ((body.empty? and line =~ /\S/) ? title : body) << line - end - } - title.tr!("\n", ' ') - title.strip! - body.strip! - - [title =~ /\S/ ? title : nil, body =~ /\S/ ? body : nil] - end - - def expand_alias(cmd) - if expanded = git_alias_for(cmd) - if expanded.index('!') != 0 - require 'shellwords' unless defined?(::Shellwords) - Shellwords.shellwords(expanded) - end - end - end - - def display_api_exception(action, response) - $stderr.puts "Error #{action}: #{response.message.strip} (HTTP #{response.status})" - if 422 == response.status and response.error_message? - msg = response.error_message - msg = msg.join("\n") if msg.respond_to? :join - warn msg - end - end - - end -end - -module Hub - class Runner - attr_reader :args - - def initialize(*args) - @args = Args.new(args) - Commands.run(@args) - end - - def self.execute(*args) - new(*args).execute - end - - def command - if args.skip? - '' - else - commands.join('; ') - end - end - - def commands - args.commands.map do |cmd| - if cmd.respond_to?(:join) - cmd.map { |arg| arg = arg.to_s; (arg.index(' ') || arg.empty?) ? "'#{arg}'" : arg }.join(' ') - else - cmd.to_s - end - end - end - - def execute - if args.noop? - puts commands - elsif not args.skip? - if args.chained? - execute_command_chain - else - exec(*args.to_exec) - end - end - end - - def execute_command_chain - commands = args.commands - commands.each_with_index do |cmd, i| - if cmd.respond_to?(:call) then cmd.call - elsif i == commands.length - 1 - exec(*cmd) - else - exit($?.exitstatus) unless system(*cmd) - end - end - end - end -end - -Hub::Runner.execute(*ARGV) - -__END__ -.\" generated with Ronn/v0.7.3 -.\" http://github.com/rtomayko/ronn/tree/0.7.3 -. -.TH "HUB" "1" "November 2012" "DEFUNKT" "Git Manual" -. -.SH "NAME" -\fBhub\fR \- git + hub = github -. -.SH "SYNOPSIS" -\fBhub\fR [\fB\-\-noop\fR] \fICOMMAND\fR \fIOPTIONS\fR -. -.br -\fBhub alias\fR [\fB\-s\fR] [\fISHELL\fR] -. -.SS "Expanded git commands:" -\fBgit init \-g\fR \fIOPTIONS\fR -. -.br -\fBgit clone\fR [\fB\-p\fR] \fIOPTIONS\fR [\fIUSER\fR/]\fIREPOSITORY\fR \fIDIRECTORY\fR -. -.br -\fBgit remote add\fR [\fB\-p\fR] \fIOPTIONS\fR \fIUSER\fR[/\fIREPOSITORY\fR] -. -.br -\fBgit remote set\-url\fR [\fB\-p\fR] \fIOPTIONS\fR \fIREMOTE\-NAME\fR \fIUSER\fR[/\fIREPOSITORY\fR] -. -.br -\fBgit fetch\fR \fIUSER\-1\fR,[\fIUSER\-2\fR,\.\.\.] -. -.br -\fBgit checkout\fR \fIPULLREQ\-URL\fR [\fIBRANCH\fR] -. -.br -\fBgit merge\fR \fIPULLREQ\-URL\fR -. -.br -\fBgit cherry\-pick\fR \fIGITHUB\-REF\fR -. -.br -\fBgit am\fR \fIGITHUB\-URL\fR -. -.br -\fBgit apply\fR \fIGITHUB\-URL\fR -. -.br -\fBgit push\fR \fIREMOTE\-1\fR,\fIREMOTE\-2\fR,\.\.\.,\fIREMOTE\-N\fR [\fIREF\fR] -. -.br -\fBgit submodule add\fR [\fB\-p\fR] \fIOPTIONS\fR [\fIUSER\fR/]\fIREPOSITORY\fR \fIDIRECTORY\fR -. -.SS "Custom git commands:" -\fBgit create\fR [\fINAME\fR] [\fB\-p\fR] [\fB\-d\fR \fIDESCRIPTION\fR] [\fB\-h\fR \fIHOMEPAGE\fR] -. -.br -\fBgit browse\fR [\fB\-u\fR] [[\fIUSER\fR\fB/\fR]\fIREPOSITORY\fR] [SUBPAGE] -. -.br -\fBgit compare\fR [\fB\-u\fR] [\fIUSER\fR] [\fISTART\fR\.\.\.]\fIEND\fR -. -.br -\fBgit fork\fR [\fB\-\-no\-remote\fR] -. -.br -\fBgit pull\-request\fR [\fB\-f\fR] [\fITITLE\fR|\fB\-i\fR \fIISSUE\fR] [\fB\-b\fR \fIBASE\fR] [\fB\-h\fR \fIHEAD\fR] -. -.SH "DESCRIPTION" -hub enhances various git commands to ease most common workflows with GitHub\. -. -.TP -\fBhub \-\-noop\fR \fICOMMAND\fR -Shows which command(s) would be run as a result of the current command\. Doesn\'t perform anything\. -. -.TP -\fBhub alias\fR [\fB\-s\fR] [\fISHELL\fR] -Shows shell instructions for wrapping git\. If given, \fISHELL\fR specifies the type of shell; otherwise defaults to the value of SHELL environment variable\. With \fB\-s\fR, outputs shell script suitable for \fBeval\fR\. -. -.TP -\fBgit init\fR \fB\-g\fR \fIOPTIONS\fR -Create a git repository as with git\-init(1) and add remote \fBorigin\fR at "git@github\.com:\fIUSER\fR/\fIREPOSITORY\fR\.git"; \fIUSER\fR is your GitHub username and \fIREPOSITORY\fR is the current working directory\'s basename\. -. -.TP -\fBgit clone\fR [\fB\-p\fR] \fIOPTIONS\fR [\fIUSER\fR\fB/\fR]\fIREPOSITORY\fR \fIDIRECTORY\fR -Clone repository "git://github\.com/\fIUSER\fR/\fIREPOSITORY\fR\.git" into \fIDIRECTORY\fR as with git\-clone(1)\. When \fIUSER\fR/ is omitted, assumes your GitHub login\. With \fB\-p\fR, clone private repositories over SSH\. For repositories under your GitHub login, \fB\-p\fR is implicit\. -. -.TP -\fBgit remote add\fR [\fB\-p\fR] \fIOPTIONS\fR \fIUSER\fR[\fB/\fR\fIREPOSITORY\fR] -Add remote "git://github\.com/\fIUSER\fR/\fIREPOSITORY\fR\.git" as with git\-remote(1)\. When /\fIREPOSITORY\fR is omitted, the basename of the current working directory is used\. With \fB\-p\fR, use private remote "git@github\.com:\fIUSER\fR/\fIREPOSITORY\fR\.git"\. If \fIUSER\fR is "origin" then uses your GitHub login\. -. -.TP -\fBgit remote set\-url\fR [\fB\-p\fR] \fIOPTIONS\fR \fIREMOTE\-NAME\fR \fIUSER\fR[/\fIREPOSITORY\fR] -Sets the url of remote \fIREMOTE\-NAME\fR using the same rules as \fBgit remote add\fR\. -. -.TP -\fBgit fetch\fR \fIUSER\-1\fR,[\fIUSER\-2\fR,\.\.\.] -Adds missing remote(s) with \fBgit remote add\fR prior to fetching\. New remotes are only added if they correspond to valid forks on GitHub\. -. -.TP -\fBgit checkout\fR \fIPULLREQ\-URL\fR [\fIBRANCH\fR] -Checks out the head of the pull request as a local branch, to allow for reviewing, rebasing and otherwise cleaning up the commits in the pull request before merging\. The name of the local branch can explicitly be set with \fIBRANCH\fR\. -. -.TP -\fBgit merge\fR \fIPULLREQ\-URL\fR -Merge the pull request with a commit message that includes the pull request ID and title, similar to the GitHub Merge Button\. -. -.TP -\fBgit cherry\-pick\fR \fIGITHUB\-REF\fR -Cherry\-pick a commit from a fork using either full URL to the commit or GitHub\-flavored Markdown notation, which is \fBuser@sha\fR\. If the remote doesn\'t yet exist, it will be added\. A \fBgit fetch \fR is issued prior to the cherry\-pick attempt\. -. -.TP -\fBgit [am|apply]\fR \fIGITHUB\-URL\fR -Downloads the patch file for the pull request or commit at the URL and applies that patch from disk with \fBgit am\fR or \fBgit apply\fR\. Similar to \fBcherry\-pick\fR, but doesn\'t add new remotes\. \fBgit am\fR creates commits while preserving authorship info while \fBapply\fR only applies the patch to the working copy\. -. -.TP -\fBgit push\fR \fIREMOTE\-1\fR,\fIREMOTE\-2\fR,\.\.\.,\fIREMOTE\-N\fR [\fIREF\fR] -Push \fIREF\fR to each of \fIREMOTE\-1\fR through \fIREMOTE\-N\fR by executing multiple \fBgit push\fR commands\. -. -.TP -\fBgit submodule add\fR [\fB\-p\fR] \fIOPTIONS\fR [\fIUSER\fR/]\fIREPOSITORY\fR \fIDIRECTORY\fR -Submodule repository "git://github\.com/\fIUSER\fR/\fIREPOSITORY\fR\.git" into \fIDIRECTORY\fR as with git\-submodule(1)\. When \fIUSER\fR/ is omitted, assumes your GitHub login\. With \fB\-p\fR, use private remote "git@github\.com:\fIUSER\fR/\fIREPOSITORY\fR\.git"\. -. -.TP -\fBgit help\fR -Display enhanced git\-help(1)\. -. -.P -hub also adds some custom commands that are otherwise not present in git: -. -.TP -\fBgit create\fR [\fINAME\fR] [\fB\-p\fR] [\fB\-d\fR \fIDESCRIPTION\fR] [\fB\-h\fR \fIHOMEPAGE\fR] -Create a new public GitHub repository from the current git repository and add remote \fBorigin\fR at "git@github\.com:\fIUSER\fR/\fIREPOSITORY\fR\.git"; \fIUSER\fR is your GitHub username and \fIREPOSITORY\fR is the current working directory name\. To explicitly name the new repository, pass in \fINAME\fR, optionally in \fIORGANIZATION\fR/\fINAME\fR form to create under an organization you\'re a member of\. With \fB\-p\fR, create a private repository, and with \fB\-d\fR and \fB\-h\fR set the repository\'s description and homepage URL, respectively\. -. -.TP -\fBgit browse\fR [\fB\-u\fR] [[\fIUSER\fR\fB/\fR]\fIREPOSITORY\fR] [SUBPAGE] -Open repository\'s GitHub page in the system\'s default web browser using \fBopen(1)\fR or the \fBBROWSER\fR env variable\. If the repository isn\'t specified, \fBbrowse\fR opens the page of the repository found in the current directory\. If SUBPAGE is specified, the browser will open on the specified subpage: one of "wiki", "commits", "issues" or other (the default is "tree")\. -. -.TP -\fBgit compare\fR [\fB\-u\fR] [\fIUSER\fR] [\fISTART\fR\.\.\.]\fIEND\fR -Open a GitHub compare view page in the system\'s default web browser\. \fISTART\fR to \fIEND\fR are branch names, tag names, or commit SHA1s specifying the range of history to compare\. If a range with two dots (\fBa\.\.b\fR) is given, it will be transformed into one with three dots\. If \fISTART\fR is omitted, GitHub will compare against the base branch (the default is "master")\. -. -.TP -\fBgit fork\fR [\fB\-\-no\-remote\fR] -Forks the original project (referenced by "origin" remote) on GitHub and adds a new remote for it under your username\. -. -.TP -\fBgit pull\-request\fR [\fB\-f\fR] [\fITITLE\fR|\fB\-i\fR \fIISSUE\fR|\fIISSUE\-URL\fR] [\fB\-b\fR \fIBASE\fR] [\fB\-h\fR \fIHEAD\fR] -Opens a pull request on GitHub for the project that the "origin" remote points to\. The default head of the pull request is the current branch\. Both base and head of the pull request can be explicitly given in one of the following formats: "branch", "owner:branch", "owner/repo:branch"\. This command will abort operation if it detects that the current topic branch has local commits that are not yet pushed to its upstream branch on the remote\. To skip this check, use \fB\-f\fR\. -. -.IP -If \fITITLE\fR is omitted, a text editor will open in which title and body of the pull request can be entered in the same manner as git commit message\. -. -.IP -If instead of normal \fITITLE\fR an issue number is given with \fB\-i\fR, the pull request will be attached to an existing GitHub issue\. Alternatively, instead of title you can paste a full URL to an issue on GitHub\. -. -.SH "CONFIGURATION" -Hub will prompt for GitHub username & password the first time it needs to access the API and exchange it for an OAuth token, which it saves in "~/\.config/hub"\. -. -.P -To avoid being prompted, use \fIGITHUB_USER\fR and \fIGITHUB_PASSWORD\fR environment variables\. -. -.P -If you prefer the HTTPS protocol for GitHub repositories, you can set "hub\.protocol" to "https"\. This will affect \fBclone\fR, \fBfork\fR, \fBremote add\fR and other operations that expand references to GitHub repositories as full URLs that otherwise use git and ssh protocols\. -. -.IP "" 4 -. -.nf - -$ git config \-\-global hub\.protocol https -. -.fi -. -.IP "" 0 -. -.SS "GitHub Enterprise" -By default, hub will only work with repositories that have remotes which point to github\.com\. GitHub Enterprise hosts need to be whitelisted to configure hub to treat such remotes same as github\.com: -. -.IP "" 4 -. -.nf - -$ git config \-\-global \-\-add hub\.host my\.git\.org -. -.fi -. -.IP "" 0 -. -.P -The default host for commands like \fBinit\fR and \fBclone\fR is still github\.com, but this can be affected with the \fIGITHUB_HOST\fR environment variable: -. -.IP "" 4 -. -.nf - -$ GITHUB_HOST=my\.git\.org git clone myproject -. -.fi -. -.IP "" 0 -. -.SH "EXAMPLES" -. -.SS "git clone" -. -.nf - -$ git clone schacon/ticgit -> git clone git://github\.com/schacon/ticgit\.git - -$ git clone \-p schacon/ticgit -> git clone git@github\.com:schacon/ticgit\.git - -$ git clone resque -> git clone git@github\.com/YOUR_USER/resque\.git -. -.fi -. -.SS "git remote add" -. -.nf - -$ git remote add rtomayko -> git remote add rtomayko git://github\.com/rtomayko/CURRENT_REPO\.git - -$ git remote add \-p rtomayko -> git remote add rtomayko git@github\.com:rtomayko/CURRENT_REPO\.git - -$ git remote add origin -> git remote add origin git://github\.com/YOUR_USER/CURRENT_REPO\.git -. -.fi -. -.SS "git fetch" -. -.nf - -$ git fetch mislav -> git remote add mislav git://github\.com/mislav/REPO\.git -> git fetch mislav - -$ git fetch mislav,xoebus -> git remote add mislav \.\.\. -> git remote add xoebus \.\.\. -> git fetch \-\-multiple mislav xoebus -. -.fi -. -.SS "git cherry\-pick" -. -.nf - -$ git cherry\-pick http://github\.com/mislav/REPO/commit/SHA -> git remote add \-f mislav git://github\.com/mislav/REPO\.git -> git cherry\-pick SHA - -$ git cherry\-pick mislav@SHA -> git remote add \-f mislav git://github\.com/mislav/CURRENT_REPO\.git -> git cherry\-pick SHA - -$ git cherry\-pick mislav@SHA -> git fetch mislav -> git cherry\-pick SHA -. -.fi -. -.SS "git am, git apply" -. -.nf - -$ git am https://github\.com/defunkt/hub/pull/55 -> curl https://github\.com/defunkt/hub/pull/55\.patch \-o /tmp/55\.patch -> git am /tmp/55\.patch - -$ git am \-\-ignore\-whitespace https://github\.com/davidbalbert/hub/commit/fdb9921 -> curl https://github\.com/davidbalbert/hub/commit/fdb9921\.patch \-o /tmp/fdb9921\.patch -> git am \-\-ignore\-whitespace /tmp/fdb9921\.patch - -$ git apply https://gist\.github\.com/8da7fb575debd88c54cf -> curl https://gist\.github\.com/8da7fb575debd88c54cf\.txt \-o /tmp/gist\-8da7fb575debd88c54cf\.txt -> git apply /tmp/gist\-8da7fb575debd88c54cf\.txt -. -.fi -. -.SS "git fork" -. -.nf - -$ git fork -[ repo forked on GitHub ] -> git remote add \-f YOUR_USER git@github\.com:YOUR_USER/CURRENT_REPO\.git -. -.fi -. -.SS "git pull\-request" -. -.nf - -# while on a topic branch called "feature": -$ git pull\-request -[ opens text editor to edit title & body for the request ] -[ opened pull request on GitHub for "YOUR_USER:feature" ] - -# explicit title, pull base & head: -$ git pull\-request "I\'ve implemented feature X" \-b defunkt:master \-h mislav:feature - -$ git pull\-request \-i 123 -[ attached pull request to issue #123 ] -. -.fi -. -.SS "git checkout" -. -.nf - -$ git checkout https://github\.com/defunkt/hub/pull/73 -> git remote add \-f \-t feature git://github:com/mislav/hub\.git -> git checkout \-\-track \-B mislav\-feature mislav/feature - -$ git checkout https://github\.com/defunkt/hub/pull/73 custom\-branch\-name -. -.fi -. -.SS "git merge" -. -.nf - -$ git merge https://github\.com/defunkt/hub/pull/73 -> git fetch git://github\.com/mislav/hub\.git +refs/heads/feature:refs/remotes/mislav/feature -> git merge mislav/feature \-\-no\-ff \-m \'Merge pull request #73 from mislav/feature\.\.\.\' -. -.fi -. -.SS "git create" -. -.nf - -$ git create -[ repo created on GitHub ] -> git remote add origin git@github\.com:YOUR_USER/CURRENT_REPO\.git - -# with description: -$ git create \-d \'It shall be mine, all mine!\' - -$ git create recipes -[ repo created on GitHub ] -> git remote add origin git@github\.com:YOUR_USER/recipes\.git - -$ git create sinatra/recipes -[ repo created in GitHub organization ] -> git remote add origin git@github\.com:sinatra/recipes\.git -. -.fi -. -.SS "git init" -. -.nf - -$ git init \-g -> git init -> git remote add origin git@github\.com:YOUR_USER/REPO\.git -. -.fi -. -.SS "git push" -. -.nf - -$ git push origin,staging,qa bert_timeout -> git push origin bert_timeout -> git push staging bert_timeout -> git push qa bert_timeout -. -.fi -. -.SS "git browse" -. -.nf - -$ git browse -> open https://github\.com/YOUR_USER/CURRENT_REPO - -$ git browse \-\- commit/SHA -> open https://github\.com/YOUR_USER/CURRENT_REPO/commit/SHA - -$ git browse \-\- issues -> open https://github\.com/YOUR_USER/CURRENT_REPO/issues - -$ git browse schacon/ticgit -> open https://github\.com/schacon/ticgit - -$ git browse schacon/ticgit commit/SHA -> open https://github\.com/schacon/ticgit/commit/SHA - -$ git browse resque -> open https://github\.com/YOUR_USER/resque - -$ git browse resque network -> open https://github\.com/YOUR_USER/resque/network -. -.fi -. -.SS "git compare" -. -.nf - -$ git compare refactor -> open https://github\.com/CURRENT_REPO/compare/refactor - -$ git compare 1\.0\.\.1\.1 -> open https://github\.com/CURRENT_REPO/compare/1\.0\.\.\.1\.1 - -$ git compare \-u fix -> (https://github\.com/CURRENT_REPO/compare/fix) - -$ git compare other\-user patch -> open https://github\.com/other\-user/REPO/compare/patch -. -.fi -. -.SS "git submodule" -. -.nf - -$ hub submodule add wycats/bundler vendor/bundler -> git submodule add git://github\.com/wycats/bundler\.git vendor/bundler - -$ hub submodule add \-p wycats/bundler vendor/bundler -> git submodule add git@github\.com:wycats/bundler\.git vendor/bundler - -$ hub submodule add \-b ryppl ryppl/pip vendor/pip -> git submodule add \-b ryppl git://github\.com/ryppl/pip\.git vendor/pip -. -.fi -. -.SS "git help" -. -.nf - -$ git help -> (improved git help) -$ git help hub -> (hub man page) -. -.fi -. -.SH "BUGS" -\fIhttps://github\.com/defunkt/hub/issues\fR -. -.SH "AUTHORS" -\fIhttps://github\.com/defunkt/hub/contributors\fR -. -.SH "SEE ALSO" -git(1), git\-clone(1), git\-remote(1), git\-init(1), \fIhttp://github\.com\fR, \fIhttps://github\.com/defunkt/hub\fR diff --git a/bin/latest-ack b/bin/latest-ack deleted file mode 100755 index 2b92af4..0000000 --- a/bin/latest-ack +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -e -curl -sLo ~/bin/ack http://betterthangrep.com/ack-standalone -chmod 755 ~/bin/ack -~/bin/ack --version diff --git a/bin/latest-hub b/bin/latest-hub deleted file mode 100755 index 8f89fbe..0000000 --- a/bin/latest-hub +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh -# Usage: latest-hub -# Grabs the latest standalone version of Chris Wanstrath's hub -# and puts its in your HOME/bin. -set -e -curl -sLo ~/bin/hub http://defunkt.github.com/hub/standalone -chmod 755 ~/bin/hub -~/bin/hub --version -- 2.45.2