git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Santi Béjar" <santi@agolina.net>
To: "Johannes Sixt" <j.sixt@viscovery.net>
Cc: "Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
	"git list" <git@vger.kernel.org>
Subject: Re: git-bpush: Pushing to a bundle
Date: Tue, 9 Dec 2008 15:58:20 +0100	[thread overview]
Message-ID: <adf1fd3d0812090658q14001019re8977b912386c256@mail.gmail.com> (raw)
In-Reply-To: <493E545B.6010609@viscovery.net>

[-- Attachment #1: Type: text/plain, Size: 5667 bytes --]

2008/12/9 Johannes Sixt <j.sixt@viscovery.net>:
> 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

[-- Attachment #2: git-bpush --]
[-- Type: application/octet-stream, Size: 4493 bytes --]

#!/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

  parent reply	other threads:[~2008-12-09 14:59 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-12-09  9:49 git-bpush: Pushing to a bundle Santi Béjar
2008-12-09 10:07 ` Johannes Schindelin
2008-12-09 10:21   ` Santi Béjar
     [not found]     ` <493E545B.6010609@viscovery.net>
2008-12-09 14:58       ` Santi Béjar [this message]
2008-12-09 17:32     ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=adf1fd3d0812090658q14001019re8977b912386c256@mail.gmail.com \
    --to=santi@agolina.net \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=git@vger.kernel.org \
    --cc=j.sixt@viscovery.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).