+run() {
+ hook pre-run
+ use
+ $VCSH_EXTERNAL_COMMAND
+ hook post-run
+}
+
+setup() {
+ hook pre-setup
+ use
+ git config core.worktree "$GIT_WORK_TREE"
+ git config core.excludesfile ".gitignore.d/$VCSH_REPO_NAME"
+ git config vcsh.vcsh 'true'
+ [ -e "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" ] && git add -f "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME"
+ hook post-setup
+}
+
+use() {
+ git_dir_exists
+ export GIT_WORK_TREE="$(git config --get core.worktree)"
+ export VCSH_DIRECTORY="$VCSH_REPO_NAME"
+}
+
+which() {
+ for VCSH_REPO_NAME in $(list); do
+ for VCSH_FILE in $(get_files); do
+ echo $VCSH_FILE | grep -q "$VCSH_COMMAND_PARAMETER" && echo "$VCSH_REPO_NAME: $VCSH_FILE"
+ done
+ done | sort -u
+}
+
+write_gitignore() {
+ use
+ cd "$VCSH_BASE" || fatal "could not enter '$VCSH_BASE'" 11
+ gitignores=$(for file in $(git ls-files); do
+ while true; do
+ echo $file; new="${file%/*}"
+ [ "$file" = "$new" ] && break
+ file="$new"
+ done;
+ done | sort -u)
+ tempfile=$(mktemp) || fatal "could not create tempfile" 51
+ echo '*' > "$tempfile" || fatal "could not write to '$tempfile'" 57
+ for gitignore in $gitignores; do
+ echo "$gitignore" | sed 's/^/!/' >> "$tempfile" || fatal "could not write to '$tempfile'" 57
+ if [ x$VCSH_GITIGNORE = x'recursive' ] && [ -d "$gitignore" ]; then
+ { echo "$gitignore/*" | sed 's/^/!/' >> "$tempfile" || fatal "could not write to '$tempfile'" 57; }
+ fi
+ done
+ if diff -N "$tempfile" "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" > /dev/null; then
+ rm -f "$tempfile" || error "could not delete '$tempfile'"
+ exit
+ fi
+ if [ -e "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" ]; then
+ info "'$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME' differs from new data, moving it to '$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME.bak'"
+ mv -f "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME.bak" ||
+ fatal "could not move '$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME' to '$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME.bak'" 53
+ fi
+ mv -f "$tempfile" "$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME" ||
+ fatal "could not move '$tempfile' to '$VCSH_BASE/.gitignore.d/$VCSH_REPO_NAME'" 53
+}
+
+if [ ! "x$VCSH_GITIGNORE" = 'xexact' ] && [ ! "x$VCSH_GITIGNORE" = 'xrecursive' ]; then
+ fatal "'\$VCSH_GITIGNORE' must be either 'exact' or 'recursive'" 1
+fi
+
+if [ "$1" = 'clone' ]; then
+ [ -z "$2" ] && fatal "$1: please specify a remote" 1
+ export VCSH_COMMAND="$1"
+ GIT_REMOTE="$2"
+ [ -n "$3" ] && VCSH_REPO_NAME="$3" || VCSH_REPO_NAME=$(basename "$GIT_REMOTE" .git)
+ export VCSH_REPO_NAME
+ export GIT_DIR="$VCSH_REPO_D/$VCSH_REPO_NAME.git"
+elif [ "$1" = 'which' ]; then
+ [ -z "$2" ] && fatal "$1: please specify a filename" 1
+ [ -n "$3" ] && fatal "$1: too many parameters" 1
+ export VCSH_COMMAND="$1"
+ export VCSH_COMMAND_PARAMETER="$2"
+elif [ "$1" = 'delete' ] ||
+ [ "$1" = 'enter' ] ||
+ [ "$1" = 'init' ] ||
+ [ "$1" = 'list-tracked-by' ] ||
+ [ "$1" = 'rename' ] ||
+ [ "$1" = 'run' ] ||
+ [ "$1" = 'setup' ] ||
+ [ "$1" = 'write-gitignore' ]; then
+ [ -z $2 ] && fatal "$1: please specify repository to work on" 1
+ [ "$1" = 'rename' -a -z "$3" ] && fatal "$1: please specify a target name" 1
+ [ "$1" = 'run' -a -z "$3" ] && fatal "$1: please specify a command" 1
+ export VCSH_COMMAND="$1"
+ export VCSH_REPO_NAME="$2"
+ export GIT_DIR="$VCSH_REPO_D/$VCSH_REPO_NAME.git"
+ [ "$VCSH_COMMAND" = 'rename' ] && export GIT_DIR_NEW="$VCSH_REPO_D/$3.git"
+ [ "$VCSH_COMMAND" = 'run' ] && shift 2 && export VCSH_EXTERNAL_COMMAND="$*"
+ [ "$VCSH_COMMAND" = 'write-gitignore' ]
+elif [ "$1" = 'list' ] ||
+ [ "$1" = 'list-tracked' ]; then
+ export VCSH_COMMAND="$1"
+elif [ -n "$2" ]; then
+ export VCSH_COMMAND='run'
+ export VCSH_REPO_NAME="$1"
+ export GIT_DIR="$VCSH_REPO_D/$VCSH_REPO_NAME.git"
+ [ -d $GIT_DIR ] || { help; exit 1; }
+ shift 1
+ export VCSH_EXTERNAL_COMMAND="git $*"
+elif [ -n "$1" ]; then
+ export VCSH_COMMAND='enter'
+ export VCSH_REPO_NAME="$1"
+ export GIT_DIR="$VCSH_REPO_D/$VCSH_REPO_NAME.git"
+ [ -d $GIT_DIR ] || { help; exit 1; }