git-sh-setup.sh 9.14 KB
Newer Older
1 2 3
# This shell scriplet is meant to be included by other shell scripts
# to set up some variables pointing at the normal git directories and
# a few helper shell functions.
4

Junio C Hamano's avatar
Junio C Hamano committed
5
# Having this variable in your environment would break scripts because
6
# you would cause "cd" to be taken to unexpected places.  If you
Junio C Hamano's avatar
Junio C Hamano committed
7 8
# like CDPATH, define it for your interactive shell sessions without
# exporting it.
9
# But we protect ourselves from such a user mistake nevertheless.
Junio C Hamano's avatar
Junio C Hamano committed
10 11
unset CDPATH

12 13 14 15 16
# Similarly for IFS, but some shells (e.g. FreeBSD 7.2) are buggy and
# do not equate an unset IFS with IFS with the default, so here is
# an explicit SP HT LF.
IFS=' 	
'
17

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
git_broken_path_fix () {
	case ":$PATH:" in
	*:$1:*) : ok ;;
	*)
		PATH=$(
			SANE_TOOL_PATH="$1"
			IFS=: path= sep=
			set x $PATH
			shift
			for elem
			do
				case "$SANE_TOOL_PATH:$elem" in
				(?*:/bin | ?*:/usr/bin)
					path="$path$sep$SANE_TOOL_PATH"
					sep=:
					SANE_TOOL_PATH=
				esac
				path="$path$sep$elem"
				sep=:
			done
			echo "$path"
		)
		;;
	esac
}

# @@BROKEN_PATH_FIX@@
45

46 47 48
# Source git-sh-i18n for gettext support.
. "$(git --exec-path)/git-sh-i18n"

49 50 51 52 53 54 55
die () {
	die_with_status 1 "$@"
}

die_with_status () {
	status=$1
	shift
56
	printf >&2 '%s\n' "$*"
57
	exit "$status"
58 59
}

60 61 62 63 64 65 66 67 68
GIT_QUIET=

say () {
	if test -z "$GIT_QUIET"
	then
		printf '%s\n' "$*"
	fi
}

69 70
if test -n "$OPTIONS_SPEC"; then
	usage() {
71 72
		"$0" -h
		exit 1
73 74
	}

75 76 77
	parseopt_extra=
	[ -n "$OPTIONS_KEEPDASHDASH" ] &&
		parseopt_extra="--keep-dashdash"
78 79
	[ -n "$OPTIONS_STUCKLONG" ] &&
		parseopt_extra="$parseopt_extra --stuck-long"
80 81

	eval "$(
82
		echo "$OPTIONS_SPEC" |
83 84 85
			git rev-parse --parseopt $parseopt_extra -- "$@" ||
		echo exit $?
	)"
86
else
87
	dashless=$(basename -- "$0" | sed -e 's/-/ /')
88
	usage() {
89
		die "$(eval_gettext "usage: \$dashless \$USAGE")"
90 91 92 93
	}

	if [ -z "$LONG_USAGE" ]
	then
94
		LONG_USAGE="$(eval_gettext "usage: \$dashless \$USAGE")"
95
	else
96
		LONG_USAGE="$(eval_gettext "usage: \$dashless \$USAGE
97

98
$LONG_USAGE")"
99 100 101
	fi

	case "$1" in
102
		-h)
103
		echo "$LONG_USAGE"
104
		case "$0" in *git-legacy-stash) exit 129;; esac
105 106 107
		exit
	esac
fi
108

109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
# Set the name of the end-user facing command in the reflog when the
# script may update refs.  When GIT_REFLOG_ACTION is already set, this
# will not overwrite it, so that a scripted Porcelain (e.g. "git
# rebase") can set it to its own name (e.g. "rebase") and then call
# another scripted Porcelain (e.g. "git am") and a call to this
# function in the latter will keep the name of the end-user facing
# program (e.g. "rebase") in GIT_REFLOG_ACTION, ensuring whatever it
# does will be record as actions done as part of the end-user facing
# operation (e.g. "rebase").
#
# NOTE NOTE NOTE: consequently, after assigning a specific message to
# GIT_REFLOG_ACTION when calling a "git" command to record a custom
# reflog message, do not leave that custom value in GIT_REFLOG_ACTION,
# after you are done.  Other callers of "git" commands that rely on
# writing the default "program name" in reflog expect the variable to
# contain the value set by this function.
#
# To use a custom reflog message, do either one of these three:
#
# (a) use a single-shot export form:
#     GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz" \
#         git command-that-updates-a-ref
#
# (b) save the original away and restore:
#     SAVED_ACTION=$GIT_REFLOG_ACTION
#     GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz"
#     git command-that-updates-a-ref
#     GIT_REFLOG_ACITON=$SAVED_ACTION
#
# (c) assign the variable in a subshell:
#     (
#         GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: preparing frotz"
#         git command-that-updates-a-ref
#     )
143 144 145 146 147 148 149 150
set_reflog_action() {
	if [ -z "${GIT_REFLOG_ACTION:+set}" ]
	then
		GIT_REFLOG_ACTION="$*"
		export GIT_REFLOG_ACTION
	fi
}

151
git_editor() {
152 153 154 155 156 157
	if test -z "${GIT_EDITOR:+set}"
	then
		GIT_EDITOR="$(git var GIT_EDITOR)" || return $?
	fi

	eval "$GIT_EDITOR" '"$@"'
158 159
}

160 161 162 163 164 165 166
git_pager() {
	if test -t 1
	then
		GIT_PAGER=$(git var GIT_PAGER)
	else
		GIT_PAGER=cat
	fi
167 168 169 170 171
	for vardef in @@PAGER_ENV@@
	do
		var=${vardef%%=*}
		eval ": \"\${$vardef}\" && export $var"
	done
172 173 174 175

	eval "$GIT_PAGER" '"$@"'
}

176
sane_grep () {
177
	GREP_OPTIONS= LC_ALL=C grep @@SANE_TEXT_GREP@@ "$@"
178 179 180
}

sane_egrep () {
181
	GREP_OPTIONS= LC_ALL=C egrep @@SANE_TEXT_GREP@@ "$@"
182 183
}

184
is_bare_repository () {
185
	git rev-parse --is-bare-repository
186 187
}

188
cd_to_toplevel () {
189 190
	cdup=$(git rev-parse --show-toplevel) &&
	cd "$cdup" || {
191
		gettextln "Cannot chdir to \$cdup, the toplevel of the working tree" >&2
192 193
		exit 1
	}
194 195
}

196 197 198
require_work_tree_exists () {
	if test "z$(git rev-parse --is-bare-repository)" != zfalse
	then
199
		program_name=$0
200
		die "$(eval_gettext "fatal: \$program_name cannot be used without a working tree.")"
201 202 203
	fi
}

204
require_work_tree () {
205 206
	test "$(git rev-parse --is-inside-work-tree 2>/dev/null)" = true || {
		program_name=$0
207
		die "$(eval_gettext "fatal: \$program_name cannot be used without a working tree.")"
208
	}
209 210
}

211 212 213 214 215 216 217
require_clean_work_tree () {
	git rev-parse --verify HEAD >/dev/null || exit 1
	git update-index -q --ignore-submodules --refresh
	err=0

	if ! git diff-files --quiet --ignore-submodules
	then
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
		action=$1
		case "$action" in
		rebase)
			gettextln "Cannot rebase: You have unstaged changes." >&2
			;;
		"rewrite branches")
			gettextln "Cannot rewrite branches: You have unstaged changes." >&2
			;;
		"pull with rebase")
			gettextln "Cannot pull with rebase: You have unstaged changes." >&2
			;;
		*)
			eval_gettextln "Cannot \$action: You have unstaged changes." >&2
			;;
		esac
233 234 235 236 237
		err=1
	fi

	if ! git diff-index --cached --quiet --ignore-submodules HEAD --
	then
238
		if test $err = 0
239
		then
240 241 242 243 244 245 246 247 248 249 250 251
			action=$1
			case "$action" in
			rebase)
				gettextln "Cannot rebase: Your index contains uncommitted changes." >&2
				;;
			"pull with rebase")
				gettextln "Cannot pull with rebase: Your index contains uncommitted changes." >&2
				;;
			*)
				eval_gettextln "Cannot \$action: Your index contains uncommitted changes." >&2
				;;
			esac
252
		else
253
		    gettextln "Additionally, your index contains uncommitted changes." >&2
254 255 256 257
		fi
		err=1
	fi

258
	if test $err = 1
259
	then
260
		test -n "$2" && echo "$2" >&2
261 262 263 264
		exit 1
	fi
}

265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
# Generate a sed script to parse identities from a commit.
#
# Reads the commit from stdin, which should be in raw format (e.g., from
# cat-file or "--pretty=raw").
#
# The first argument specifies the ident line to parse (e.g., "author"), and
# the second specifies the environment variable to put it in (e.g., "AUTHOR"
# for "GIT_AUTHOR_*"). Multiple pairs can be given to parse author and
# committer.
pick_ident_script () {
	while test $# -gt 0
	do
		lid=$1; shift
		uid=$1; shift
		printf '%s' "
		/^$lid /{
			s/'/'\\\\''/g
			h
			s/^$lid "'\([^<]*\) <[^>]*> .*$/\1/'"
			s/.*/GIT_${uid}_NAME='&'/p

			g
			s/^$lid "'[^<]* <\([^>]*\)> .*$/\1/'"
			s/.*/GIT_${uid}_EMAIL='&'/p

			g
			s/^$lid "'[^<]* <[^>]*> \(.*\)$/@\1/'"
			s/.*/GIT_${uid}_DATE='&'/p
		}
		"
	done
	echo '/^$/q'
}

# Create a pick-script as above and feed it to sed. Stdout is suitable for
# feeding to eval.
parse_ident_from_commit () {
	LANG=C LC_ALL=C sed -ne "$(pick_ident_script "$@")"
}

# Parse the author from a commit given as an argument. Stdout is suitable for
# feeding to eval to set the usual GIT_* ident variables.
307 308
get_author_ident_from_commit () {
	encoding=$(git config i18n.commitencoding || echo UTF-8)
309
	git show -s --pretty=raw --encoding="$encoding" "$1" -- |
310
	parse_ident_from_commit author AUTHOR
311 312
}

313 314 315 316 317 318 319
# Clear repo-local GIT_* environment variables. Useful when switching to
# another repository (e.g. when entering a submodule). See also the env
# list in git_connect()
clear_local_git_env() {
	unset $(git rev-parse --local-env-vars)
}

320 321 322 323 324 325 326 327 328 329 330 331
# Generate a virtual base file for a two-file merge. Uses git apply to
# remove lines from $1 that are not in $2, leaving only common lines.
create_virtual_base() {
	sz0=$(wc -c <"$1")
	@@DIFF@@ -u -La/"$1" -Lb/"$1" "$1" "$2" | git apply --no-add
	sz1=$(wc -c <"$1")

	# If we do not have enough common material, it is not
	# worth trying two-file merge using common subsections.
	expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$1"
}

332

333
# Platform specific tweaks to work around some commands
334 335 336 337 338 339 340 341 342
case $(uname -s) in
*MINGW*)
	# Windows has its own (incompatible) sort and find
	sort () {
		/usr/bin/sort "$@"
	}
	find () {
		/usr/bin/find "$@"
	}
343 344 345 346
	# git sees Windows-style pwd
	pwd () {
		builtin pwd -W
	}
347 348 349 350 351 352 353
	is_absolute_path () {
		case "$1" in
		[/\\]* | [A-Za-z]:*)
			return 0 ;;
		esac
		return 1
	}
354
	;;
355 356 357 358 359 360 361 362
*)
	is_absolute_path () {
		case "$1" in
		/*)
			return 0 ;;
		esac
		return 1
	}
363
esac
364 365 366

# Make sure we are in a valid repository of a vintage we understand,
# if we require to be in a git repository.
367
git_dir_init () {
368 369 370 371 372
	GIT_DIR=$(git rev-parse --git-dir) || exit
	if [ -z "$SUBDIRECTORY_OK" ]
	then
		test -z "$(git rev-parse --show-cdup)" || {
			exit=$?
373
			gettextln "You need to run this command from the toplevel of the working tree." >&2
374 375 376 377
			exit $exit
		}
	fi
	test -n "$GIT_DIR" && GIT_DIR=$(cd "$GIT_DIR" && pwd) || {
378
		gettextln "Unable to determine absolute path of git directory" >&2
379 380
		exit 1
	}
381
	: "${GIT_OBJECT_DIRECTORY="$(git rev-parse --git-path objects)"}"
382 383 384 385 386
}

if test -z "$NONGIT_OK"
then
	git_dir_init
387
fi
388 389 390 391 392 393 394 395 396 397 398 399

peel_committish () {
	case "$1" in
	:/*)
		peeltmp=$(git rev-parse --verify "$1") &&
		git rev-parse --verify "${peeltmp}^0"
		;;
	*)
		git rev-parse --verify "${1}^0"
		;;
	esac
}