#!/bin/bash # # Usage: gsync [rsync-options] source destination # # Synchronize a git source directory with a remote directory, excluding files according to then # rules found in .gitignore. If subdirectories also contain .gitignore files, then those rules # will be applied (but only in each respective subdirectory). # # Note that ONLY .gitignore files in the directory where this command is run from will be considered # Thus, when the source or destination is a local path, it should be specified relative to the current # directory. # # There will be two rsync statements - one to exclude everything that should be excluded, # and a second to handle the exceptions to the exclusion rules - the lines in .gitignore that begin with ! # # The exceptions to the exclusions are rsync'd first, and if that succeeds, the second rsync # copies everything else. # # # --- SUPPORT OPEN SOURCE --- # If you find this script has saved you a decent amount time, please consider dropping me some coin. # I will be forever grateful and your name will be permanently emblazoned on my Wall of Honor. # My bitcoin wallet address is 1HoiSHKxYM4EtsP3xFGsY2xWYvh4hAuJ2q # Paypal or Dwolla: jonathan (replace this with the 'AT' sign on your keyboard) kyuss.org # # Thank You. # # - jonathan. # if [[ -z "${1}" || -z "${2}" || "${1}" == "--help" || "${1}" == "-help" || "${1}" == "-h" ]] ; then echo "Usage: gsync [rsync-options] source destination" exit 1 fi includes="" excludes='--exclude=.git*' base="$(pwd)" function process_git_ignore () { git_ignore="${1}" if [ "$(dirname ${git_ignore})" = "${base}" ] ; then prefix="" else prefix=".$(echo -n "$(dirname ${git_ignore})" | sed -e 's,^'${base}',,')" fi while read -r line || [[ -n "${line}" ]] ; do # todo: there is probably a cleaner test for "first char == !" if [ $(echo "${line}" | head -c 1 | grep -- '!' | wc -l) -gt 0 ] ; then includes="${includes} --include='${prefix}$(echo "${line}" | sed -e 's/^!//' | sed -e 's/ /\\ /g')'" else excludes="${excludes} --exclude='${prefix}$(echo "${line}" | sed -e 's/ /\\ /g')'" fi done < ${git_ignore} } # root .gitignore file if [ -f .gitignore ] ; then process_git_ignore "$(pwd)/.gitignore" fi # check for other .gitignore files for i in $(find $(pwd) -mindepth 2 -type f -name .gitignore) ; do process_git_ignore "${i}" done rsync ${includes} --exclude="*" ${@} && rsync ${excludes} ${@} # for debugging #echo "rsync ${includes} --exclude=\"*\" ${@}" && echo "rsync ${excludes} ${@}" #echo "rsync ${excludes} ${@}"