#!/usr/bin/env bash # # Push changes to a remote GIT repository. # Copyright (c) Petr Baudis, 2005. # # It will push your commits on the current branch (or as specified by # the -r option) to the remote repository, provided that your commits # follow the last commit in the remote repository. # # Note that if the remote repository is associated with a working # tree copy, this command won't update that. Use cg-reset at the # remote side to bring it in sync (but throw away any local changes # in that tree). Consider setting up a standalone repository (see # `cg-admin-setuprepo`). # # Takes the branch name as an argument, defaulting to "origin". # # OPTIONS # ------- # -r BRANCH:: Push the given branch # Pushes the given branch instead of the current one. Note that # we lie a little here and you can actually specify a particular # commit here, but you probably will not want to do that. # # -t TAG:: Push the given TAG # Tells cg-push to also push the given tag. Note that in the # future, cg-push should push tags automatically. Also note # that even if you pass `cg-push` the '-t' arguments, your # HEAD is still pushed as well in addition to the tags. USAGE="cg-push [-r LOCAL_BRANCH] [REMOTE_BRANCH] [-t TAG]..." . "${COGITO_LIB}"cg-Xlib || exit 1 send_pack_update() { name="$1"; shift commit="$(cg-object-id -c "$locbranch")"; old="$(cat "$_git/refs/heads/$name" 2>/dev/null)" git-send-pack "$@" && git-update-ref refs/heads/"$name" "$commit" $old } locbranch="$_git_head" tags=() while optparse; do if optparse -r=; then locbranch="$OPTARG" [ "$(cg-object-id -c "$locbranch")" ] || exit 1 elif optparse -t=; then tags[${#tags[@]}]="refs/tags/$OPTARG" else optfail fi done [ ${#ARGS[@]} -gt 1 ] && die "too many arguments, I can push only one branch at once" name="${ARGS[0]}" [ "$name" ] || { [ -s "$_git/branches/origin" ] && name=origin; } [ "$name" ] || die "where to push to?" uri="$(cat "$_git/branches/$name" 2>/dev/null)" || die "unknown branch: $name" rembranch=master if echo "$uri" | grep -q '#'; then rembranch="$(echo "$uri" | cut -d '#' -f 2)" uri="$(echo "$uri" | cut -d '#' -f 1)" fi sprembranch=":refs/heads/$rembranch" if [ "${uri#http://}" != "$uri" -o "${uri#https://}" != "$uri" ]; then # git-http-push doesn't like $sprembranch git-http-push "$uri/" "$locbranch:$rembranch" "${tags[@]}" elif [ "${uri#git+ssh://}" != "$uri" ]; then send_pack_update "$name" "$(echo "$uri" | sed 's#^git+ssh://\([^/]*\)\(/.*\)$#\1:\2#')" "$locbranch$sprembranch" "${tags[@]}" elif [ "${uri#rsync://}" != "$uri" ]; then die "pushing over rsync not supported" elif [ "${uri#*:}" != "$uri" ]; then echo "WARNING: I guessed the host:path syntax was used and fell back to the git+ssh protocol." echo "WARNING: The host:path syntax is evil because it is implicit. Please just use a URI." send_pack_update "$name" "$uri" "$locbranch$sprembranch" "${tags[@]}" else remgit="$uri"; [ -d "$remgit/.git" ] && remgit="$remgit/.git" if is_same_repo "$_git_objects" "$remgit/objects"; then commit="$(cg-object-id -c "$locbranch")" remid="$(cat "$remgit"/refs/heads/$rembranch)" || die "$remgit: no branch $master" if [ "$remid" = "$commit" ] && [ ! "${tags[*]}" ]; then echo "$remgit#$rembranch: Already up-to-date." >&2 exit 0 fi if [ "$remid" != "$(git-merge-base "$remid" "$commit")" ]; then echo "ERROR: Remote '$rembranch' has some changes you don't have in your '$locbranch'" >&2 echo "Try to cg-update from it first, then push." >&2 exit 1 fi echo "Pushing $commit to $remgit#$rembranch" >&2 [ -x "$remgit/hooks/update" ] && "$remgit/hooks/update" "$rembranch" "$remid" "$commit" GIT_DIR="$remgit" git-update-ref refs/heads/"$rembranch" "$commit" "$remid" || die "push failed" git-update-ref refs/heads/"$name" "$commit" for tag in "${tags[@]}"; do GIT_DIR="$remgit" git-update-ref refs/tags/"$tag" "$(cat "$_git/refs/tags/$tag")" done [ -x "$remgit/hooks/post-update" ] && "$remgit/hooks/post-update" "$rembranch" else send_pack_update "$name" "$uri" "$locbranch$sprembranch" "${tags[@]}" fi fi