diff --git a/_vcsh b/_vcsh
index 96ae6120f8964872cfe9a71e50479b3d01514d90..6880f728eaf266b0573bd0da9acf556f48428658 100644
--- a/_vcsh
+++ b/_vcsh
@@ -95,6 +95,9 @@ function _vcsh () {
local state vcshcommand
local -a args subcommands
+ local VCSH_REPO_D
+ : ${VCSH_REPO_D:="${XDG_CONFIG_HOME:-"$HOME/.config"}/vcsh/repo.d"}
+
subcommands=(
"clone:clone an existing repository"
"commit:commit in all repositories"
@@ -136,7 +139,7 @@ function _vcsh () {
# There is no handler function, so this is probably the name
# of a repository. Act accordingly.
# FIXME: this may want to use '_dispatch vcsh git'
- _dispatch git git
+ GIT_DIR=$VCSH_REPO_D/$words[1].git _dispatch git git
else
curcontext="${curcontext%:*:*}:vcsh-${vcshcommand}:"
_call_function ret _vcsh-${vcshcommand}
diff --git a/_vcsh_bash b/_vcsh_bash
new file mode 100644
index 0000000000000000000000000000000000000000..3cfe88a6ace6594bebc9ce983a34a4c1dd1f4ea5
--- /dev/null
+++ b/_vcsh_bash
@@ -0,0 +1,138 @@
+# bash completion for vcsh.
+
+# run git command
+# based on bash_completion:_command_offset()
+_vcsh_git_command () {
+ local word_offset=$1
+ for (( i=0; i < $word_offset; i++ )); do
+ for (( j=0; j <= ${#COMP_LINE}; j++ )); do
+ [[ "$COMP_LINE" == "${COMP_WORDS[i]}"* ]] && break
+ COMP_LINE=${COMP_LINE:1}
+ ((COMP_POINT--))
+ done
+ COMP_LINE=${COMP_LINE#"${COMP_WORDS[i]}"}
+ ((COMP_POINT-=${#COMP_WORDS[i]}))
+ done
+ COMP_LINE="git $COMP_LINE"
+ ((COMP_POINT+=4))
+
+ # shift COMP_WORDS elements and adjust COMP_CWORD
+ for (( i=1; i <= COMP_CWORD - $word_offset + 1; i++ )); do
+ COMP_WORDS[i]=${COMP_WORDS[i+$word_offset-1]}
+ done
+ for (( i; i <= COMP_CWORD; i++ )); do
+ unset 'COMP_WORDS[i]'
+ done
+ COMP_WORDS[0]=git
+ ((COMP_CWORD -= $word_offset - 1))
+
+ local cspec=$( complete -p git 2>/dev/null )
+ if [[ -n $cspec ]]; then
+ if [[ ${cspec#* -F } != $cspec ]]; then
+ local func=${cspec#*-F }
+ func=${func%% *}
+
+ if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then
+ $func git "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}"
+ else
+ $func git "${COMP_WORDS[${#COMP_WORDS[@]}-1]}"
+ fi
+
+ # restore initial compopts
+ local opt
+ while [[ $cspec == *" -o "* ]]; do
+ # FIXME: should we take "+o opt" into account?
+ cspec=${cspec#*-o }
+ opt=${cspec%% *}
+ compopt -o $opt
+ cspec=${cspec#$opt}
+ done
+ fi
+ fi
+}
+
+_vcsh () {
+ local cur prev words cword OPTS
+ _init_completion -n = || return
+
+ local repos cmds
+ repos=( $(command vcsh list) )
+ cmds="clone delete enter foreach help init list list-tracked list-untracked
+ pull push rename run status upgrade version which write-gitignore"
+
+ local subcword cmd subcmd
+ for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do
+ [[ -n $cmd && ${words[subcword]} != -* ]] && subcmd=${words[subcword]} && break
+ [[ ${words[subcword]} != -* ]] && cmd=${words[subcword]}
+ done
+
+ if [[ -z $cmd ]]; then
+ case $prev in
+ -c)
+ COMPREPLY=( $(compgen -f -- $cur) )
+ return
+ ;;
+ esac
+
+ case $cur in
+ -*)
+ OPTS='-c -d -h -v'
+ COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
+ return
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W "${repos[*]} ${cmds[*]}" -- $cur) )
+ return 0
+ fi
+
+ case $cmd in
+ help|init|list|pull|push|version|which)
+ return
+ ;;
+
+ list-untracked)
+ [[ $cur == -* ]] && \
+ COMPREPLY=( $(compgen -W '-a -r' -- $cur) ) && return
+ ;;&
+
+ run)
+ if [[ -n $subcmd && -n "${repos[$subcmd]}" ]]; then
+ _command_offset $(( $subcword+1 ))
+ return
+ fi
+ ;;&
+
+ delete|enter|list-tracked|list-untracked|rename|run|status|upgrade|write-gitignore)
+ # return repos
+ if [[ -z $subcmd ]]; then
+ COMPREPLY=( $(compgen -W "${repos[*]}" -- $cur) )
+ return
+ fi
+ return
+ ;;
+
+ clone)
+ [[ $cur == -* ]] && \
+ COMPREPLY=( $(compgen -W '-b' -- $cur) )
+ return
+ ;;
+
+ foreach)
+ [[ $cur == -* ]] \
+ && COMPREPLY=( $(compgen -W "-g" -- $cur) ) && return
+ _vcsh_git_command $subcword
+ return
+ ;;
+
+ esac
+
+ # git command on repository
+ if [[ -n "${repos[$cmd]}" ]]; then
+ _vcsh_git_command $subcword
+ fi
+ return 0
+}
+
+complete -F _vcsh vcsh
+
+# vim: ft=sh:
diff --git a/doc/vcsh.1.ronn b/doc/vcsh.1.ronn
index 45b8c831c0b913ad170eabbebbb9af4996a3ff6f..a25bf65b18c5ac5fecef303cae607e662a22d71c 100644
--- a/doc/vcsh.1.ronn
+++ b/doc/vcsh.1.ronn
@@ -98,7 +98,7 @@ an interactive user.
Delete an existing repository.
* enter:
- Enter repository; spawn new <$SHELL>.
+ Enter repository; spawn new <$SHELL> with <$GIT_DIR> set.
* foreach:
Execute git command for every vcsh repository.
diff --git a/t/100-init.t b/t/100-init.t
index 74facc02655ba9db6b733c754d6685b61d43813d..15ce922f0e32040dae47cb795653567b8a90a2b7 100644
--- a/t/100-init.t
+++ b/t/100-init.t
@@ -18,7 +18,7 @@ ok $output eq "", 'No repos set up yet.';
$output = `./vcsh init test1`;
-ok $output eq "Initialized empty shared Git repository in " . $ENV{'HOME'} . "/.config/vcsh/repo.d/test1.git/\n";
+ok $output eq "Initialized empty Git repository in " . $ENV{'HOME'} . "/.config/vcsh/repo.d/test1.git/\n";
$output = `./vcsh status`;
diff --git a/vcsh b/vcsh
index de1b419f4ce57ee0d74233d4156358d418f3055a..ce6705d979916ae84dcf759efc9881bc546231d9 100755
--- a/vcsh
+++ b/vcsh
@@ -22,6 +22,9 @@
VERSION='1.20141026'
SELF=$(basename $0)
+# Ensure all files created are accessible only to the current user.
+umask 0077
+
fatal() {
echo "$SELF: fatal: $1" >&2
[ -z $2 ] && exit 1
@@ -106,6 +109,7 @@ help() {
commit Commit in all repositories
delete <repo> Delete an existing repository
enter <repo> Enter repository; spawn new instance of \$SHELL
+ with \$GIT_DIR set.
foreach [<-g>]
<git command> Execute a command for every repository
help Display this help text
@@ -261,7 +265,7 @@ init() {
[ ! -e "$GIT_DIR" ] || fatal "'$GIT_DIR' exists" 10
mkdir -p "$VCSH_BASE" || fatal "could not create '$VCSH_BASE'" 50
cd "$VCSH_BASE" || fatal "could not enter '$VCSH_BASE'" 11
- git init --shared=0600
+ git init --shared=false
upgrade
hook post-init
}