#!/bin/bash set -e NOGIT_DIR=.nogit NOGIT_DIR_TMP=$NOGIT_DIR-tmp usage_brief() { echo "Usage: nogit " echo "" echo "Available commands are:" echo "" echo " nogit clone" echo " nogit sync" echo "" echo "See 'nogit help' for more details" } usage() { echo "Usage: nogit " echo "" echo "Possible commands are described below:" echo "" echo "nogit clone " echo "" echo " Clone a nogit repository into the current directory." echo " This differs from 'git clone' in that it will not create" echo " a new top-level directory but will instead clone the" echo " resulting files into the current directory (which may" echo " already be a local git repository). The object store for" echo " this newly-cloned repository will be a directory named" echo " .nogit rather than .git." echo "" echo " The repository to be cloned should be a nogit repository" echo " in the sense that its files are intended to be managed" echo " according to nogit semantics. But other than that, the" echo " repository to be cloned is an actual git repository." echo "" echo "nogit sync" echo "" echo " Synchronize local and remote changes" echo "" echo " For all files managed by a previously-cloned nogit repository" echo " this command will:" echo "" echo " * Commit local changes (auto-generated commit message)" echo "" echo " * Pull down any new commits from the remote" echo "" echo " * Auto-merge local and remote (keeping both sides and" echo " with an auto-generated commit message)" echo "" echo " * Push out any new commits generated locally" echo "" echo "nogit log" echo "" echo " Display a log of changes" } nogit_clone() { url="$1" if [ -e $NOGIT_DIR ]; then echo "Error: $NOGIT_DIR already exists. Cowardly refusing to re-clone." return 1 fi if [ -e $NOGIT_DIR_TMP ]; then echo "Error: $NOGIT_DIR_TMP already exists. Was a previous clone interrupted?" echo "You'll want to clean that up before trying again." return 1 fi # Clone the repository into a temporary directory mkdir $NOGIT_DIR_TMP cd $NOGIT_DIR_TMP git clone "$url" tmp >/dev/null 2>&1 # Sanity check that we won't be overwriting any files EXISTING=() cd tmp for file in $(find . -mindepth 1 -a -path ./.git -prune -o -print); do if [ -e "../../$file" ]; then EXISTING+=($(echo "$file" | sed -s 's,^\./,,')) fi done cd .. if [ ${#EXISTING[@]} -gt 0 ]; then echo "Error: The following existing files would be overwritten:" >&2 echo "" >&2 for file in ${EXISTING[@]}; do echo " $file" >&2 done echo "" >&2 echo "Cowardly refusing to clone" >&2 cd .. rm -rf $NOGIT_DIR_TMP false fi # Install the info/atttributes file that forces the "union" merge # driver for all files, giving us the semantics of "keep both sides # of all conflicts" that is at the heart of nogit. mkdir -p tmp/.git/info echo '* merge=union' > tmp/.git/info/attributes # Install the config entry for the pretty format for "nogit log" (cd tmp; git config pretty.nogit "format:%Cblue%h %an (%ad)%Creset") # Now that we've passed the sanity check, install the cloned .git # object store into $NOGIT_DIR, cleanup our temporary files, and # checkout the (known to not be conflicting) files. mv tmp/.git ../$NOGIT_DIR cd .. rm -rf $NOGIT_DIR_TMP GIT_DIR=$NOGIT_DIR git reset --hard >/dev/null 2>&1 echo "Completed nogit clone of $url" } nogit_sync() { # First commit any locally modified nogit files GIT_DIR=$NOGIT_DIR git commit -a -m "nogit-sync commit" >/dev/null 2>&1 || true # Then, fetch and merge any upstream changes GIT_DIR=$NOGIT_DIR git fetch >/dev/null 2>&1 GIT_DIR=$NOGIT_DIR git merge -m "nogit-sync merge" >/dev/null 2>&1 # Finally, push any new commits up to the upstream repository GIT_DIR=$NOGIT_DIR git push >/dev/null 2>&1 echo "Completed nogit sync" } nogit_log() { GIT_DIR=$NOGIT_DIR git log -p --pretty=nogit } if [ $# -lt 1 ]; then echo "Error: missing command name." >&2 echo "" usage_brief >&2 exit 1 fi cmd="$1" case "$cmd" in clone) if [ $# -lt 2 ]; then echo "Error: 'nogit clone' requires the URL of a repository to clone" false; fi nogit_clone "$2" ;; sync) nogit_sync ;; log) nogit_log ;; help) usage true ;; *) echo "Error: Unknown command: $cmd" >&2 echo "" usage_brief >&2 false ;; esac exit $?