2
0
mirror of https://github.com/gitwatch/gitwatch synced 2024-11-15 06:12:52 +00:00
gitwatch/gitwatch.sh

158 lines
6.9 KiB
Bash
Raw Normal View History

2012-12-02 22:26:02 +00:00
#!/usr/bin/env bash
#
# gitwatch - watch file or directory and git commit all changes as they happen
#
# Copyright (C) 2013 Patrick Lehner
# with modifications and contributions by:
# - Matthew McGowan
# - Dominik D. Geyer
#
#############################################################################
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#############################################################################
#
# Idea and original code taken from http://stackoverflow.com/a/965274
# (but heavily modified by now)
#
# Requires the command 'inotifywait' to be available, which is part of
# the inotify-tools (See https://github.com/rvoicilas/inotify-tools ),
# and (obviously) git
#
2012-11-28 00:02:11 +00:00
REMOTE=""
BRANCH=""
SLEEP_TIME=2
DATE_FMT="+%Y-%m-%d %H:%M:%S"
COMMITMSG="Scripted auto-commit on change (%d) by gitwatch.sh"
2012-11-28 00:02:11 +00:00
shelp () { # Print a message about how to use this script
echo "gitwatch - watch file or directory and git commit all changes as they happen"
echo ""
echo "Usage:"
echo "${0##*/} [-s <secs>] [-d <fmt>] [-r <remote> [-b <branch>]]"
echo " [-m <msg>] <target>"
echo ""
echo "Where <target> is the file or folder which should be watched. The target needs"
echo "to be in a Git repository, or in the case of a folder, it may also be the top"
echo "folder of the repo."
echo ""
echo " -s <secs> after detecting a change to the watched file or directory,"
echo " wait <secs> seconds until committing, to allow for more"
echo " write actions of the same batch to finish; default is 2sec"
echo " -d <fmt> the format string used for the timestamp in the commit"
echo " message; see 'man date' for details; default is "
echo " \"+%Y-%m-%d %H:%M:%S\""
echo " -r <remote> if defined, a 'git push' to the given <remote> is done after"
echo " every commit"
echo " -b <branch> the branch which should be pushed automatically;"
echo " - if not given, the push command used is 'git push <remote>',"
echo " thus doing a default push (see git man pages for details)"
echo " - if given and"
echo " + repo is in a detached HEAD state (at launch)"
echo " then the command used is 'git push <remote> <branch>'"
echo " + repo is NOT in a detached HEAD state (at launch)"
echo " then the command used is"
echo " 'git push <remote> <current branch>:<branch>' where"
echo " <current branch> is the target of HEAD (at launch)"
echo " if no remote was define with -r, this option has no effect"
echo " -m <msg> the commit message used for each commit; all occurences of"
echo " %d in the string will be replaced by the formatted date/time"
echo " (unless the <fmt> specified by -d is empty, in which case %d"
echo " is replaced by an empty string); the default message is:"
echo " \"Scripted auto-commit on change (%d) by gitwatch.sh\""
echo ""
echo "As indicated, several conditions are only checked once at launch of the"
echo "script. You can make changes to the repo state and configurations even while"
echo "the script is running, but that may lead to undefined and unpredictable (even"
echo "destructive) behavior!"
echo "It is therefore recommended to terminate the script before changin the repo's"
echo "config and restarting it afterwards."
}
while getopts b:d:hm:p:r:s: option # Process command line options
2012-11-28 00:02:11 +00:00
do
case "${option}" in
b) BRANCH=${OPTARG};;
d) DATE_FMT=${OPTARG};;
h) shelp; exit;;
m) COMMITMSG=${OPTARG};;
p|r) REMOTE=${OPTARG};;
s) SLEEP_TIME=${OPTARG};;
2012-11-28 00:02:11 +00:00
esac
done
2012-11-28 00:02:11 +00:00
shift $((OPTIND-1)) # Shift the input arguments, so that the input file (last arg) is $1 in the code below
if [ $# -ne 1 ]; then # If no command line arguments are left (that's bad: no target was passed)
shelp # print usage help
exit # and exit
fi
is_command () { # Tests for the availability of a command
which $1 &>/dev/null
}
# Check dependencies and die if not met
for cmd in git inotifywait; do
is_command $cmd || { echo "Error: Required command '$cmd' not found." >&2; exit 1; }
done
unset cmd
2012-11-27 09:04:20 +00:00
IN=$(readlink -f "$1")
if [ -d $1 ]; then
TARGETDIR=$(sed -e "s/\/*$//" <<<"$IN") # dir to CD into before using git commands: trim trailing slash, if any
INCOMMAND="inotifywait --exclude=\"^${TARGETDIR}/.git\" -qqr -e close_write,move,delete,create $TARGETDIR" # construct inotifywait-commandline
GITADD="." # add "." (CWD) recursively to index
2012-12-02 22:49:38 +00:00
GITINCOMMAND="-a" # add -a switch to "commit" call just to be sure
elif [ -f $1 ]; then
TARGETDIR=$(dirname "$IN") # dir to CD into before using git commands: extract from file name
INCOMMAND="inotifywait -qq -e close_write,move,delete $IN" # construct inotifywait-commandline
GITADD="$IN" # add only the selected file to index
GITINCOMMAND="" # no need to add anything more to "commit" call
else
echo >&2 "Error: The target is neither a regular file nor a directory."
exit 1
fi
cd $TARGETDIR # CD into right dir
#check if we are on a detached HEAD
HEADREF=$(git symbolic-ref HEAD 2> /dev/null)
if [ $? -eq 0 ]; then # HEAD is not detached
PUSH_BRANCH_EXPR="$(sed "s_^refs/heads/__" <<< "$HEADREF"):$BRANCH"
else # HEAD is detached
PUSH_BRANCH_EXPR="$BRANCH"
fi
while true; do
$INCOMMAND # wait for changes
sleep $SLEEP_TIME # wait some more seconds to give apps time to write out all changes
if [ -n "$DATE_FMT" ]; then
DATE=$(date "$DATE_FMT") # construct date-time string
fi
cd $TARGETDIR # CD into right dir
git add $GITADD # add file(s) to index
git commit $GITINCOMMAND -m"$(sed "s/%d/$DATE/" <<< "$COMMITMSG")" # construct commit message and commit
2012-11-28 00:02:11 +00:00
if [ -n "$REMOTE" ]; then # are we pushing to a remote?
if [ -z "$BRANCH" ]; then # Do we have a branch set to push to ?
2012-12-02 22:51:42 +00:00
git push $REMOTE # Branch not set, push to remote without a branch
else
git push $REMOTE $PUSH_BRANCH_EXPR # Branch set, push to the remote with the given branch
2012-11-28 00:02:11 +00:00
fi
fi
done