Re: git-bpush: Pushing to a bundle
- From
- Santi 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"
doneheader="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