codekingpro/portable-devtools
114k
1# This shell scriplet is meant to be included by other shell scripts2# to set up some variables pointing at the normal git directories and3# a few helper shell functions.4 5# Having this variable in your environment would break scripts because6# you would cause "cd" to be taken to unexpected places. If you7# like CDPATH, define it for your interactive shell sessions without8# exporting it.9# But we protect ourselves from such a user mistake nevertheless.10unset CDPATH11 12# Similarly for IFS, but some shells (e.g. FreeBSD 7.2) are buggy and13# do not equate an unset IFS with IFS with the default, so here is14# an explicit SP HT LF.15IFS=' 16'17 18git_broken_path_fix () {19 case ":$PATH:" in20 *:$1:*) : ok ;;21 *)22 PATH=$(23 SANE_TOOL_PATH="$1"24 IFS=: path= sep=25 set x $PATH26 shift27 for elem28 do29 case "$SANE_TOOL_PATH:$elem" in30 (?*:/bin | ?*:/usr/bin)31 path="$path$sep$SANE_TOOL_PATH"32 sep=:33 SANE_TOOL_PATH=34 esac35 path="$path$sep$elem"36 sep=:37 done38 echo "$path"39 )40 ;;41 esac42}43 44 45# Source git-sh-i18n for gettext support.46. "$(git --exec-path)/git-sh-i18n"47 48die () {49 die_with_status 1 "$@"50}51 52die_with_status () {53 status=$154 shift55 printf >&2 '%s\n' "$*"56 exit "$status"57}58 59if test -n "$OPTIONS_SPEC"; then60 usage() {61 "$0" -h62 exit 163 }64 65 parseopt_extra=66 [ -n "$OPTIONS_KEEPDASHDASH" ] &&67 parseopt_extra="--keep-dashdash"68 [ -n "$OPTIONS_STUCKLONG" ] &&69 parseopt_extra="$parseopt_extra --stuck-long"70 71 eval "$(72 echo "$OPTIONS_SPEC" |73 git rev-parse --parseopt $parseopt_extra -- "$@" ||74 echo exit $?75 )"76else77 dashless=$(basename -- "$0" | sed -e 's/-/ /')78 usage() {79 die "$(eval_gettext "usage: \$dashless \$USAGE")"80 }81 82 if [ -z "$LONG_USAGE" ]83 then84 LONG_USAGE="$(eval_gettext "usage: \$dashless \$USAGE")"85 else86 LONG_USAGE="$(eval_gettext "usage: \$dashless \$USAGE87 88$LONG_USAGE")"89 fi90 91 case "$1" in92 -h)93 echo "$LONG_USAGE"94 exit95 esac96fi97 98# Set the name of the end-user facing command in the reflog when the99# script may update refs. When GIT_REFLOG_ACTION is already set, this100# will not overwrite it, so that a scripted Porcelain (e.g. "git101# rebase") can set it to its own name (e.g. "rebase") and then call102# another scripted Porcelain (e.g. "git am") and a call to this103# function in the latter will keep the name of the end-user facing104# program (e.g. "rebase") in GIT_REFLOG_ACTION, ensuring whatever it105# does will be record as actions done as part of the end-user facing106# operation (e.g. "rebase").107#108# NOTE NOTE NOTE: consequently, after assigning a specific message to109# GIT_REFLOG_ACTION when calling a "git" command to record a custom110# reflog message, do not leave that custom value in GIT_REFLOG_ACTION,111# after you are done. Other callers of "git" commands that rely on112# writing the default "program name" in reflog expect the variable to113# contain the value set by this function.114#115# To use a custom reflog message, do either one of these three:116#117# (a) use a single-shot export form:118# GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz" \119# git command-that-updates-a-ref120#121# (b) save the original away and restore:122# SAVED_ACTION=$GIT_REFLOG_ACTION123# GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz"124# git command-that-updates-a-ref125# GIT_REFLOG_ACITON=$SAVED_ACTION126#127# (c) assign the variable in a subshell:128# (129# GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz"130# git command-that-updates-a-ref131# )132set_reflog_action() {133 if [ -z "${GIT_REFLOG_ACTION:+set}" ]134 then135 GIT_REFLOG_ACTION="$*"136 export GIT_REFLOG_ACTION137 fi138}139 140git_editor() {141 if test -z "${GIT_EDITOR:+set}"142 then143 GIT_EDITOR="$(git var GIT_EDITOR)" || return $?144 fi145 146 eval "$GIT_EDITOR" '"$@"'147}148 149git_pager() {150 if test -t 1151 then152 GIT_PAGER=$(git var GIT_PAGER)153 else154 GIT_PAGER=cat155 fi156 for vardef in LESS=FRX LV=-c157 do158 var=${vardef%%=*}159 eval ": \"\${$vardef}\" && export $var"160 done161 162 eval "$GIT_PAGER" '"$@"'163}164 165is_bare_repository () {166 git rev-parse --is-bare-repository167}168 169cd_to_toplevel () {170 cdup=$(git rev-parse --show-toplevel) &&171 cd "$cdup" || {172 gettextln "Cannot chdir to \$cdup, the toplevel of the working tree" >&2173 exit 1174 }175}176 177require_work_tree_exists () {178 if test "z$(git rev-parse --is-bare-repository)" != zfalse179 then180 program_name=$0181 die "$(eval_gettext "fatal: \$program_name cannot be used without a working tree.")"182 fi183}184 185require_work_tree () {186 test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true || {187 program_name=$0188 die "$(eval_gettext "fatal: \$program_name cannot be used without a working tree.")"189 }190}191 192require_clean_work_tree () {193 git rev-parse --verify HEAD >/dev/null || exit 1194 git update-index -q --ignore-submodules --refresh195 err=0196 197 if ! git diff-files --quiet --ignore-submodules198 then199 action=$1200 case "$action" in201 "rewrite branches")202 gettextln "Cannot rewrite branches: You have unstaged changes." >&2203 ;;204 *)205 eval_gettextln "Cannot \$action: You have unstaged changes." >&2206 ;;207 esac208 err=1209 fi210 211 if ! git diff-index --cached --quiet --ignore-submodules HEAD --212 then213 if test $err = 0214 then215 action=$1216 eval_gettextln "Cannot \$action: Your index contains uncommitted changes." >&2217 else218 gettextln "Additionally, your index contains uncommitted changes." >&2219 fi220 err=1221 fi222 223 if test $err = 1224 then225 test -n "$2" && echo "$2" >&2226 exit 1227 fi228}229 230# Generate a sed script to parse identities from a commit.231#232# Reads the commit from stdin, which should be in raw format (e.g., from233# cat-file or "--pretty=raw").234#235# The first argument specifies the ident line to parse (e.g., "author"), and236# the second specifies the environment variable to put it in (e.g., "AUTHOR"237# for "GIT_AUTHOR_*"). Multiple pairs can be given to parse author and238# committer.239pick_ident_script () {240 while test $# -gt 0241 do242 lid=$1; shift243 uid=$1; shift244 printf '%s' "245 /^$lid /{246 s/'/'\\\\''/g247 h248 s/^$lid "'\([^<]*\) <[^>]*> .*$/\1/'"249 s/.*/GIT_${uid}_NAME='&'/p250 251 g252 s/^$lid "'[^<]* <\([^>]*\)> .*$/\1/'"253 s/.*/GIT_${uid}_EMAIL='&'/p254 255 g256 s/^$lid "'[^<]* <[^>]*> \(.*\)$/@\1/'"257 s/.*/GIT_${uid}_DATE='&'/p258 }259 "260 done261 echo '/^$/q'262}263 264# Create a pick-script as above and feed it to sed. Stdout is suitable for265# feeding to eval.266parse_ident_from_commit () {267 LANG=C LC_ALL=C sed -ne "$(pick_ident_script "$@")"268}269 270# Parse the author from a commit given as an argument. Stdout is suitable for271# feeding to eval to set the usual GIT_* ident variables.272get_author_ident_from_commit () {273 encoding=$(git config i18n.commitencoding || echo UTF-8)274 git show -s --pretty=raw --encoding="$encoding" "$1" -- |275 parse_ident_from_commit author AUTHOR276}277 278# Generate a virtual base file for a two-file merge. Uses git apply to279# remove lines from $1 that are not in $2, leaving only common lines.280create_virtual_base() {281 sz0=$(wc -c <"$1")282 diff -u -La/"$1" -Lb/"$1" "$1" "$2" | git apply --no-add283 sz1=$(wc -c <"$1")284 285 # If we do not have enough common material, it is not286 # worth trying two-file merge using common subsections.287 expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$1"288}289 290 291# Platform specific tweaks to work around some commands292case $(uname -s) in293*MINGW*)294 if test -x /usr/bin/sort295 then296 # Windows has its own (incompatible) sort; override297 sort () {298 /usr/bin/sort "$@"299 }300 fi301 if test -x /usr/bin/find302 then303 # Windows has its own (incompatible) find; override304 find () {305 /usr/bin/find "$@"306 }307 fi308 # On Windows, Git wants Windows paths. But /usr/bin/pwd spits out309 # Unix-style paths. At least in Bash, we have a builtin pwd that310 # understands the -W option to force "mixed" paths, i.e. with drive311 # prefix but still with forward slashes. Let's use that, if available.312 if type builtin >/dev/null 2>&1313 then314 pwd () {315 builtin pwd -W316 }317 fi318 is_absolute_path () {319 case "$1" in320 [/\\]* | [A-Za-z]:*)321 return 0 ;;322 esac323 return 1324 }325 ;;326*)327 is_absolute_path () {328 case "$1" in329 /*)330 return 0 ;;331 esac332 return 1333 }334esac335 336# Make sure we are in a valid repository of a vintage we understand,337# if we require to be in a git repository.338git_dir_init () {339 GIT_DIR=$(git rev-parse --git-dir) || exit340 if [ -z "$SUBDIRECTORY_OK" ]341 then342 test -z "$(git rev-parse --show-cdup)" || {343 exit=$?344 gettextln "You need to run this command from the toplevel of the working tree." >&2345 exit $exit346 }347 fi348 test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {349 gettextln "Unable to determine absolute path of git directory" >&2350 exit 1351 }352 : "${GIT_OBJECT_DIRECTORY="$(git rev-parse --git-path objects)"}"353}354 355if test -z "$NONGIT_OK"356then357 git_dir_init358fi359 360peel_committish () {361 case "$1" in362 :/*)363 peeltmp=$(git rev-parse --verify "$1") &&364 git rev-parse --verify "${peeltmp}^0"365 ;;366 *)367 git rev-parse --verify "${1}^0"368 ;;369 esac370}371 