#!/bin/sh # # Pushes changes from the local git repo to remote repo. # # Copyright (C) 2005 Tony Lindgren # # Some parts based on an earlier push script, # Copyright (C) 2005 Matthias Urlichs. # # Takes the remote repo's name or url as parameter. # # Most likely the remote repo is not rsync writable, but # you can use rsync over ssh for the push. # # When using rsync over ssh, you must use the real repo # path on the server and an ssh key to avoid typing in # the password multiple times. For example: # # $ export RSYNC_FLAGS="-z --progress" # $ export RSYNC_RSH="ssh -i /home/user/.ssh/my-git-key" # $ cg-rpush some.machine:/home/git/repo # . ${COGITO_LIB}cg-Xlib name=$1 BRANCHES=".git/branches" HEADS=".git/refs/heads" OBJECTS=".git/objects" LOCKS=".git/locks" REMOTE_LOCK="write_lock" TMP="/tmp" uri="" function usage () { echo "Usage: [RSYNC_FLAGS=\"-e ssh\"] $0 some.machine:/home/git/repo" exit 1 } function die () { if [ -f $LOCKS/$REMOTE_LOCK ]; then rm -f $LOCKS/$REMOTE_LOCK fi echo cg-rpush: $@ >&2 exit 1 } function clean_locks () { rm -f $LOCKS/$REMOTE_LOCK rsync $RSYNC_FLAGS -r --delete $LOCKS/ $uri/$LOCKS } function validate_input () { [ "$name" ] || usage if [ ! -d ".git" ]; then die "Could not find local .git directory" fi uri=$(cat $BRANCHES/$name 2>/dev/null) [ "$uri" ] || uri=$name echo $uri } # # We must use a lock directory to allow removing the remote lock # files with rsync by copying over it with an empty directory. # Creating the remote lock file should be safe. However, please note # that we must also be careful not to remove local .git/locks/write_lock # in case somebody is pushing to our local repo from a remote machine. # Currently the local lock file creation can conflict with a lock # file creation from a remote machine to our local machine. # function lock_files () { echo "Attempting to to create a write lock on remote..." if [ ! -d $LOCKS ]; then mkdir $LOCKS; fi if [ -f $LOCKS/$REMOTE_LOCK ]; then echo "Local write_lock already exists: $LOCKS/$REMOTE_LOCK" exit 1 fi lock_stamp="$USER@$HOSTNAME $(date)" echo $lock_stamp > $LOCKS/$REMOTE_LOCK rsync $RSYNC_FLAGS -r --ignore-existing $LOCKS/ $uri/$LOCKS # Check what the remote .git/locks/write_lock has tmpfile=$TMP/remote_lock_$RANDOM rsync $RSYNC_FLAGS "$uri/$LOCKS/$REMOTE_LOCK" $tmpfile remote_stamp=$(cat $tmpfile) rm -f $tmpfile if [ "$remote_stamp" != "$lock_stamp" ]; then die "Remote locked by $remote_stamp, please try again later" fi } function check_remote_version () { echo "Getting remote version..." tmpfile=$TMP/remote_head_$RANDOM rsync $RSYNC_FLAGS -Lr "$uri/$HEADS/master" $tmpfile remote_head=$(cat $tmpfile) rm -f $tmpfile if [ -z "$remote_head" ]; then clean_locks die "Remote repository does not have $uri/$HEADS/master" fi echo "Remote head is at: $remote_head" if [ "$(git-cat-file -t "$remote_head" 2>/dev/null)" != "commit" ]; then clean_locks die "Remote is ahead, please do a pull first" fi } function push_git_objects () { echo "Pushing .git/objects..." rsync $RSYNC_FLAGS --ignore-existing --whole-file -v -r \ "$OBJECTS/" "$uri/$OBJECTS/" } function update_remote_head () { local_head=$(cat $HEADS/master) echo "Updating remote head to: $local_head" rsync $RSYNC_FLAGS -Lr $HEADS/master "$uri/$HEADS/master" } function print_note () { echo "Remote updated successfully" echo "NOTE: Not updating checked out remote files in case they" echo "have been edited locally on the remote machine." echo "To sync checked out files on remote, you can run cg-cancel" echo "on remote machine. You can check for uncommitted changes" echo "on remote with cg-diff first, which should only show" echo "changes done in this push." } # # Main program # uri=$(validate_input) lock_files check_remote_version push_git_objects update_remote_head clean_locks print_note exit