Dridi Boukelmoune <dridi.boukelmoune@gmail.com>
Rob Cornish <jrmcornish@gmail.com>
Vincent Demeester <vincent@demeester.fr>
+Mert Dirik <mertdirik@gmail.com>
Jeff Fein-Worton <jeff@fein-worton.com>
Thomas Ferris Nicolaisen <tfnico@gmail.com>
martin f. krafft <madduck@madduck.net>
Richard Hartmann <richih@debian.org>
Gregor Jasny <gjasny@googlemail.com>
Errietta Kostala <errietta@errietta.me>
+Yuval Langer <yuval.langer@gmail.com>
Caleb Maclennan <caleb@alerque.com>
Markus Martin <markus@archwyrm.net>
mek-apelsin <mek@pels.in>
Pavlos Ratis <dastergon@gentoo.org>
Dewey Sasser <dewey@sasser.com>
Gernot Schulz <post@gernot-schulz.com>
+Aaron Schumacher <ajschumacher@gmail.com>
Andrew Schwartzmeyer <andrew@schwartzmeyer.com>
Dato Simó <dato@net.com.org.es>
Alexander Skurikhin <a.skurihin@gmail.com>
Jonathan Sternberg <jonathansternberg@gmail.com>
Frank Terbeck <ft@bewatermyfriend.org>
+mirabilos <tg@debian.org>
Aaron VonderHaar <gruen0aermel@gmail.com>
Tony <zearin@gonk.net>
-PREFIX=/usr
+PREFIX?=/usr
DOCDIR_PREFIX=$(PREFIX)/share/doc
DOCDIR=$(DOCDIR_PREFIX)/$(self)
ZSHDIR=$(PREFIX)/share/zsh/vendor-completions
(( CURRENT == 2 )) && __vcsh_repositories
}
+function _vcsh-list-untracked () {
+ _nothing
+}
+
function _vcsh-pull () {
_nothing
}
fi
}
+function _vcsh-status () {
+ (( CURRENT == 2 )) && __vcsh_repositories
+}
+
function _vcsh-upgrade () {
(( CURRENT == 2 )) && __vcsh_repositories
}
"list:list all local vcsh repositories"
"list-tracked:list all files tracked by vcsh"
"list-tracked-by:list files tracked by a repository"
+ "list-untracked:list all files not tracked by vcsh"
"pull:pull from all vcsh remotes"
"push:push to vcsh remotes"
"rename:rename a repository"
+2014-10-25 Richard Hartmann <richih.mailinglist@gmail.com>
+
+ * Release 1.20141025
+ * `vcsh which dontexist` exits 1
+ * `vcsh status` shows commits ahead/behind remote tracking branch
+ * Support overlay functions
+ * Support `vcsh list-untracked`, optionally recursively
+ * Support `vcsh list-untracked $repo`
+ * Improve error handling of clone()
+ * Rename `list-tracked-by` to `list-tracked <repo>`
+ * Support repo-specific config files
+ * Various minor improvements
+ * More moo
+
+2014-10-09 Richard Hartmann <richih.mailinglist@gmail.com>
+
+ * Display full paths in list-tracked*
+ * Lots of help improvements
+
2014-05-08 Richard Hartmann <richih.mailinglist@gmail.com>
* Revert "Introduce static manpage as part of normal repo"
`vcsh` was designed with [myrepos][myrepos], a tool to manage Multiple
Repositories, in mind and the two integrate very nicely. The myrepos tool
(`mr`) has native support for `vcsh` repositories and the configuration for
-myrepos is just another set of files that you cat track with `vcsh` like any
+myrepos is just another set of files that you can track with `vcsh` like any
other. This makes setting up any new machine a breeze. It can take literally
less than five minutes to go from standard installation to fully set up system.
proposed system that follows. For instance, you can use
[myrepos][myrepos] to track repositories in home such as `.emacs.d`,
which `mr` can clone and update for you automatically. To do this,
-just add a `mr` configuration file to `availabile.d` with a `checkout`
+just add a `mr` configuration file to `available.d` with a `checkout`
command to clone the repo, and set the [title] to the desired
location, e.g. `$HOME/.emacs.d`. Try the `mr register` command in an
existing repository, then view `~/.mrconfig` for an example.
vcsh will check if any file it would want to create exists. If it exists, vcsh
will throw a warning and exit. Move away your old config and try again.
Optionally, merge your local and your global configs afterwards and push with
-`vcsh foo push`.
+`vcsh repo_name push`.
## Moving into a New Host
And then create your own stuff:
- vcsh init foo
- vcsh foo add bar baz quux
- vcsh foo remote add origin git://quuux
- vcsh foo commit
- vcsh foo push
- cp $XDG_CONFIG_HOME/mr/available.d/mr.vcsh $XDG_CONFIG_HOME/mr/available.d/foo.vcsh
- vim $XDG_CONFIG_HOME/mr/available.d/foo.vcsh # add your own repo
+ vcsh init repo_name
+ vcsh repo_name add bar baz quux
+ vcsh repo_name remote add origin git://quuux
+ vcsh repo_name commit
+ vcsh repo_name push
+
+ cp $XDG_CONFIG_HOME/mr/available.d/mr.vcsh $XDG_CONFIG_HOME/mr/available.d/repo_name.vcsh
+ vim $XDG_CONFIG_HOME/mr/available.d/repo_name.vcsh # add your own repo
Done!
After you have made some changes, for which you would normally use `git add`
and `git commit`, use the vcsh wrapper (like above):
- vcsh foo add bar baz quux
- vcsh foo commit
- vcsh foo push
+ vcsh repo_name add bar baz quux
+ vcsh repo_name commit
+ vcsh repo_name push
### Using vcsh without myrepos
`vcsh` list
-`vcsh` list-tracked
+`vcsh` list-tracked [<rpoe>]
-`vcsh` list-tracked-by <repo>
+`vcsh` list-untracked [<-r>] [<repo>]
`vcsh` pull
* list-tracked:
List all files tracked by vcsh.
+ If you want to list files tracked by a specific repository, simply
+ append the repository's name last.
+
* list-tracked-by:
List files tracked by a repository.
+ This is a legacy command; you should use `list-tracked <repo>` instead.
+
+* list-untracked:
+ List all files NOT tracked by vcsh.
+
+ By default, the file list is shallow and stops at directory levels where
+ possible. If you prefer to get a list of all files, append `-r` for
+ recursive mode.
+
+ If you want to list files not tracked by a specific repository, simply
+ append the repository's name last.
+
* pull:
Pull from all vcsh remotes.
If you need more, vcsh is trivial to patch, but please let upstream know so
we can ship them by default.
+## OVERLAY SYSTEM
+
+`vcsh` also provides an overlay system. Similar to hooks, the recommended
+locations are <$XDG_CONFIG_HOME/vcsh/overlays-available> and
+<$XDG_CONFIG_HOME/vcsh/overlays-enabled>.
+
+Overlays follow the same rules as hooks and you are free to overwrite any
+and all functions. Same as hooks, you can use global or repository-specific
+overlays by using either <$VCSH_OVERLAY_D/$VCSH_COMMAND> or
+<$VCSH_OVERLAY_D/$VCSH_REPO_NAME.$VCSH_COMMAND>.
+
+Please note that nothing stops you from, e.g. overwriting `status()` in
+<$VCSH_OVERLAY_D/commit>. As the overlays will be sourced and you are
+replacing arbitrary functions, any and all features may stop working, or you
+may even lose data.
+
+You have been warned.
+
## DETAILED HOWTO AND FURTHER READING
Manpages are often short and sometimes useless to glean best practices from.
# If '.git-HEAD' is appended to the version, you are seeing an unreleased
# version of vcsh; the master branch is supposed to be clean at all times
# so you can most likely just use it nonetheless
-VERSION='1.20140508'
+VERSION='1.20141025'
SELF=$(basename $0)
fatal() {
echo "$SELF: fatal: $1" >&2
+ [ -z $2] && exit 1
exit $2
}
# Read defaults
: ${VCSH_REPO_D:="$XDG_CONFIG_HOME/vcsh/repo.d"}
: ${VCSH_HOOK_D:="$XDG_CONFIG_HOME/vcsh/hooks-enabled"}
+: ${VCSH_OVERLAY_D:="$XDG_CONFIG_HOME/vcsh/overlays-enabled"}
: ${VCSH_BASE:="$HOME"}
: ${VCSH_GITIGNORE:=exact}
: ${VCSH_GITATTRIBUTES:=none}
help Display this help text
init <repo> Initialize a new repository
list List all repositories
- list-tracked List all files tracked by vcsh
- list-tracked-by \\
- <repo> List files tracked by a repository
+ list-tracked \\
+ [<repo>] List all files tracked all or one repositories
+ list-untracked \\
+ [<-r>] [<repo>] List all files not tracked by all or one repositories
pull Pull from all vcsh remotes
push Push to vcsh remotes
rename <repo> \\
}
list_tracked() {
- for VCSH_REPO_NAME in $(list); do
- get_files
- done | sed "s,^,$(printf '%s\n' "$VCSH_BASE/" | \
- sed 's/[,\&]/\\&/g')," | sort -u
+ VCSH_REPO_NAME=$2; export VCSH_REPO_NAME
+ if [ -n "$VCSH_REPO_NAME" ]; then
+ get_files | list_tracked_helper
+ else
+ for VCSH_REPO_NAME in $(list); do
+ get_files
+ done | list_tracked_helper
+ fi
+}
+
+list_tracked_helper() {
+ sed "s,^,$(printf '%s\n' "$VCSH_BASE/" | sed 's/[,\&]/\\&/g')," | sort -u
}
list_tracked_by() {
- use
- git ls-files | sed "s,^,$(printf '%s\n' "$VCSH_BASE/" | \
- sed 's/[,\&]/\\&/g')," | sort -u
+ list_tracked $2
+}
+
+list_untracked() {
+ command -v 'comm' >/dev/null 2>&1 || fatal "Could not find 'comm'"
+
+ temp_file_others=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file'
+ temp_file_untracked=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file'
+ temp_file_untracked_copy=$(mktemp "${TMPDIR:-/tmp}/tmp.XXXXXXXXXX") || fatal 'Could not create temp file'
+
+ # Hack in support for `vcsh list-untracked -r`...
+ directory_opt="--directory"
+ shift 1
+ while getopts "r" flag; do
+ if [ x"$1" = x'-r' ]; then
+ unset directory_opt
+ fi
+ shift 1
+ done
+ # ...and parse for a potential parameter afterwards. As we shifted things out of $* in during getops, we need to look at $1
+ VCSH_REPO_NAME=$1; export VCSH_REPO_NAME
+
+ if [ -n "$VCSH_REPO_NAME" ]; then
+ list_untracked_helper $VCSH_REPO_NAME
+ else
+ for VCSH_REPO_NAME in $(list); do
+ list_untracked_helper $VCSH_REPO_NAME
+ done
+ fi
+ cat $temp_file_untracked
+
+ unset directory_opt directory_component
+ rm -f $temp_file_others $temp_file_untracked $temp_file_untracked_copy || fatal 'Could not delete temp files'
+}
+
+list_untracked_helper() {
+ export GIT_DIR="$VCSH_REPO_D/$VCSH_REPO_NAME.git"
+ git ls-files --others "$directory_opt" | (
+ while read line; do
+ echo "$line"
+ directory_component=${line%%/*}
+ [ -d "$directory_component" ] && printf '%s/\n' "$directory_component"
+ done
+ ) | sort -u > $temp_file_others
+ if [ -z "$ran_once" ]; then
+ ran_once=1
+ cp $temp_file_others $temp_file_untracked || fatal 'Could not copy temp file'
+ fi
+ cp $temp_file_untracked $temp_file_untracked_copy || fatal 'Could not copy temp file'
+ comm -12 --nocheck-order $temp_file_others $temp_file_untracked_copy > $temp_file_untracked
}
pull() {
status() {
if [ -n "$VCSH_REPO_NAME" ]; then
- GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR
- use
- git status --short --untracked-files='no'
- VCSH_COMMAND_RETURN_CODE=$?
+ status_helper $VCSH_REPO_NAME
else
for VCSH_REPO_NAME in $(list); do
echo "$VCSH_REPO_NAME:"
- GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR
- use
- git status --short --untracked-files='no'
- VCSH_COMMAND_RETURN_CODE=$?
+ status_helper $VCSH_REPO_NAME
echo
done
fi
}
+status_helper() {
+ GIT_DIR=$VCSH_REPO_D/$VCSH_REPO_NAME.git; export GIT_DIR
+ use
+ remote_tracking_branch=$(git rev-parse --abbrev-ref --symbolic-full-name @{u} 2> /dev/null) && {
+ commits_behind=$(git log ..${remote_tracking_branch} --oneline | wc -l)
+ commits_ahead=$(git log ${remote_tracking_branch}.. --oneline | wc -l)
+ [ ${commits_behind} -ne 0 ] && echo "Behind $remote_tracking_branch by $commits_behind commits"
+ [ ${commits_ahead} -ne 0 ] && echo "Ahead of $remote_tracking_branch by $commits_ahead commits"
+ }
+ git status --short --untracked-files='no'
+ VCSH_COMMAND_RETURN_CODE=$?
+}
+
upgrade() {
hook pre-upgrade
# fake-bare repositories are not bare, actually. Set this to false
}
which() {
+ [ -e "$VCSH_COMMAND_PARAMETER" ] || fatal "'$VCSH_COMMAND_PARAMETER' does not exist" 1
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"
elif [ x"$VCSH_COMMAND" = x'commit' ] ||
[ x"$VCSH_COMMAND" = x'list' ] ||
[ x"$VCSH_COMMAND" = x'list-tracked' ] ||
+ [ x"$VCSH_COMMAND" = x'list-untracked' ] ||
[ x"$VCSH_COMMAND" = x'pull' ] ||
[ x"$VCSH_COMMAND" = x'push' ]; then
:
verbose "$VCSH_COMMAND begin"
VCSH_COMMAND=$(echo "$VCSH_COMMAND" | sed 's/-/_/g'); export VCSH_COMMAND
+
+# Source repo-specific configuration file
+[ -r "$XDG_CONFIG_HOME/vcsh/config.d/$VCSH_REPO_NAME" ] && . "$XDG_CONFIG_HOME/vcsh/config.d/$VCSH_REPO_NAME"
+
+# source overlay functions
+for overlay in "$VCSH_OVERLAY_D/$VCSH_COMMAND"* "$VCSH_OVERLAY_D/$VCSH_REPO_NAME.$VCSH_COMMAND"*; do
+ [ -r "$overlay" ] || continue
+ info "sourcing '$overlay'"
+ . "$overlay"
+done
+
hook pre-command
$VCSH_COMMAND "$@"
hook post-command