#!/bin/bash abort() { echo $1 exit 1 } cmd="$1" shift USAGE="usage: zit COMMAND FILE [ARGS...]" zit_help() { cmd="$1" shift case $cmd in git) git help "$@" ;; *) echo $USAGE echo "" echo "Set up a git repository under .zit.FILE to track changes for FILE." echo "File must be a regular file and in the current directory." echo "" echo "Zit commands:" echo " init Synonym for track" echo " list Synonym for tracked" echo " track Start tracking changes to FILE" echo " tracked List tracked files in current directory" echo "" echo "See 'zit help git' or 'git help' for git commands." ;; esac } ZIT_DIR=.zit zit_setup() { ZIT_FILE="$1" test $ZIT_FILE || abort "Please specify a file" test -f $ZIT_FILE || abort "No such file $ZIT_FILE" test $ZIT_FILE = "`basename $ZIT_FILE`" || abort "Sorry, Zit only works on files in the current directory" export GIT_WORK_TREE="`pwd`" # first, check if a repo exists already, looking for # .zit/file.git or .file.git, in that order # if neither is found, and .zit exists, set the repo dir # to .zit/file.git, otherwise set it to .file.git GIT_DIR="$ZIT_DIR/$ZIT_FILE.git" if ! test -d "$GIT_DIR"; then GIT_DIR=".$ZIT_FILE.git" if ! test -d "$GIT_DIR"; then test -d "$ZIT_DIR" && GIT_DIR="$ZIT_DIR/$ZIT_FILE.git" fi fi export GIT_DIR } zit_init() { if test "$1"; then zit_setup $1 test -e $GIT_DIR && abort "$GIT_DIR exists, is $ZIT_FILE tracked already?" mkdir $GIT_DIR && echo "Initializing Zit repository in $GIT_DIR" test -d $GIT_DIR || abort "Failed to create $GIT_DIR" git init || abort "Failed to initialize Git repository in $GIT_DIR" rm -rf $GIT_DIR/{hooks,info,branches,refs/tags,objects/pack,description} ZIT_IGNORE="$HOME/.zitignore" if ! test -f "$ZIT_IGNORE"; then touch "$ZIT_IGNORE" || abort "Cannot create $ZIT_IGNORE file" echo "# Ignore patterns used by Zit repositories" > "$ZIT_IGNORE" echo "# By default it's the single '*' glob, since we want to ignore all" >> $ZIT_IGNORE echo "# non-tracked files in the work-tree" >> $ZIT_IGNORE echo "*" >> $ZIT_IGNORE fi git config core.excludesfile "$ZIT_IGNORE" git add -f $ZIT_FILE || abort "Failed to add $ZIT_FILE" git commit "$@" || abort "Failed to make first commit for $ZIT_FILE" else if test -d "$ZIT_DIR"; then echo "$ZIT_DIR exists already" exit fi test -e $ZIT_DIR && abort "$ZIT_DIR exists but it's not a directory, cannot continue" mkdir $ZIT_DIR fi } zit_list() { export GIT_WORK_TREE="`pwd`" GIT_DIR="" for file in "$ZIT_DIR"/*.git .*.git; do if ! test -e $file; then continue fi export GIT_DIR="$file" file="${file#.}" file="${file#zit/}" file="${file%.git}" # TODO show actual file status git ls-files -t $file done; # if $GIT_DIR is empty, no files were found test "$GIT_DIR" || echo "(no files tracked by zit)" } case $cmd in "") echo $USAGE ;; help) zit_help "$@" ;; init|track) zit_init $1 ;; list|tracked) zit_list ;; # Most commands will work with the generic catch-all mechanism used # below, but some of them require a more thorough analysis of the # parameters to decide whether $ZIT_FILE should be put back into the # parameter list or not. For example, # $ zit commit somefile # wouldn't do what one expects it to do, unless 'add' is run first, # (except that # $ zit add somefile # wouldn't work either), however # $ zit commit somefile -a # would work correctly. So we handle some commands separately (for the # moment just add and commit) add|commit) zit_setup $1 shift git $cmd "$@" "$ZIT_FILE" ;; # the raw method can be used to not replicate $ZIT_FILE in the # parameter list raw*) zit_setup $1 shift git ${cmd#raw} "$@" ;; *) zit_setup $1 shift git $cmd "$@" ;; esac