merge upstream/master

This commit is contained in:
2022-02-10 08:59:46 +01:00
30 changed files with 1042 additions and 273 deletions

View File

@@ -17,7 +17,7 @@ unalias git > /dev/null 2>&1
unset -f git > /dev/null 2>&1
# Use the full path to git to avoid infinite loop with git function
export _git_cmd="$(\which git)"
export _git_cmd="$(bin_path git)"
# Wrap git with the 'hub' github wrapper, if installed (https://github.com/defunkt/hub)
if type hub > /dev/null 2>&1; then export _git_cmd="hub"; fi
@@ -28,9 +28,9 @@ if type hub > /dev/null 2>&1; then export _git_cmd="hub"; fi
function git(){
# Only expand args for git commands that deal with paths or branches
case $1 in
commit|blame|add|log|rebase|merge|difftool)
commit|blame|add|log|rebase|merge|difftool|switch)
exec_scmb_expand_args "$_git_cmd" "$@";;
checkout|diff|rm|reset)
checkout|diff|rm|reset|restore)
exec_scmb_expand_args --relative "$_git_cmd" "$@";;
branch)
_scmb_git_branch_shortcuts "${@:2}";;
@@ -57,7 +57,7 @@ let COMP_CWORD+=1
local cur words cword prev
_get_comp_words_by_ref -n =: cur words cword prev
_git
__git_wrap__git_main
}
"
}
@@ -71,7 +71,7 @@ __git_alias () {
alias_str="$1"; cmd_prefix="$2"; cmd="$3";
if [ $# -gt 2 ]; then
shift 3 2>/dev/null
cmd_args=$@
cmd_args=("$@")
fi
alias $alias_str="$cmd_prefix $cmd${cmd_args:+ }${cmd_args[*]}"
@@ -89,6 +89,7 @@ _alias "$git_add_shortcuts_alias" 'git_add_shortcuts'
_alias "$exec_scmb_expand_args_alias" 'exec_scmb_expand_args'
_alias "$git_show_files_alias" 'git_show_affected_files'
_alias "$git_commit_all_alias" 'git_commit_all'
_alias "$git_grep_shortcuts_alias" 'git_grep_shortcuts'
# Git Index alias
_alias "$git_index_alias" 'git_index'
@@ -100,21 +101,23 @@ if [ "$git_setup_aliases" = "yes" ]; then
__git_alias "$git_checkout_alias" 'git' 'checkout'
__git_alias "$git_commit_alias" 'git' 'commit'
__git_alias "$git_commit_verbose_alias" 'git' 'commit' '--verbose'
__git_alias "$git_reset_alias" 'git' 'reset' '--'
__git_alias "$git_reset_alias" 'git' 'reset'
__git_alias "$git_reset_hard_alias" 'git' 'reset' '--hard'
__git_alias "$git_rm_alias" 'git' 'rm'
__git_alias "$git_blame_alias" 'git' 'blame'
__git_alias "$git_diff_no_whitespace_alias" 'git' 'diff' '-w' '--'
__git_alias "$git_diff_no_whitespace_alias" 'git' 'diff' '-w'
__git_alias "$git_diff_alias" 'git' 'diff'
__git_alias "$git_diff_file_alias" 'git' 'diff' '--'
__git_alias "$git_diff_file_alias" 'git' 'diff'
__git_alias "$git_diff_word_alias" 'git' 'diff' '--word-diff'
__git_alias "$git_diff_cached_alias" 'git' 'diff' '--cached --'
__git_alias "$git_diff_cached_alias" 'git' 'diff' '--cached'
__git_alias "$git_add_patch_alias" 'git' 'add' '-p'
__git_alias "$git_add_updated_alias" 'git' 'add' '-u'
__git_alias "$git_difftool_alias" 'git' 'difftool'
__git_alias "$git_difftool_meld_alias" 'git' 'difftool -y -t meld'
__git_alias "$git_difftool_vimdiff_alias" 'git' 'difftool -y -t vimdiff'
__git_alias "$git_difftool_gvimdiff_alias" 'git' 'difftool -y -t gvimdiff'
__git_alias "$git_mergetool_alias" 'git' 'mergetool'
__git_alias "$git_restore_alias" 'git' 'restore'
# Custom default format for git log
git_log_command="log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
@@ -157,6 +160,7 @@ if [ "$git_setup_aliases" = "yes" ]; then
__git_alias "$git_submodule_update_rec_alias" 'git' 'submodule' 'update' '--init' '--recursive'
__git_alias "$git_whatchanged_alias" 'git' 'whatchanged'
__git_alias "$git_apply_alias" 'git' 'apply'
__git_alias "$git_switch_alias" 'git' 'switch'
# Compound/complex commands
_alias "$git_fetch_all_alias" 'git fetch --all'
@@ -184,7 +188,7 @@ if [ $shell = "bash" ]; then
[[ -s "/usr/share/git/completion/git-completion.bash" ]] && source "/usr/share/git/completion/git-completion.bash"
# new path in Ubuntu 13.04
[[ -s "/usr/share/bash-completion/completions/git" ]] && source "/usr/share/bash-completion/completions/git"
complete -o default -o nospace -F _git $git_alias
complete -o default -o nospace -F __git_wrap__git_main $git_alias
# Git repo management & aliases.
# If you know how to rewrite _git_index_tab_completion() for zsh, please send me a pull request!

View File

@@ -20,9 +20,9 @@ function _scmb_git_branch_shortcuts {
return 1
fi
# Use ruby to inject numbers into ls output
# Use ruby to inject numbers into git branch output
ruby -e "$( cat <<EOF
output = %x($_git_cmd branch --color=always $@)
output = %x($_git_cmd branch --color=always $(token_quote "$@"))
line_count = output.lines.to_a.size
output.lines.each_with_index do |line, i|
spaces = (line_count > 9 && i < 9 ? " " : " ")
@@ -32,14 +32,12 @@ EOF
)"
# Set numbered file shortcut in variable
local e=1
IFS=$'\n'
local e=1 IFS=$'\n'
for branch in $($_git_cmd branch "$@" | sed "s/^[* ]\{2\}//"); do
export $git_env_char$e="$branch"
if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi
let e++
done
unset IFS
}
__git_alias "$git_branch_alias" "_scmb_git_branch_shortcuts" ""

View File

@@ -16,7 +16,7 @@
# --------------------------------------------------------------------
git_status_shortcuts() {
zsh_compat # Ensure shwordsplit is on for zsh
IFS=$'\n'
local IFS=$'\n'
local git_status="$(git status --porcelain 2> /dev/null)"
local i
@@ -95,7 +95,7 @@ git_status_shortcuts() {
fi
done
IFS=" "
local IFS=" "
grp_num=1
for heading in 'Changes to be committed' 'Unmerged paths' 'Changes not staged for commit' 'Untracked files'; do
# If no group specified as param, or specified group is current group
@@ -114,11 +114,12 @@ git_status_shortcuts() {
# so just use plain 'git status'
git status
fi
unset IFS
zsh_reset # Reset zsh environment to default
}
# Template function for 'git_status_shortcuts'.
_gs_output_file_group() {
local relative
for i in ${stat_grp[$1]}; do
# Print colored hashes & files based on modification groups
local c_group="\033[0;$(eval echo -e \$c_grp_$1)"
@@ -127,9 +128,10 @@ _gs_output_file_group() {
if [ -z "$project_root" ]; then
relative="${stat_file[$i]}"
else
dest=$(readlink -f "$project_root/${stat_file[$i]}")
local absolute="$project_root/${stat_file[$i]}"
local dest=$(readlink -f "$absolute")
local pwd=$(readlink -f "$PWD")
relative="$(_gs_relative_path "$pwd" "$dest" )"
relative="$(_gs_relative_path "$pwd" "${dest:-$absolute}" )"
fi
if [[ $f -gt 10 && $e -lt 10 ]]; then local pad=" "; else local pad=""; fi # (padding)
@@ -150,7 +152,7 @@ _gs_relative_path(){
# Credit to 'pini' for the following script.
# (http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory)
target=$2; common_part=$1; back=""
while [[ "${target#$common_part}" == "${target}" ]]; do
while [[ -n "${common_part}" && "${target#$common_part}" == "${target}" ]]; do
common_part="${common_part%/*}"
back="../${back}"
done

47
lib/git/grep_shortcuts.rb Normal file
View File

@@ -0,0 +1,47 @@
#!/usr/bin/env ruby
# encoding: UTF-8
PROJECT_ROOT = File.exist?(".git") ? Dir.pwd : `\git rev-parse --show-toplevel 2> /dev/null`.strip
COLORS = {
:rst => "\033[0m",
:del => "\033[0;31m",
:mod => "\033[0;32m",
:new => "\033[0;33m",
:ren => "\033[0;34m",
:cpy => "\033[0;33m",
:typ => "\033[0;35m",
:unt => "\033[0;36m",
:dark => "\033[2;37m",
:branch => "\033[1m",
:header => "\033[0m"
}
COLOR_MATCH = /\e\[[0-9;]*[mK]/
output_files = []
stdin = STDIN.set_encoding(Encoding::ASCII_8BIT)
while stdin.gets
if $. > 1000
puts "Only showing first 1000 results. Please refine your search."
break
end
print "#{COLORS[:dark]}[#{COLORS[:rst]}#{$.}#{COLORS[:dark]}]#{COLORS[:rst]} "
matches = $_.match(/(^.+?)#{COLOR_MATCH}?:#{COLOR_MATCH}?(\d+)?/)
file = matches[1]
line = matches[2]
output_files << "#{file}#{line ? ":#{line}" : ""}"
puts $_
end
print "@@filelist@@::"
output_files.each_with_index {|f,i|
# If file starts with a '~', treat it as a relative path.
# This is important when dealing with symlinks
print "|" unless i == 0
print f.start_with?("~") ? f.sub(/~/, '') : File.join(PROJECT_ROOT, f)
}
puts

24
lib/git/grep_shortcuts.sh Normal file
View File

@@ -0,0 +1,24 @@
git_grep_shortcuts() {
fail_if_not_git_repo || return 1
git_clear_vars
# Run ruby script, store output
tmp_grep_results="$(git rev-parse --git-dir)/tmp_grep_results_$$"
git grep -n --color=always "$@" |
/usr/bin/env ruby "$scmbDir/lib/git/grep_shortcuts.rb" >"$tmp_grep_results"
# Fetch list of files from last line of script output
files="$(tail -1 "$tmp_grep_results" | sed 's%@@filelist@@::%%g')"
# Export numbered env variables for each file
IFS="|"
local e=1
for file in ${=files}; do
export $git_env_char$e="$file"
let e++
done
IFS=$' \t\n'
# Print status
cat "$tmp_grep_results" | sed '$d' | less -SfRMXFi
rm -f "$tmp_grep_results"
}

View File

@@ -13,4 +13,11 @@ function fail_if_not_git_repo() {
return 1
fi
return 0
}
}
bin_path() {
if [[ -n ${ZSH_VERSION:-} ]];
then builtin whence -cp "$1" 2> /dev/null
else builtin type -P "$1"
fi
}

View File

@@ -24,16 +24,24 @@ _bind(){
if [[ "$git_keyboard_shortcuts_enabled" = "true" ]]; then
case "$-" in
*i*)
if [ -n "$ZSH_VERSION" ]; then
RETURN_CHAR="^M"
else
RETURN_CHAR="\n"
fi
# Uses emacs style keybindings, so vi mode is not supported for now
if ! set -o | grep -q '^vi .*on$'; then
if [[ $shell == "zsh" ]]; then
_bind "$git_commit_all_keys" " git_commit_all""\n"
_bind "$git_add_and_commit_keys" " \033[1~ git_add_and_commit ""\n"
_bind "$git_commit_all_with_ci_skip_keys" " \033[1~ APPEND='[ci skip]' git_commit_all ""\n"
_bind "$git_commit_all_keys" " git_commit_all""$RETURN_CHAR"
_bind "$git_add_and_commit_keys" " \033[1~ git_add_and_commit ""$RETURN_CHAR"
_bind "$git_commit_all_with_ci_skip_keys" " \033[1~ GIT_COMMIT_MSG_SUFFIX='[ci skip]' git_commit_all ""$RETURN_CHAR"
_bind "$git_add_and_amend_commit_keys" " git add --all . && git commit --amend -C HEAD""$RETURN_CHAR"
else
_bind "$git_commit_all_keys" "\" git_commit_all\n\""
_bind "$git_add_and_commit_keys" "\"\C-A git_add_and_commit \n\""
_bind "$git_commit_all_with_ci_skip_keys" "\"\C-A APPEND='[ci skip]' git_commit_all \n\""
_bind "$git_commit_all_keys" "\" git_commit_all$RETURN_CHAR\""
_bind "$git_add_and_commit_keys" "\"\C-A git_add_and_commit $RETURN_CHAR\""
_bind "$git_commit_all_with_ci_skip_keys" "\"\C-A GIT_COMMIT_MSG_SUFFIX='[ci skip]' git_commit_all $RETURN_CHAR\""
_bind "$git_add_and_amend_commit_keys" "\" git add --all . && git commit --amend -C HEAD$RETURN_CHAR\""
fi
fi

View File

@@ -51,7 +51,7 @@
function git_index() {
IFS=$'\n'
local IFS=$'\n'
if [ -z "$1" ]; then
# Just change to $GIT_REPO_DIR if no params given.
"cd" $GIT_REPO_DIR
@@ -68,8 +68,8 @@ function git_index() {
elif [ "$1" = "--list" ] || [ "$1" = "-l" ]; then
echo -e "$_bld_col$(_git_index_count)$_txt_col Git repositories in $_bld_col$GIT_REPO_DIR$_txt_col:\n"
for repo in $(_git_index_dirs_without_home); do
echo $(basename $repo) : $repo
done | sort | column -t -s ':'
echo $(basename $repo | sed "s/ /_/g") : $repo
done | sort -t ":" -k1,1 | column -t -s ':'
elif [ "$1" = "--count-by-host" ]; then
echo -e "=== Producing a report of the number of repos per host...\n"
_git_index_batch_cmd git remote -v | \grep "origin.*(fetch)" |
@@ -103,7 +103,7 @@ function git_index() {
# --------------------
# Go to our base path
if [ -n "$base_path" ]; then
IFS=$' \t\n'
local IFS=$' \t\n'
# evaluate ~ if necessary
if [[ "$base_path" == "~"* ]]; then
base_path=$(eval echo ${base_path%%/*})/${base_path#*/}
@@ -116,7 +116,6 @@ function git_index() {
fi
fi
fi
unset IFS
}
_git_index_dirs_without_home() {
@@ -126,12 +125,11 @@ _git_index_dirs_without_home() {
# Recursively searches for git repos in $GIT_REPO_DIR
function _find_git_repos() {
# Find all unarchived projects
IFS=$'\n'
for repo in $(find -L "$GIT_REPO_DIR" -maxdepth 5 -name ".git" -type d \! -wholename '*/archive/*'); do
local IFS=$'\n'
for repo in $(find -L "$GIT_REPO_DIR" -maxdepth 3 -name ".git" -type d \! -wholename '*/archive/*'); do
echo ${repo%/.git} # Return project folder, with trailing ':'
_find_git_submodules $repo # Detect any submodules
done
unset IFS
}
# List all submodules for a git repo, if any.
@@ -146,11 +144,10 @@ function _find_git_submodules() {
function _rebuild_git_index() {
if [ "$1" != "--silent" ]; then echo -e "== Scanning $GIT_REPO_DIR for git repos & submodules..."; fi
# Get repos from src dir and custom dirs, then sort by basename
IFS=$'\n'
local IFS=$'\n'
for repo in $(echo -e "$(_find_git_repos)\n$(echo $GIT_REPOS | sed "s/:/\\\\n/g")"); do
echo $(basename $repo | sed "s/ /_/g") $repo
done | sort | cut -d " " -f2- >| "$GIT_REPO_DIR/.git_index"
unset IFS
echo $(basename $repo | sed "s/ /_/g"):$repo
done | sort -t ":" -k1,1 | cut -d ":" -f2- >| "$GIT_REPO_DIR/.git_index"
if [ "$1" != "--silent" ]; then
echo -e "===== Indexed $_bld_col$(_git_index_count)$_txt_col repos in $GIT_REPO_DIR/.git_index"
@@ -205,39 +202,39 @@ _git_index_update_all_branches() {
return
fi
local remotes merges branches
# zsh 5.0.2 requires local separate to assignment for arrays
local remote merge remotes merges branches
# Get branch configuration from .git/config
IFS=$'\n'
local IFS=$'\n'
for branch in $($GIT_BINARY branch 2> /dev/null | sed -e 's/.\{2\}\(.*\)/\1/'); do
# Skip '(no branch)'
if [[ "$branch" = "(no branch)" ]]; then continue; fi
local remote=$(git config --get branch.$branch.remote)
local merge=$(git config --get branch.$branch.merge)
remote=$(git config --get "branch.$branch.remote")
merge=$(git config --get "branch.$branch.merge")
# Ignore branch if remote and merge is not configured
if [[ -n "$remote" ]] && [[ -n "$merge" ]]; then
branches=(${branches[@]} "$branch")
remotes=(${remotes[@]} "$remote")
branches=("${branches[@]}" "$branch")
remotes=("${remotes[@]}" "$remote")
# Get branch from merge ref (refs/heads/master => master)
merges=(${merges[@]} "$(basename $merge)")
merges=("${merges[@]}" "$(basename "$merge")")
else
echo "=== Skipping $branch: remote and merge refs are not configured."
fi
done
unset IFS
# Update all remotes if there are any branches to update
if [ -n "${branches[*]}" ]; then git fetch --all 2> /dev/null; fi
local index=0
# Iterate over branches, and update those that can be fast-forwarded
for branch in ${branches[@]}; do
for branch in "${branches[@]}"; do
branch_rev="$(git rev-parse $branch)"
# Local branch can be fast-forwarded if revision is ancestor of remote revision, and not the same.
# (see http://stackoverflow.com/a/2934062/304706)
if [[ "$branch_rev" != "$(git rev-parse ${remotes[$index]}/${merges[$index]})" ]] && \
[[ "$(git merge-base $branch_rev ${remotes[$index]}/${merges[$index]})" = "$branch_rev" ]]; then
if [[ "$branch_rev" != "$(git rev-parse "${remotes[$index]}/${merges[$index]}")" ]] && \
[[ "$(git merge-base "$branch_rev" "${remotes[$index]}/${merges[$index]}")" = "$branch_rev" ]]; then
echo "=== Updating $branch branch in $base_path from ${remotes[$index]}/${merges[$index]}..."
# Checkout branch if we aren't already on it.
if [[ "$branch" != "$(parse_git_branch)" ]]; then git checkout $branch; fi
@@ -268,11 +265,11 @@ function _git_index_batch_cmd() {
cwd="$PWD"
if [ -n "$1" ]; then
echo -e "== Running command for $_bld_col$(_git_index_count)$_txt_col repos...\n"
unset IFS
local IFS=$'\n'
local base_path
for base_path in $(sed -e "s/--.*//" "$GIT_REPO_DIR/.git_index" | \grep . | sort); do
builtin cd "$base_path"
$@
"$@"
done
else
echo "Please give a command to run for all repos. (It may be useful to write your command as a function or script.)"
@@ -285,8 +282,7 @@ if [ $shell = 'bash' ]; then
# Bash tab completion function for git_index()
function _git_index_tab_completion() {
_check_git_index
local curw
IFS=$'\n'
local curw IFS=$'\n'
COMPREPLY=()
curw=${COMP_WORDS[COMP_CWORD]}
@@ -313,10 +309,9 @@ if [ $shell = 'bash' ]; then
else
COMPREPLY=($(compgen -W '$(sed -e "s:.*/::" -e "s:$:/:" "$GIT_REPO_DIR/.git_index" | sort)' -- $curw))
fi
unset IFS
return 0
}
else
else # Zsh tab completion function for git_index()
function _git_index_tab_completion() {
typeset -A opt_args
local state state_descr context line

View File

@@ -5,9 +5,9 @@
# ------------------------------------------------------------------------------
if test | sed -E 's///g' 2>/dev/null; then
if sed -E 's///g' </dev/null &>/dev/null; then
SED_REGEX_ARG="E"
elif test | sed -r 's///g' 2>/dev/null; then
elif sed -r 's///g' </dev/null &>/dev/null; then
SED_REGEX_ARG="r"
else
echo "Cannot determine extended regex argument for sed! (Doesn't respond to either -E or -r)"
@@ -23,19 +23,19 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
# Define 'whence' for bash, to get the value of an alias
type whence > /dev/null 2>&1 || function whence() { LC_MESSAGES="C" type "$@" | sed -$SED_REGEX_ARG -e "s/.*is aliased to \`//" -e "s/'$//"; }
local cmd=''
for cmd in $(echo $scmb_wrapped_shell_commands); do
for cmd in $scmb_wrapped_shell_commands; do
if [ "${scmbDebug:-}" = "true" ]; then echo "SCMB: Wrapping $cmd..."; fi
# Special check for 'cd', to make sure SCM Breeze is loaded after RVM
if [ "$cmd" = 'cd' ]; then
if [ -e "$HOME/.rvm" ] && ! type rvm > /dev/null 2>&1; then
echo -e "\033[0;31mSCM Breeze must be loaded \033[1;31mafter\033[0;31m RVM, otherwise there will be a conflict when RVM wraps the 'cd' command.\033[0m"
echo -e "\033[0;31mPlease move the line that loads SCM Breeze to the bottom of your ~/.bashrc\033[0m"
echo -e "\\033[0;31mSCM Breeze must be loaded \\033[1;31mafter\\033[0;31m RVM, otherwise there will be a conflict when RVM wraps the 'cd' command.\\033[0m"
echo -e "\\033[0;31mPlease move the line that loads SCM Breeze to the bottom of your ~/.bashrc\\033[0m"
continue
fi
fi
case "$(LC_MESSAGES="C" type $cmd 2>&1)" in
case "$(LC_MESSAGES="C" type "$cmd" 2>&1)" in
# Don't do anything if command already aliased, or not found.
*'exec_scmb_expand_args'*)
@@ -49,10 +49,10 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
# Store original alias
local original_alias="$(whence $cmd)"
# Remove alias, so that we can find binary
unalias $cmd
unalias "$cmd"
# Detect original $cmd type, and escape
case "$(LC_MESSAGES="C" type $cmd 2>&1)" in
case "$(LC_MESSAGES="C" type "$cmd" 2>&1)" in
# Escape shell builtins with 'builtin'
*'is a shell builtin'*) local escaped_cmd="builtin $cmd";;
# Get full path for files with 'find_binary' function
@@ -67,9 +67,9 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
*'is a'*'function'*)
if [ "${scmbDebug:-}" = "true" ]; then echo "SCMB: $cmd is a function"; fi
# Copy old function into new name
eval "$(declare -f $cmd | sed -$SED_REGEX_ARG "s/^$cmd \(\)/__original_$cmd ()/")"
eval "$(declare -f "$cmd" | sed -"$SED_REGEX_ARG" "s/^$cmd \\(\\)/__original_$cmd ()/")"
# Remove function
unset -f $cmd
unset -f "$cmd"
# Create function that wraps old function
eval "${cmd}(){ exec_scmb_expand_args __original_${cmd} \"\$@\"; }";;
@@ -92,61 +92,95 @@ if [ "$shell_command_wrapping_enabled" = "true" ] || [ "$bash_command_wrapping_e
fi
# BSD ls is different to Linux (GNU) ls
# Test for BSD ls
if ! ls --color=auto > /dev/null 2>&1; then
# ls is BSD
_ls_bsd="BSD"
fi
# Test if readlink supports -f option, otherwise use perl (a bit slower)
if ! readlink -f > /dev/null 2>&1; then
_abs_path_command='perl -e "use Cwd "abs_path"; print abs_path(shift)"'
else
_abs_path_command="readlink -f"
fi
# Function wrapper around 'll'
# Adds numbered shortcuts to output of ls -l, just like 'git status'
if [ "$shell_ls_aliases_enabled" = "true" ] && which ruby > /dev/null 2>&1; then
if [ "$shell_ls_aliases_enabled" = "true" ] && builtin command -v ruby > /dev/null 2>&1; then
# BSD ls is different to Linux (GNU) ls
# Test for BSD ls
if ! ls --color=auto > /dev/null 2>&1; then
# ls is BSD
_ls_bsd="BSD"
fi
# Test if readlink supports -f option, test for greadlink on Mac, then fallback to perl
if \readlink -f / > /dev/null 2>&1; then
_abs_path_command=(readlink -f)
elif greadlink -f / > /dev/null 2>&1; then
_abs_path_command=(greadlink -f)
else
_abs_path_command=(perl -e 'use Cwd abs_path; print abs_path(shift)')
fi
unalias ll > /dev/null 2>&1; unset -f ll > /dev/null 2>&1
function ls_with_file_shortcuts {
local ll_output
local ll_command # Ensure sort ordering of the two invocations is the same
if [ "$_ls_bsd" != "BSD" ]; then
ll_output="$(\ls -lhv --group-directories-first --color "$@")"
ll_command=(\ls -hv --group-directories-first)
ll_output="$("${ll_command[@]}" -l --color "$@")"
else
ll_output="$(CLICOLOR_FORCE=1 \ls -l -G "$@")"
ll_command=(\ls)
ll_output="$(CLICOLOR_FORCE=1 "${ll_command[@]}" -lG "$@")"
fi
if [[ $shell == "zsh" ]]; then
# Ensure sh_word_split is on
if setopt | grep -q shwordsplit; then SHWORDSPLIT_ON=true; fi
[[ -o shwordsplit ]] && SHWORDSPLIT_ON=true
setopt shwordsplit
fi
# Parse path from args
IFS=$'\n'
for arg in $@; do
if [ -d "$arg" ]; then local rel_path="${arg%/}"; fi
# Get the directory that `ls` is being run relative to.
# Only allow one directory to avoid incorrect $e# variables when listing
# multiple directories (issue #274)
local IFS=$'\n'
local rel_path
for arg in "$@"; do
if [[ -e $arg ]]; then # Path rather than option to ls
if [[ -z $rel_path ]]; then # We are seeing our first pathname
if [[ -d $arg ]]; then # It's a directory
rel_path=$arg
else # It's a file, expand the current directory
rel_path=.
fi
elif [[ -d $arg || ( -f $arg && $rel_path != . ) ]]; then
if [[ -f $arg ]]; then arg=$PWD; fi # Get directory for current argument
# We've already seen a different directory. Quit to avoid damage (issue #274)
printf 'scm_breeze: Cannot list relative to both directories:\n %s\n %s\n' "$arg" "$rel_path" >&2
printf 'Currently only listing a single directory is supported. See issue #274.\n' >&2
return 1
fi
fi
done
unset IFS
rel_path=$("${_abs_path_command[@]}" ${rel_path:-$PWD})
# Replace user/group with user symbol, if defined at ~/.user_sym
# Before : -rw-rw-r-- 1 ndbroadbent ndbroadbent 1.1K Sep 19 21:39 scm_breeze.sh
# After : -rw-rw-r-- 1 𝐍 𝐍 1.1K Sep 19 21:39 scm_breeze.sh
if [ -e $HOME/.user_sym ]; then
if [ -e "$HOME"/.user_sym ]; then
# Little bit of ruby golf to rejustify the user/group/size columns after replacement
# TODO(ghthor): Convert this to a cat <<EOF to improve readibility
function rejustify_ls_columns(){
ruby -e "o=STDIN.read;re=/^(([^ ]* +){2})(([^ ]* +){3})/;\
u,g,s=o.lines.map{|l|l[re,3]}.compact.map(&:split).transpose.map{|a|a.map(&:size).max+1};\
puts o.lines.map{|l|l.sub(re){|m|\"%s%-#{u}s %-#{g}s%#{s}s \"%[\$1,*\$3.split]}}"
}
ll_output=$(echo "$ll_output" | \sed -$SED_REGEX_ARG "s/ $USER/ $(/bin/cat $HOME/.user_sym)/g" | rejustify_ls_columns)
local USER_SYM=$(/bin/cat $HOME/.user_sym)
if [ -f "$HOME/.staff_sym" ]; then
local STAFF_SYM=$(/bin/cat $HOME/.staff_sym)
ll_output=$(echo "$ll_output" | \
\sed -$SED_REGEX_ARG "s/ $USER staff/ $USER_SYM $STAFF_SYM /g" | \
rejustify_ls_columns)
else
ll_output=$(echo "$ll_output" | \
\sed -$SED_REGEX_ARG "s/ $USER/ $USER_SYM /g" | \
rejustify_ls_columns)
fi
fi
# Bail if there are two many lines to process
if [ "$(echo "$ll_output" | wc -l)" -gt "50" ]; then
echo -e "\033[33mToo many files to create shortcuts. Running plain ll command...\033[0m"
echo -e '\033[33mToo many files to create shortcuts. Running plain ll command...\033[0m' >&2
echo "$ll_output"
return 1
fi
@@ -169,23 +203,26 @@ EOF
local ll_files=''
local file=''
# XXX FIXME XXX
# There is a race condition here: If a file is removed between the above
# and this second call of `ls` then the $e# variables can refer to the
# wrong files.
if [ -z $_ls_bsd ]; then
ll_files="$(\ls -v --group-directories-first --color=never "$@")"
ll_files="$(QUOTING_STYLE=literal "${ll_command[@]}" --color=never "$@")"
else
ll_files="$(\ls "$@")"
ll_files="$("${ll_command[@]}" "$@")"
fi
IFS=$'\n'
local IFS=$'\n'
for file in $ll_files; do
if [ -n "$rel_path" ]; then file="$rel_path/$file"; fi
export $git_env_char$e="$(eval $_abs_path_command \"${file//\"/\\\"}\")"
if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi
file=$rel_path/$file
export $git_env_char$e=$("${_abs_path_command[@]}" "$file")
if [[ ${scmbDebug:-} = true ]]; then echo "Set \$$git_env_char$e => $file"; fi
let e++
done
unset IFS
# Turn off shwordsplit unless it was on previously
if [[ $shell == "zsh" ]] && [ -z "$SHWORDSPLIT_ON" ]; then unsetopt shwordsplit; fi
if [[ $shell == "zsh" && -z $SHWORDSPLIT_ON ]]; then unsetopt shwordsplit; fi
}
# Setup aliases

View File

@@ -26,7 +26,7 @@
git_status_lines = @git_status.split("\n")
git_branch = git_status_lines[0]
@branch = git_branch[/^## (?:Initial commit on )?([^ \.]+)/, 1]
@branch = git_branch[/^## (?:Initial commit on )?([^ ]+)/, 1]
@ahead = git_branch[/\[ahead ?(\d+).*\]/, 1]
@behind = git_branch[/\[.*behind ?(\d+)\]/, 1]
@@ -76,16 +76,15 @@ difference = difference.length > 0 ? " #{@c[:dark]}| #{@c[:new]}#{difference}#
# If no changes, just display green no changes message and exit here
if @git_status == ""
puts "%s#%s On branch: %s#{@branch}#{difference} %s| \033[0;32mNo changes (working directory clean)%s" % [
@c[:dark], @c[:rst], @c[:branch], @c[:dark], @c[:rst]
if @changes.size == 0
puts "%s#%s On branch: %s#{@branch}#{difference}%s %s| \033[0;32mNo changes (working directory clean)%s" % [
@c[:dark], @c[:rst], @c[:branch], @c[:rst], @c[:dark], @c[:rst]
]
exit
end
puts "%s#%s On branch: %s#{@branch}#{difference} %s| [%s*%s]%s => $#{ENV["git_env_char"]}*\n%s#%s" % [
@c[:dark], @c[:rst], @c[:branch], @c[:dark], @c[:rst], @c[:dark], @c[:rst], @c[:dark], @c[:rst]
puts "%s#%s On branch: %s#{@branch}#{difference}%s %s| [%s*%s]%s => $#{ENV["git_env_char"]}*\n%s#%s" % [
@c[:dark], @c[:rst], @c[:branch], @c[:rst], @c[:dark], @c[:rst], @c[:dark], @c[:rst], @c[:dark], @c[:rst]
]
def has_modules?

View File

@@ -21,7 +21,7 @@ git_status_shortcuts() {
zsh_compat # Ensure shwordsplit is on for zsh
git_clear_vars
# Run ruby script, store output
local cmd_output="$(/usr/bin/env ruby "$scmbDir/lib/git/status_shortcuts.rb" $@)"
local cmd_output="$(/usr/bin/env ruby "$scmbDir/lib/git/status_shortcuts.rb" "$@")"
# Print debug information if $scmbDebug = "true"
if [ "${scmbDebug:-}" = "true" ]; then
printf "status_shortcuts.rb output => \n$cmd_output\n------------------------\n"
@@ -36,14 +36,13 @@ git_status_shortcuts() {
files="$(echo "$cmd_output" | \grep '@@filelist@@::' | sed 's%@@filelist@@::%%g')"
if [ "${scmbDebug:-}" = "true" ]; then echo "filelist => $files"; fi
# Export numbered env variables for each file
IFS="|"
local IFS="|"
local e=1
for file in $files; do
export $git_env_char$e="$file"
if [ "${scmbDebug:-}" = "true" ]; then echo "Set \$$git_env_char$e => $file"; fi
let e++
done
unset IFS
if [ "${scmbDebug:-}" = "true" ]; then echo "------------------------"; fi
# Print status
@@ -80,10 +79,11 @@ git_add_shortcuts() {
git_silent_add_shortcuts() {
if [ -n "$1" ]; then
# Expand args and process resulting set of files.
IFS=$'\t'
for file in $(scmb_expand_args "$@"); do
local args
eval args="$(scmb_expand_args "$@")" # populate $args array
for file in "${args[@]}"; do
# Use 'git rm' if file doesn't exist and 'ga_auto_remove' is enabled.
if [[ $ga_auto_remove == "yes" ]] && ! [ -e "$file" ]; then
if [[ $ga_auto_remove = yes && ! -e $file ]]; then
echo -n "# "
git rm "$file"
else
@@ -91,7 +91,6 @@ git_silent_add_shortcuts() {
echo -e "# Added '$file'"
fi
done
unset IFS
echo "#"
fi
}
@@ -100,18 +99,18 @@ git_silent_add_shortcuts() {
# and exports numbered environment variables for each file.
git_show_affected_files(){
fail_if_not_git_repo || return 1
f=0 # File count
local f=0 # File count
# Show colored revision and commit message
echo -n "# "; git show --oneline --name-only $@ | head -n1; echo "# "
for file in $(git show --pretty="format:" --name-only $@ | \grep -v '^$'); do
echo -n "# "; git show --oneline --name-only "$@" | head -n1; echo "# "
for file in $(git show --pretty="format:" --name-only "$@" | \grep -v '^$'); do
let f++
export $git_env_char$f=$file # Export numbered variable.
echo -e "# \033[2;37m[\033[0m$f\033[2;37m]\033[0m $file"
done; echo "# "
}
# Allows expansion of numbered shortcuts, ranges of shortcuts, or standard paths.
# Return a string which can be `eval`ed like: eval args="$(scmb_expand_args "$@")"
# Numbered shortcut variables are produced by various commands, such as:
# * git_status_shortcuts() - git status implementation
# * git_show_affected_files() - shows files affected by a given SHA1, etc.
@@ -122,43 +121,52 @@ scmb_expand_args() {
shift
fi
first=1
OLDIFS="$IFS"; IFS=" " # We need to split on spaces to loop over expanded range
local args
args=() # initially empty array. zsh 5.0.2 from Ubuntu 14.04 requires this to be separated
for arg in "$@"; do
if [[ "$arg" =~ ^[0-9]{0,4}$ ]] ; then # Substitute $e{*} variables for any integers
if [ "$first" -eq 1 ]; then first=0; else printf '\t'; fi
if [ -e "$arg" ]; then
# Don't expand files or directories with numeric names
printf '%s' "$arg"
args+=("$arg")
else
_print_path "$relative" "$git_env_char$arg"
args+=("$(_print_path "$relative" "$git_env_char$arg")")
fi
elif [[ "$arg" =~ ^[0-9]+-[0-9]+$ ]]; then # Expand ranges into $e{*} variables
for i in $(eval echo {${arg/-/..}}); do
if [ "$first" -eq 1 ]; then first=0; else printf '\t'; fi
_print_path "$relative" "$git_env_char$i"
args+=("$(_print_path "$relative" "$git_env_char$i")")
done
else # Otherwise, treat $arg as a normal string.
if [ "$first" -eq 1 ]; then first=0; else printf '\t'; fi
printf '%s' "$arg"
args+=("$arg")
fi
done
IFS="$OLDIFS"
# "declare -p" with zsh 5.0.2 on Ubuntu 14.04 creates a string that it cannot process:
# typeset -a args args=(one three six)
# There should be a ; between the two "args" tokens
# "declare -p" with bash 4.3.11(1) on Ubuntu 14.04 creates a string like:
# declare -a a='([0]="a" [1]="b c" [2]="d")'
# The RHS of this string is incompatible with zsh 5.0.2 and "eval args="
# Generate a quoted array string to assign to "eval args="
echo "( $(token_quote "${args[@]}") )"
}
# Expand a variable (named by $2) into a (possibly relative) pathname
_print_path() {
if [ "$1" = 1 ]; then
eval printf '%s' "\"\$$2\"" | sed -e "s%$(pwd)/%%" | awk '{printf("%s", $0)}'
else
eval printf '%s' "\"\$$2\""
local pathname
pathname=$(eval printf '%s' "\"\${$2}\"")
if [ "$1" = 1 ]; then # print relative
pathname=${pathname#$PWD/} # Remove $PWD from beginning of the path
fi
printf '%s' "$pathname"
}
# Execute a command with expanded args, e.g. Delete files 6 to 12: $ ge rm 6-12
# Fails if command is a number or range (probably not worth fixing)
exec_scmb_expand_args() {
eval "$(scmb_expand_args "$@" | sed -e "s/\([][|;()<>^ \"'&]\)/"'\\\1/g')"
local args
eval "args=$(scmb_expand_args "$@")" # populate $args array
_safe_eval "${args[@]}"
}
# Clear numbered env variables
@@ -180,13 +188,13 @@ git_clear_vars() {
_git_resolve_merge_conflict() {
if [ -n "$2" ]; then
# Expand args and process resulting set of files.
IFS=$'\t'
for file in $(scmb_expand_args "${@:2}"); do
local args
eval "args=$(scmb_expand_args "$@")" # populate $args array
for file in "${args[@]:2}"; do
git checkout "--$1""s" "$file" # "--$1""s" is expanded to --ours or --theirs
git add "$file"
echo -e "# Added $1 version of '$file'"
done
unset IFS
echo -e "# -- If you have finished resolving conflicts, commit the resolutions with 'git commit'"
fi
}
@@ -203,29 +211,62 @@ theirs(){ _git_resolve_merge_conflict "their" "$@"; }
# * Add escaped commit command and unescaped message to bash history.
git_commit_prompt() {
local commit_msg
local saved_commit_msg
if [ -f "/tmp/.git_commit_message~" ]; then
saved_commit_msg="$(cat /tmp/.git_commit_message~)"
echo -e "\033[0;36mLeave blank to use saved commit message: \033[0m$saved_commit_msg"
fi
if [[ $shell == "zsh" ]]; then
vared -h -p "Commit Message: " commit_msg
else
read -r -e -p "Commit Message: " commit_msg
fi
if [ -n "$commit_msg" ]; then
eval $@ # run any prequisite commands
# Add $APPEND to commit message, if given. (Used to append things like [ci skip] for Travis CI)
if [ -n "$APPEND" ]; then commit_msg="$commit_msg $APPEND"; fi
echo $commit_msg | git commit -F - | tail -n +2
else
echo -e "\033[0;31mAborting commit due to empty commit message.\033[0m"
if [ -z "$commit_msg" ]; then
if [ -n "$saved_commit_msg" ]; then
commit_msg="$saved_commit_msg"
else
echo -e "\033[0;31mAborting commit due to empty commit message.\033[0m"
return
fi
fi
escaped=$(echo "$commit_msg" | sed -e 's/"/\\"/g' -e 's/!/"'"'"'!'"'"'"/g')
# Add $GIT_COMMIT_MSG_SUFFIX to commit message, if given.
# (Used to append things like [ci skip] for Travis CI)
if [ -n "$GIT_COMMIT_MSG_SUFFIX" ]; then
commit_msg="$commit_msg $GIT_COMMIT_MSG_SUFFIX"
fi
# Exclamation marks are really difficult to escape properly in a bash prompt.
# They must always be enclosed with single quotes.
escaped_msg=$(echo "$commit_msg" | sed -e 's/"/\\"/g' -e "s/!/\"'!'\"/g")
# Add command to bash history, so that if a git pre-commit hook fails,
# you can just press "up" and "return" to retry the commit.
if [[ $shell == "zsh" ]]; then
print -s "git commit -m \"${escaped//\\/\\\\}\"" # zsh's print needs double escaping
print -s "$commit_msg"
# zsh's print needs double escaping
print -s "git commit -m \"${escaped_msg//\\/\\\\}\""
else
echo "git commit -m \"$escaped\"" >> $HISTFILE
# Also add unescaped commit message, for git prompt
echo "$commit_msg" >> $HISTFILE
history -s "git commit -m \"$escaped_msg\""
# Need to write history to a file for tests
if [ -n "$SHUNIT_VERSION" ]; then history -w $HISTFILE; fi
fi
# Also save the commit message to a temp file in case git commit fails
echo "$commit_msg" > "/tmp/.git_commit_message~"
eval $@ # run any prequisite commands
echo "$commit_msg" | git commit -F - | tail -n +2
# Fetch the pipe status (for both bash and zsh):
GIT_PIPE_STATUS=("${PIPESTATUS[@]}${pipestatus[@]}")
if [[ $shell == "zsh" ]]; then
git_exit_status="${GIT_PIPE_STATUS[2]}" # zsh array indexes start at 1
else
git_exit_status="${GIT_PIPE_STATUS[1]}"
fi
if [[ "$git_exit_status" == 0 ]]; then
# Delete saved commit message if commit was successful
rm -f "/tmp/.git_commit_message~"
fi
}
@@ -234,8 +275,8 @@ git_commit_all() {
fail_if_not_git_repo || return 1
changes=$(git status --porcelain | wc -l | tr -d ' ')
if [ "$changes" -gt 0 ]; then
if [ -n "$APPEND" ]; then
local appending=" | \033[0;36mappending '\033[1;36m$APPEND\033[0;36m' to commit message.\033[0m"
if [ -n "$GIT_COMMIT_MSG_SUFFIX" ]; then
local appending=" | \033[0;36mappending '\033[1;36m$GIT_COMMIT_MSG_SUFFIX\033[0;36m' to commit message.\033[0m"
fi
echo -e "\033[0;33mCommitting all files (\033[0;31m$changes\033[0;33m)\033[0m$appending"
git_commit_prompt "git add --all ."

View File

@@ -0,0 +1,328 @@
#!/usr/bin/env ruby
# encoding: UTF-8
# ------------------------------------------------------------------------------
# SCM Breeze - Streamline your SCM workflow.
# Copyright 2011 Nathan Broadbent (http://madebynathan.com). All Rights Reserved.
# Released under the LGPL (GNU Lesser General Public License)
# ------------------------------------------------------------------------------
#
# Original work by Nathan Broadbent
# Rewritten by LFDM
#
# A much faster implementation of git_status_shortcuts() in ruby
# (original benchmarks - bash: 0m0.549s, ruby: 0m0.045s, the updated
# version is twice as fast, especially noticable in big repos)
#
#
# Last line of output contains the ordered absolute file paths,
# which need to be extracted by the shell and exported as numbered env variables.
#
# Processes 'git status', and exports numbered
# env variables that contain the path of each affected file.
# Output is also more concise than standard 'git status'.
#
# Call with optional <group> parameter to just show one modification state
# # groups => 1: staged, 2: unmerged, 3: unstaged, 4: untracked
# --------------------------------------------------------------------
#
require 'strscan'
class GitStatus
def initialize(request = nil)
@request = request.to_s # capture nils
@status = get_status
@ahead, @behind = parse_remote_stat
@grouped_changes = parse_changes
@index = 0
end
def report
exit if all_changes.length > ENV["gs_max_changes"].to_i
print_header
print_groups
puts filelist if @grouped_changes.any?
end
######### Parsing methods #########
def get_status
`git status 2>/dev/null`
end
# Remote info is always on the second line of git status
def parse_remote_stat
remote_line = @status.lines[1].strip
if remote_line.match(/diverged/)
remote_line.match(/.*(\d*).*(\d*)/).captures
else
[remote_line[/is ahead of.*by (\d*).*/, 1], remote_line[/is behind.*by (\d*).*/, 1]]
end
end
# We have to resort to the StringScanner to stay away from overly complex
# regular expressions.
# The individual blocks are always formatted the same
#
# identifier Changes not staged for commit
# helper text (use "git add <file>..." ...
# empty line
# changed files, leaded by a tab modified: file
# deleted: other_file
# empty line
# next identifier Untracked files
# ...
#
# We parse each requested group and return a grouped hash, its values are
# arrays of GitChange objects.
def parse_changes
scanner = StringScanner.new(@status)
requested_groups.each_with_object({}) do |(type, identifier), h|
if scanner.scan_until(/#{identifier}/)
scan_until_next_empty_line(scanner)
file_block = scan_until_next_empty_line(scanner)
h[type] = extract_changes(file_block)
end
scanner.reset
end
end
def scan_until_next_empty_line(scanner)
scanner.scan_until(/\n\n/)
end
# Matches
# modified: file # usual output in git status
# modified: file (untracked content) # output for submodules
# file # untracked files have no additional info
def extract_changes(str)
str.lines.map do |line|
new_git_change(*Regexp.last_match.captures) if line.match(/\t(.*:)?(.*)/)
end.compact # in case there were any non matching lines left
end
def new_git_change(status, file_and_message)
status = 'untracked:' unless status
GitChange.new(file_and_message, status)
end
GROUPS = {
staged: 'Changes to be committed',
unmerged: 'Unmerged paths',
unstaged: 'Changes not staged for commit',
untracked: 'Untracked files'
}
# Returns all possible groups when there was no request at all,
# otherwise selects groups by name or integer
def requested_groups
@request.empty? ? GROUPS : select_groups
end
def select_groups
req = parse_request
GROUPS.select { |k, _| k == req }
end
def parse_request
if @request.match(/\d/)
GROUPS.keys[@request.to_i - 1]
else
@request.to_sym
end
end
######### Outputting methods #########
def print_header
puts delimiter(:header) + header
puts delimiter(:header) if anything_changed?
end
def print_groups
@grouped_changes.each do |type, changes|
print_group_header(type)
puts delimiter(type)
changes.each do |change|
raise_index!
print delimiter(type)
puts change.report_with_index(@index, type, padding)
end
puts delimiter(type)
end
end
def print_group_header(type)
puts "#{gmu('➤', type, 1)} #{GROUPS[type]}"
end
######### Items of interest #########
def branch
@status.lines.first.strip[/^On branch (.*)$/, 1]
end
def ahead
"+#{@ahead}" if @ahead
end
def behind
"-#{@behind}" if @behind
end
def difference
[behind, ahead].compact.join('/')
end
def header
parts = [[:branch, :branch], [:difference, :new]]
parts << (anything_changed? ? [:hotkey, :dark] : [:clean_state, :mod]) # mod is green
# compact because difference might return nil
"On branch: #{parts.map { |meth, col| mu(send(meth), col) }.compact.join(' | ')}"
end
def clean_state
"No changes (working directory clean)"
end
def hotkey
"[*] => $#{ENV['git_env_char']}"
end
# used to delimit the left side of the screen - looks nice
def delimiter(col)
gmu("# ", col)
end
def filelist
"@@filelist@@::#{all_changes.map(&:absolute_path).join('|')}"
end
######### Helper Methods #########
# To know about changes we could ask if there are any parsing results, as in
# @grouped_changes.any?, but that is not a good idea, since
# we might have selected a requested group before parsing already.
# Groups could be empty while there are in fact changes present,
# there we look into the original status string once
def anything_changed?
@any_changes ||=
! @status.match(/nothing to commit.*working directory clean/)
end
# needed by hotkey filelist
def raise_index!
@index += 1
end
def all_changes
@all_changes ||= @grouped_changes.values.flatten
end
# Dynamic padding, always looks for the longest status string present
# and adds a little whitespace
def padding
@padding ||= all_changes.map { |change| change.status.size }.max + 5
end
######### Markup/Color methods #########
COL = {
:rst => "0",
:header => "0",
:branch => "1",
:del => "0;31",
:mod => "0;32",
:new => "0;33",
:ren => "0;34",
:cpy => "0;33",
:typ => "0;35",
:unt => "0;36",
:dark => "2;37",
}
GR_COL = {
:staged => "33",
:unmerged => "31",
:unstaged => "32",
:untracked => "36",
}
# markup
def mu(str, col_in, col_out = :rst)
return if str.empty?
col_in = "\033[#{COL[col_in]}m"
col_out = "\033[#{COL[col_out]}m"
with_color(str, col_in, col_out)
end
# group markup
def gmu(str, group, boldness = 0, col_out = :rst)
group_col = "\033[#{boldness};#{GR_COL[group]}m"
col_out = "\033[#{COL[col_out]}m"
with_color(str, group_col, col_out)
end
def with_color(str, col_in, col_out)
"#{col_in}#{str}#{col_out}"
end
end
class GitChange < GitStatus
attr_reader :status
# Restructively singles out the submodules message and
# strips the remaining string to get rid of padding
def initialize(file_and_message, status)
@message = file_and_message.slice!(/\(.*\)/)
@file = file_and_message.strip
@file = (@file.include? " ") ? "\"#{@file}\"" : @file
@status = status.strip
end
def absolute_path
File.expand_path(@file, Dir.pwd)
end
STATUS_COLORS = {
"copied" => :cpy,
"both deleted" => :del,
"deleted by us" => :del,
"deleted by them" => :del,
"deleted" => :del,
"both modified" => :mod,
"modified" => :mod,
"added by them" => :new,
"added by us" => :new,
"both added" => :new,
"new file" => :new,
"renamed" => :ren,
"typechange" => :typ,
"untracked" => :unt,
}
# Looks like this
#
# PADDING STATUS INDEX FILE MESSAGE (optional)
# modified: [1] changed_file (untracked content)
#
def report_with_index(index, type, padding = 0)
"#{pad(padding)}#{mu(@status, color_key)} " +
"#{mu("[#{index}]", :dark)} #{gmu(@file, type)} #{@message}"
end
# we most likely have a : with us which we don't need here
def color_key
STATUS_COLORS[@status.chomp(':')]
end
def pad(padding)
' ' * (padding - @status.size)
end
end
GitStatus.new(ARGV.first).report

View File

@@ -23,8 +23,9 @@ git_remove_history() {
return
fi
# Remove all paths passed as arguments from the history of the repo
files=$@
$_git_cmd filter-branch --index-filter "$_git_cmd rm -rf --cached --ignore-unmatch $files" HEAD
local files
files=("$@")
$_git_cmd filter-branch --index-filter "$_git_cmd rm -rf --cached --ignore-unmatch ${files[*]}" HEAD
# Remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && $_git_cmd reflog expire --all && $_git_cmd gc --aggressive --prune
}
@@ -142,4 +143,4 @@ git_branch_delete_all() {
commit_docs() {
git commit -m "Update README / Documentation [ci skip]"
}
}