#!/bin/sh
#
# Author: Matthieu Prat <matthieuprat@gmail.com>
# Date: 01/22/2015
#
# Sync a local work tree with a remote one.
# It's rsync on steroids within large Git repositories.
USAGE='<repository>'
LONG_USAGE='Sync a local work tree with a remote one.'
SUBDIRECTORY_OK=No
OPTIONS_SPEC=
. "$(git --exec-path)/git-sh-setup"
require_work_tree
cd_to_toplevel
[ $# -eq 0 ] || [ $# -gt 1 ] && {
usage
}
head=$(git rev-parse HEAD)
remote=$(git ls-remote --get-url $1) # e.g. git.example.org:path/to/repository
remote_host=${remote%:*} # git.example.org
remote_repo=${remote##*:} # path/to/repository
remote_exec () {
ssh -T -A $remote_host "cd $remote_repo && $*"
}
{
# Push the local HEAD to the remote (if need be).
if ! remote_exec git rev-parse --verify --quiet $head^{commit}
then
git push --quiet --force $remote $head:refs/heads/rsync/HEAD &&
remote_exec rm '$(git rev-parse --git-dir)'/refs/heads/rsync/HEAD
fi || die "Failed to push local HEAD to the remote." &&
# Checkout the local HEAD on the remote end and clean untracked files.
remote_exec "
git checkout --quiet -f $head &&
git clean -df
" || die "Unable to checkout local HEAD on the remote." &&
# Apply local changes (if any) to the remote work tree.
if ! git diff-index --quiet --ignore-submodules HEAD
then
git diff-index --unified=0 --binary --ignore-submodules $head |
remote_exec git apply --unidiff-zero --whitespace=nowarn -
fi || die "Could not apply local changes on the remote." &&
# Fallback to rsync for untracked files.
git ls-files --others --exclude-standard -z |
rsync --files-from=- -0 --no-dirs --whole-file . dev:dailymotion \
|| die "Failed to push untracked files."
} > /dev/null && echo "Success."