From: Richard Hartmann Date: Sat, 25 Oct 2014 20:33:39 +0000 (+0200) Subject: Merge branch 'feature--clone_branch' X-Git-Url: https://git.madduck.net/code/vcsh.git/commitdiff_plain/93b8c205b18a69c4e5ae6b9ebe425c328e23c17b?hp=4327b9b3c0a74b45c670f5af44700ef8d4579d8e Merge branch 'feature--clone_branch' Conflicts: vcsh --- diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 07456f9..d7a3394 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -6,6 +6,7 @@ Eric Bouchut Dridi Boukelmoune Rob Cornish Vincent Demeester +Mert Dirik Jeff Fein-Worton Thomas Ferris Nicolaisen martin f. krafft @@ -17,6 +18,7 @@ Valentin Haenel Richard Hartmann Gregor Jasny Errietta Kostala +Yuval Langer Caleb Maclennan Markus Martin mek-apelsin @@ -26,10 +28,12 @@ Corey Quinn Pavlos Ratis Dewey Sasser Gernot Schulz +Aaron Schumacher Andrew Schwartzmeyer Dato Simó Alexander Skurikhin Jonathan Sternberg Frank Terbeck +mirabilos Aaron VonderHaar Tony diff --git a/Makefile b/Makefile index 31ac2e4..ca6ebe6 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -PREFIX=/usr +PREFIX?=/usr DOCDIR_PREFIX=$(PREFIX)/share/doc DOCDIR=$(DOCDIR_PREFIX)/$(self) ZSHDIR=$(PREFIX)/share/zsh/vendor-completions diff --git a/_vcsh b/_vcsh index a33551b..53eaada 100644 --- a/_vcsh +++ b/_vcsh @@ -43,6 +43,10 @@ function _vcsh-list-tracked-by () { (( CURRENT == 2 )) && __vcsh_repositories } +function _vcsh-list-untracked () { + _nothing +} + function _vcsh-pull () { _nothing } @@ -66,6 +70,10 @@ function _vcsh-run () { fi } +function _vcsh-status () { + (( CURRENT == 2 )) && __vcsh_repositories +} + function _vcsh-upgrade () { (( CURRENT == 2 )) && __vcsh_repositories } @@ -97,6 +105,7 @@ function _vcsh () { "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" diff --git a/changelog b/changelog index 3e8029e..badf445 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,22 @@ +2014-10-25 Richard Hartmann + + * 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 ` + * Support repo-specific config files + * Various minor improvements + * More moo + +2014-10-09 Richard Hartmann + + * Display full paths in list-tracked* + * Lots of help improvements + 2014-05-08 Richard Hartmann * Revert "Introduce static manpage as part of normal repo" diff --git a/doc/README.md b/doc/README.md index 0fc717a..b14d782 100644 --- a/doc/README.md +++ b/doc/README.md @@ -117,7 +117,7 @@ your `$HOME`, you will end up with a lot of repositories very quickly. `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. @@ -128,7 +128,7 @@ of myrepos is technically optional, it will be an integral part of the 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. @@ -220,7 +220,7 @@ this document (see above). 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 @@ -351,14 +351,15 @@ Now, it's time to edit the template config and fill it with your own remotes: 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! @@ -427,9 +428,9 @@ Neat. 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 diff --git a/doc/vcsh.1.ronn b/doc/vcsh.1.ronn index e768882..1d432c3 100644 --- a/doc/vcsh.1.ronn +++ b/doc/vcsh.1.ronn @@ -17,9 +17,9 @@ vcsh(1) - Version Control System for $HOME - multiple Git repositories in $HOME `vcsh` list -`vcsh` list-tracked +`vcsh` list-tracked [] -`vcsh` list-tracked-by +`vcsh` list-untracked [<-r>] [] `vcsh` pull @@ -110,9 +110,24 @@ an interactive user. * 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 ` 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. @@ -257,6 +272,24 @@ Available hooks are , , , 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. diff --git a/vcsh b/vcsh index 4ab17bf..af67e18 100755 --- a/vcsh +++ b/vcsh @@ -19,11 +19,12 @@ # 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 } @@ -75,6 +76,7 @@ fi # 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} @@ -107,9 +109,10 @@ help() { help Display this help text init Initialize a new repository list List all repositories - list-tracked List all files tracked by vcsh - list-tracked-by \\ - List files tracked by a repository + list-tracked \\ + [] List all files tracked all or one repositories + list-untracked \\ + [<-r>] [] List all files not tracked by all or one repositories pull Pull from all vcsh remotes push Push to vcsh remotes rename \\ @@ -244,16 +247,71 @@ get_files() { } 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() { @@ -309,22 +367,29 @@ run() { 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 @@ -353,6 +418,7 @@ use() { } 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" @@ -482,6 +548,7 @@ elif [ x"$VCSH_COMMAND" = x'delete' ] || 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 : @@ -529,6 +596,17 @@ check_dir "$VCSH_REPO_D" 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