Staging
v0.8.1
Revision be15f50538afa4bfb912a86fa9d9f141010ad691 authored by Linus Torvalds on 11 December 2007, 04:08:06 UTC, committed by Junio C Hamano on 11 December 2007, 08:38:46 UTC
Commit 396865859918e9c7bf8ce74aae137c57da134610 broke signed tags using
the "-u" flag when it made builtin-tag.c use parse_options() to parse its
arguments (but it quite possibly was broken even before that, by the
builtin rewrite).

It used to be that passing the signing ID with the -u parameter also
(obviously!) implied that you wanted to sign and annotate the tag, but
that logic got dropped. It also totally ignored the actual key ID that was
passed in.

This reinstates it all.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent ace9c2a
Raw File
git-clone.sh
#!/bin/sh
#
# Copyright (c) 2005, Linus Torvalds
# Copyright (c) 2005, Junio C Hamano
#
# Clone a repository into a different directory that does not yet exist.

# See git-sh-setup why.
unset CDPATH

OPTIONS_SPEC="\
git-clone [options] [--] <repo> [<dir>]
--
n,no-checkout        don't create a checkout
bare                 create a bare repository
naked                create a bare repository
l,local              to clone from a local repository
no-hardlinks         don't use local hardlinks, always copy
s,shared             setup as a shared repository
template=            path to the template directory
q,quiet              be quiet
reference=           reference repository
o,origin=            use <name> instead of 'origin' to track upstream
u,upload-pack=       path to git-upload-pack on the remote
depth=               create a shallow clone of that depth

use-separate-remote  compatibility, do not use
no-separate-remote   compatibility, do not use"

die() {
	echo >&2 "$@"
	exit 1
}

usage() {
	exec "$0" -h
}

eval "$(echo "$OPTIONS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)"

get_repo_base() {
	(
		cd "`/bin/pwd`" &&
		cd "$1" || cd "$1.git" &&
		{
			cd .git
			pwd
		}
	) 2>/dev/null
}

if [ -n "$GIT_SSL_NO_VERIFY" -o \
	"`git config --bool http.sslVerify`" = false ]; then
    curl_extra_args="-k"
fi

http_fetch () {
	# $1 = Remote, $2 = Local
	curl -nsfL $curl_extra_args "$1" >"$2" ||
		case $? in
		126|127) exit ;;
		*)	 return $? ;;
		esac
}

clone_dumb_http () {
	# $1 - remote, $2 - local
	cd "$2" &&
	clone_tmp="$GIT_DIR/clone-tmp" &&
	mkdir -p "$clone_tmp" || exit 1
	if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
		"`git config --bool http.noEPSV`" = true ]; then
		curl_extra_args="${curl_extra_args} --disable-epsv"
	fi
	http_fetch "$1/info/refs" "$clone_tmp/refs" ||
		die "Cannot get remote repository information.
Perhaps git-update-server-info needs to be run there?"
	test "z$quiet" = z && v=-v || v=
	while read sha1 refname
	do
		name=`expr "z$refname" : 'zrefs/\(.*\)'` &&
		case "$name" in
		*^*)	continue;;
		esac
		case "$bare,$name" in
		yes,* | ,heads/* | ,tags/*) ;;
		*)	continue ;;
		esac
		if test -n "$use_separate_remote" &&
		   branch_name=`expr "z$name" : 'zheads/\(.*\)'`
		then
			tname="remotes/$origin/$branch_name"
		else
			tname=$name
		fi
		git-http-fetch $v -a -w "$tname" "$sha1" "$1" || exit 1
	done <"$clone_tmp/refs"
	rm -fr "$clone_tmp"
	http_fetch "$1/HEAD" "$GIT_DIR/REMOTE_HEAD" ||
	rm -f "$GIT_DIR/REMOTE_HEAD"
	if test -f "$GIT_DIR/REMOTE_HEAD"; then
		head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
		case "$head_sha1" in
		'ref: refs/'*)
			;;
		*)
			git-http-fetch $v -a "$head_sha1" "$1" ||
			rm -f "$GIT_DIR/REMOTE_HEAD"
			;;
		esac
	fi
}

quiet=
local=no
use_local_hardlink=yes
local_shared=no
unset template
no_checkout=
upload_pack=
bare=
reference=
origin=
origin_override=
use_separate_remote=t
depth=
no_progress=
local_explicitly_asked_for=
test -t 1 || no_progress=--no-progress

while test $# != 0
do
	case "$1" in
	-n|--no-checkout)
		no_checkout=yes ;;
	--naked|--bare)
		bare=yes ;;
	-l|--local)
		local_explicitly_asked_for=yes
		use_local_hardlink=yes
		;;
	--no-hardlinks)
		use_local_hardlink=no ;;
	-s|--shared)
		local_shared=yes ;;
	--template)
		shift; template="--template=$1" ;;
	-q|--quiet)
		quiet=-q ;;
	--use-separate-remote|--no-separate-remote)
		die "clones are always made with separate-remote layout" ;;
	--reference)
		shift; reference="$1" ;;
	-o,--origin)
		shift;
		case "$1" in
		'')
		    usage ;;
		*/*)
		    die "'$1' is not suitable for an origin name"
		esac
		git check-ref-format "heads/$1" ||
		    die "'$1' is not suitable for a branch name"
		test -z "$origin_override" ||
		    die "Do not give more than one --origin options."
		origin_override=yes
		origin="$1"
		;;
	-u|--upload-pack)
		shift
		upload_pack="--upload-pack=$1" ;;
	--depth)
		shift
		depth="--depth=$1" ;;
	--)
		shift
		break ;;
	*)
		usage ;;
	esac
	shift
done

repo="$1"
test -n "$repo" ||
    die 'you must specify a repository to clone.'

# --bare implies --no-checkout and --no-separate-remote
if test yes = "$bare"
then
	if test yes = "$origin_override"
	then
		die '--bare and --origin $origin options are incompatible.'
	fi
	no_checkout=yes
	use_separate_remote=
fi

if test -z "$origin"
then
	origin=origin
fi

# Turn the source into an absolute path if
# it is local
if base=$(get_repo_base "$repo"); then
	repo="$base"
	local=yes
fi

dir="$2"
# Try using "humanish" part of source repo if user didn't specify one
[ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*[/:]||g')
[ -e "$dir" ] && die "destination directory '$dir' already exists."
[ yes = "$bare" ] && unset GIT_WORK_TREE
[ -n "$GIT_WORK_TREE" ] && [ -e "$GIT_WORK_TREE" ] &&
die "working tree '$GIT_WORK_TREE' already exists."
D=
W=
cleanup() {
	err=$?
	test -z "$D" && rm -rf "$dir"
	test -z "$W" && test -n "$GIT_WORK_TREE" && rm -rf "$GIT_WORK_TREE"
	cd ..
	test -n "$D" && rm -rf "$D"
	test -n "$W" && rm -rf "$W"
	exit $err
}
trap cleanup 0
mkdir -p "$dir" && D=$(cd "$dir" && pwd) || usage
test -n "$GIT_WORK_TREE" && mkdir -p "$GIT_WORK_TREE" &&
W=$(cd "$GIT_WORK_TREE" && pwd) && GIT_WORK_TREE="$W" && export GIT_WORK_TREE
if test yes = "$bare" || test -n "$GIT_WORK_TREE"; then
	GIT_DIR="$D"
else
	GIT_DIR="$D/.git"
fi &&
export GIT_DIR &&
GIT_CONFIG="$GIT_DIR/config" git-init $quiet ${template+"$template"} || usage

if test -n "$bare"
then
	GIT_CONFIG="$GIT_DIR/config" git config core.bare true
fi

if test -n "$reference"
then
	ref_git=
	if test -d "$reference"
	then
		if test -d "$reference/.git/objects"
		then
			ref_git="$reference/.git"
		elif test -d "$reference/objects"
		then
			ref_git="$reference"
		fi
	fi
	if test -n "$ref_git"
	then
		ref_git=$(cd "$ref_git" && pwd)
		echo "$ref_git/objects" >"$GIT_DIR/objects/info/alternates"
		(
			GIT_DIR="$ref_git" git for-each-ref \
				--format='%(objectname) %(*objectname)'
		) |
		while read a b
		do
			test -z "$a" ||
			git update-ref "refs/reference-tmp/$a" "$a"
			test -z "$b" ||
			git update-ref "refs/reference-tmp/$b" "$b"
		done
	else
		die "reference repository '$reference' is not a local directory."
	fi
fi

rm -f "$GIT_DIR/CLONE_HEAD"

# We do local magic only when the user tells us to.
case "$local" in
yes)
	( cd "$repo/objects" ) ||
		die "cannot chdir to local '$repo/objects'."

	if test "$local_shared" = yes
	then
		mkdir -p "$GIT_DIR/objects/info"
		echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates"
	else
		l= &&
		if test "$use_local_hardlink" = yes
		then
			# See if we can hardlink and drop "l" if not.
			sample_file=$(cd "$repo" && \
				      find objects -type f -print | sed -e 1q)
			# objects directory should not be empty because
			# we are cloning!
			test -f "$repo/$sample_file" || exit
			if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
			then
				rm -f "$GIT_DIR/objects/sample"
				l=l
			elif test -n "$local_explicitly_asked_for"
			then
				echo >&2 "Warning: -l asked but cannot hardlink to $repo"
			fi
		fi &&
		cd "$repo" &&
		find objects -depth -print | cpio -pumd$l "$GIT_DIR/" || exit 1
	fi
	git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
	;;
*)
	case "$repo" in
	rsync://*)
		case "$depth" in
		"") ;;
		*) die "shallow over rsync not supported" ;;
		esac
		rsync $quiet -av --ignore-existing  \
			--exclude info "$repo/objects/" "$GIT_DIR/objects/" ||
		exit
		# Look at objects/info/alternates for rsync -- http will
		# support it natively and git native ones will do it on the
		# remote end.  Not having that file is not a crime.
		rsync -q "$repo/objects/info/alternates" \
			"$GIT_DIR/TMP_ALT" 2>/dev/null ||
			rm -f "$GIT_DIR/TMP_ALT"
		if test -f "$GIT_DIR/TMP_ALT"
		then
		    ( cd "$D" &&
		      . git-parse-remote &&
		      resolve_alternates "$repo" <"$GIT_DIR/TMP_ALT" ) |
		    while read alt
		    do
			case "$alt" in 'bad alternate: '*) die "$alt";; esac
			case "$quiet" in
			'')	echo >&2 "Getting alternate: $alt" ;;
			esac
			rsync $quiet -av --ignore-existing  \
			    --exclude info "$alt" "$GIT_DIR/objects" || exit
		    done
		    rm -f "$GIT_DIR/TMP_ALT"
		fi
		git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1
		;;
	https://*|http://*|ftp://*)
		case "$depth" in
		"") ;;
		*) die "shallow over http or ftp not supported" ;;
		esac
		if test -z "@@NO_CURL@@"
		then
			clone_dumb_http "$repo" "$D"
		else
			die "http transport not supported, rebuild Git with curl support"
		fi
		;;
	*)
		case "$upload_pack" in
		'') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";;
		*) git-fetch-pack --all -k $quiet "$upload_pack" $depth $no_progress "$repo" ;;
		esac >"$GIT_DIR/CLONE_HEAD" ||
			die "fetch-pack from '$repo' failed."
		;;
	esac
	;;
esac
test -d "$GIT_DIR/refs/reference-tmp" && rm -fr "$GIT_DIR/refs/reference-tmp"

if test -f "$GIT_DIR/CLONE_HEAD"
then
	# Read git-fetch-pack -k output and store the remote branches.
	if [ -n "$use_separate_remote" ]
	then
		branch_top="remotes/$origin"
	else
		branch_top="heads"
	fi
	tag_top="tags"
	while read sha1 name
	do
		case "$name" in
		*'^{}')
			continue ;;
		HEAD)
			destname="REMOTE_HEAD" ;;
		refs/heads/*)
			destname="refs/$branch_top/${name#refs/heads/}" ;;
		refs/tags/*)
			destname="refs/$tag_top/${name#refs/tags/}" ;;
		*)
			continue ;;
		esac
		git update-ref -m "clone: from $repo" "$destname" "$sha1" ""
	done < "$GIT_DIR/CLONE_HEAD"
fi

if test -n "$W"; then
	cd "$W" || exit
else
	cd "$D" || exit
fi

if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD"
then
	# a non-bare repository is always in separate-remote layout
	remote_top="refs/remotes/$origin"
	head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"`
	case "$head_sha1" in
	'ref: refs/'*)
		# Uh-oh, the remote told us (http transport done against
		# new style repository with a symref HEAD).
		# Ideally we should skip the guesswork but for now
		# opt for minimum change.
		head_sha1=`expr "z$head_sha1" : 'zref: refs/heads/\(.*\)'`
		head_sha1=`cat "$GIT_DIR/$remote_top/$head_sha1"`
		;;
	esac

	# The name under $remote_top the remote HEAD seems to point at.
	head_points_at=$(
		(
			test -f "$GIT_DIR/$remote_top/master" && echo "master"
			cd "$GIT_DIR/$remote_top" &&
			find . -type f -print | sed -e 's/^\.\///'
		) | (
		done=f
		while read name
		do
			test t = $done && continue
			branch_tip=`cat "$GIT_DIR/$remote_top/$name"`
			if test "$head_sha1" = "$branch_tip"
			then
				echo "$name"
				done=t
			fi
		done
		)
	)

	# Upstream URL
	git config remote."$origin".url "$repo" &&

	# Set up the mappings to track the remote branches.
	git config remote."$origin".fetch \
		"+refs/heads/*:$remote_top/*" '^$' &&

	# Write out remote.$origin config, and update our "$head_points_at".
	case "$head_points_at" in
	?*)
		# Local default branch
		git symbolic-ref HEAD "refs/heads/$head_points_at" &&

		# Tracking branch for the primary branch at the remote.
		git update-ref HEAD "$head_sha1" &&

		rm -f "refs/remotes/$origin/HEAD"
		git symbolic-ref "refs/remotes/$origin/HEAD" \
			"refs/remotes/$origin/$head_points_at" &&

		git config branch."$head_points_at".remote "$origin" &&
		git config branch."$head_points_at".merge "refs/heads/$head_points_at"
		;;
	'')
		# Source had detached HEAD pointing nowhere
		git update-ref --no-deref HEAD "$head_sha1" &&
		rm -f "refs/remotes/$origin/HEAD"
		;;
	esac

	case "$no_checkout" in
	'')
		test "z$quiet" = z -a "z$no_progress" = z && v=-v || v=
		git read-tree -m -u $v HEAD HEAD
	esac
fi
rm -f "$GIT_DIR/CLONE_HEAD" "$GIT_DIR/REMOTE_HEAD"

trap - 0
back to top