git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: git-bpush: Pushing to a bundle

From
SBSanti Béjar <santi@agolina.net>
Date
Dec 9, 2008, 14:58 UTC
Message-ID
<adf1fd3d0812090658q14001019re8977b912386c256@mail.gmail.com>
In-Reply-To
<493E545B.6010609@viscovery.net>
2008/12/9 Johannes Sixt <j.sixt@viscovery.net>:
Show 13 quoted lines
> Santi Béjar schrieb:
>> 2008/12/9 Johannes Schindelin <Johannes.Schindelin@gmx.de>:
>>> On Tue, 9 Dec 2008, Santi Béjar wrote:
>>>> while [ $# != 0 ] ; do
>>>>     refs="$refs$LF$1" && shift
>>>> done
>>> That is equivalent to refs="$*", no?
>>
>> Almost, IFS is set to line-feed so I needed to put $LF instead of spaces.
>
> But "$*" inserts the first character of IFS (not necessarily spaces), and
> since your IFS *is* $LF, "$*" should do what you want.
>
Oh, you are right.
> Anyway, I found reading your shell script quite hard, because of excessive
> use of brackets and single line && chains (which lack proper error
> handling, BTW).

I've changed the script to follow the Git's conventions (at least I've tried), a few more error handling and some simplification. BTW, what do you find hard with single line && chains?

I do not sent a diff because it is almost as big as the script itself. #!/bin/sh

OPTIONS_KEEPDASHDASH= OPTIONS_SPEC="\ git bpush [options] [<remote> [<refs>...]] -- f,force force updates full create a full bundle v be verbose " SUBDIRECTORY_OK=Yes . git-sh-setup . git-parse-remote

cd_to_toplevel

LF=' ' IFS="$LF"

bases=
bbases=
changed=
force=
nonff=
remote=
refs=
while :
do
	case "$1" in
	-v)
		verbose=t ;;
	--full)
		full=t ;;
	-f|--force)
		force=t ;;
	--)
		shift
		break ;;
	*)
		usage ;;
	esac
	shift
done

test -n "$1" && remote=$1 && shift refs="$*"

test -z "$remote" && remote=$(get_default_remote) remoteurl=$(git config remote.${remote}.url) test -z "$remoteurl" && remoteurl=$remote test -d "$remoteurl" && die "$remoteurl is a directory"

# Default bases in bundle.base
# Default {refs,base} can be specified in remote.<remote>.{push,bundlebase}
if test "$remote" != "$remoteurl"
then
	test -z "$refs" &&
	refs=$(git config --get-all remote.${remote}.push)
	bases=$(git config --get-all remote.${remote}.bundlebase ||
		git config --get-all bundle.base)
else
	bases=$(git config --get-all bundle.base)
fi
# git rev-parse --symbolic-full-name resolves symlinks
# Keep at least HEAD
head=
for ref in $refs ; do
	test "$ref" = HEAD && head=t && break
done
test -n "$bases" && bases=$(git rev-parse --revs-only $bases | sort -u)

# Full symbolic refs need to be uniq test -n "$refs" && refs=$(git-rev-parse --symbolic-full-name --revs-only $refs | sort -u)

test -n "$head" && refs="HEAD$LF$refs"
if test -e "$remoteurl"
then
	blines=$(git bundle verify "$remoteurl" 2>/dev/null) ||
	die "Verification of \"$remoteurl\" failed"
	# Find the bundle's bases
	refs="$refs$LF$(git bundle list-heads $remoteurl | cut -d " " -f 2)"
	requires=
	for line in $blines
	do
		case "$requires,$line" in
		",The bundle requires"*)
			requires=t ;;
		t,) ;;
		t,*)
			bbase=$(echo $line | cut -d " " -f 1)
			bbases="$bbases$LF$bbase"
			;;
		esac
	done
	bases="$bases$LF$bbases"
elif test -z "$refs" ; then
	# Push current branch
	refs="HEAD$LF$(git symbolic-ref -q HEAD)"
fi
test -z "$refs" && die "No refs to push"
refs=$(echo "$refs" | sort -u)
for ref in $bases $refs
do
	test "$(git cat-file -t $ref^{})" != commit &&
	die "$(basename $0): $ref is not a commit"
done

header="To $remoteurl" test -n "$verbose" && echo "Pushing to $remoteurl" && echo $header && header=

# Find what is/is not a fast-forward, up to date or new
# As "git bundle" does not support refspecs we must push all matching branches
for ref in $refs ; do
	text=
	bchanged=
	case $ref in
	refs/tags/*)
		bshort=$(echo $ref | sed -e "s|^refs/tags/||")
		newtext="new tag";;
	refs/heads/*|HEAD)
		bshort=$(echo $ref | sed -e "s|^refs/heads/||")
		newtext="new branch" ;;
	esac
	newhash=$(git rev-parse $ref) || die "Ref $ref not valid"
	newshort=$(git rev-parse --short $ref)
	bheads=
	test -e "$remoteurl" && bheads="$(git bundle list-heads $remoteurl)"
	for bhead in $bheads
	do
		bhash=$(echo $bhead | cut -d " " -f 1)
		bref=$(echo $bhead | cut -d " " -f 2)
		# Find the matching ref in the bundle
		test "$bref" != "$ref" && continue
		oldshort=$(git rev-parse --short $bhash)
		mergebase=
		case $ref in
		refs/tags/*)
			# Only test if it is different
			mergebase=$newhash;;
		refs/heads/*|HEAD)
			mergebase=$(git merge-base $bref $bhash);;
		esac
		case $newhash,$bhash,$mergebase,$force in
		$bhash,$newhash,*)
			# No changes
			text=" = [up to date] $bshort -> $bshort"
			;;
		*,*,$bhash,*)
			# Fast-forward
			bchanged=t
			text="   $oldshort..$newshort $bshort -> $bshort"
			;;
		*,t)
			# Forced non fast-forward
			bchanged=t
			text=" + $oldshort...$newshort $bshort -> $bshort (forced update)"
			;;
		*)
			bchanged=t
			nonff=t
			text=" ! [rejected] $bshort -> $bshort (non-fast forward)"
		esac
		break
	done
	test -z "$text" && text=" * [$newtext] $bshort -> $bshort" && bchanged=t
	if test -n "$bchanged" || test -n "$verbose"
	then
		test -n "$header" && echo $header && header=
		echo $text
	fi
	test -n "$bchanged" && changed=t
done

# Recreate the bundle if --full and the current bundle is not full test -n "$full" && bases= && test -n "$bbases" && changed=t

test -n "$nonff" && die "error: failed to push some refs to $remoteurl" test -z "$changed" && die "Everything up-to-date" test -n "$bases" && bases="--not$LF$bases"

git bundle create $remoteurl $refs $bases || die "Cannot create bundle \"$remoteurl\""

test "$remote" != "$remoteurl" && { git fetch -q "$remote" ||
	die "Error fetch from bundle \"$remoteurl\"" ; }
exit 0
Previous: Junio C Hamano
Message 5 of 5 in “git-bpush: Pushing to a bundle”
  1. Santi BéjarDec 9, 2008
  2. Johannes SchindelinDec 9, 2008
  3. Santi BéjarDec 9, 2008
  4. Junio C HamanoDec 9, 2008
  5. Santi BéjarDec 9, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.