]> git.madduck.net Git - code/vcsh.git/blob - vcsh

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

All patches and comments are welcome. Please squash your changes to logical commits before using git-format-patch and git-send-email to patches@git.madduck.net. If you'd read over the Git project's submission guidelines and adhered to them, I'd be especially grateful.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Merge branch 'master' into docs
[code/vcsh.git] / vcsh
1 #!/bin/sh
2
3 [ -n "$VCSH_DEBUG" ] && set -x
4
5 SELF=$(basename $0)
6
7 [ -z "$XDG_CONFIG_HOME" ] && XDG_CONFIG_HOME="$HOME/.config"
8 [ -z "$VCSH_BASE" ]       && VCSH_BASE="$XDG_CONFIG_HOME/vcsh/repo.d"
9 for check_directory in "$VCSH_BASE" "$HOME/.gitignore.d"
10 do
11         if [ ! -d "$check_directory" ]; then
12                 if [ -e "$check_directory" ]; then
13                         echo "$SELF: error: $check_directory exists but is not a directory" >&2
14                         exit 2
15                 else
16                         echo "$SELF: info: attempting to create $check_directory"
17                         mkdir -p "$check_directory" || (echo "$SELF: error: could not create $check_directory" >&2; exit 2)
18                 fi
19         fi
20 done
21
22 debug() {
23         [ -n "$VCSH_DEBUG" ] && echo "$SELF: debug: $1"
24 }
25
26 verbose() {
27         if [ -n "$VCSH_DEBUG" ] || [ -n "$VCSH_VERBOSE" ]; then echo "$SELF: verbose: $1"; fi
28 }
29
30 #   use <repo>     Use this repository
31 #
32 #   exit              Exit vcsh mode" >&2
33 help() {
34         echo "usage: $SELF <args>
35
36    help              Display this help
37
38    list              List all repos
39
40    run <repo> \\
41        <command>     Use this repository
42
43    init <repo>       Initialize a new repository
44    clone <remote> \\
45          [<repo>]    Clone from an existing repository
46    seed-gitignore \\
47    <repo>            Seed .gitignore.d/<repo> from git ls-files" >&2
48 }
49
50 use() {
51         verbose "use() begin"
52         REPO_NAME="$1"
53         GIT_DIR="$VCSH_BASE/$REPO_NAME.git"
54
55         if [ ! -d "$GIT_DIR" ]; then
56                 echo E: no repository found for "$REPO_NAME" >&2
57                 return 2
58         fi
59
60         export GIT_DIR
61         export GIT_WORK_TREE="$(git config --get core.worktree)"
62         export VCSH_DIRECTORY="$REPO_NAME"
63         verbose "use() end"
64 }
65
66 init() {
67         verbose "init() begin"
68         [ -e "$GIT_DIR" ] &&
69                 echo "$SELF: fatal: $GIT_DIR exists" &&
70                 return 21
71         export GIT_WORK_TREE="$HOME"
72         mkdir -p "$GIT_WORK_TREE"
73         cd "$GIT_WORK_TREE" ||
74                 (echo "$SELF: fatal: could not enter $GIT_WORK_TREE" &&
75                  exit 20) || exit 20
76         cd "$GIT_WORK_TREE"
77         git init
78         git config core.worktree     "$GIT_WORK_TREE"
79         git config core.excludesfile ".gitignore.d/$REPO_NAME"
80         verbose "init() end"
81 }
82
83 leave() {
84         unset GIT_DIR
85         unset GIT_WORK_TREE
86         unset VCSH_DIRECTORY
87 }
88
89 if [ "$1" = 'help' ] || [ "$#" -eq 0 ]; then
90         help
91         [ "$1" = 'help' ]
92         exit $?
93
94 elif [ "$1" = 'list' ]; then
95         verbose "list begin"
96         for i in "$VCSH_BASE"/*.git; do
97                 echo $(basename "$i" .git)
98         done
99         verbose "list end"
100         exit 0
101
102 elif [ "$1" = 'run' ]; then
103         verbose "run begin"
104         use "$2"
105         shift 2
106         "$@"
107         leave
108         verbose "run end"
109         exit 0
110
111 #elif [ "$1" = 'use' ]; then
112 #       verbose "use begin"
113 #       if [ -n "$ZSH_VERSION" ]; then
114 #               if [ -o NO_IGNORE_EOF ]; then
115 #                       export VCSH_NO_IGNORE_EOF=1
116 #                       setopt IGNORE_EOF
117 #               fi
118 #               vcsh_exit() {
119 #                       vcsh exit;
120 #                       zle reset-prompt;
121 #               }
122 #               zle -N vcsh_exit
123 #               bindkey '^d' 'vcsh_exit'
124 #       fi
125 #       use $2
126 #       [ -n "$ZSH_VERSION" ] && [ "$USER" = richih ] && buildPS1
127 #       verbose "use end"
128 #       exit 0
129
130 elif [ "$1" = 'clone' ]; then
131         verbose "clone begin"
132         GIT_REMOTE="$2"
133         REPO_NAME="$3"
134         [ -z "$REPO_NAME" ] && REPO_NAME=$(basename "$GIT_REMOTE" .git)
135         export REPO_NAME
136         export GIT_DIR="$VCSH_BASE/$REPO_NAME.git"
137         init
138
139         git remote add origin "$GIT_REMOTE"
140         git config branch.master.remote origin
141         git config branch.master.merge  refs/heads/master
142         git config core.excludesfile    ".gitignore.d/$REPO_NAME"
143         git fetch
144         for object in $(git ls-tree -r origin/master | awk '{print $4}'); do
145                 [ -e "$object" ] &&
146                         echo "$SELF: error: $object exists." &&
147                         VCSH_CONFLICT=1;
148         done
149         [ "$VCSH_CONFLICT" = '1' ] &&
150                 echo "$SELF: fatal: will stop after fetching and not try to merge!\n" &&
151                 echo "  Once this situation has been resolved, run 'vcsh run <foo> git pull' to finish cloning.\n" &&
152                 exit 3
153         git merge origin/master
154 #       vcsh use $REPO_NAME
155         verbose "clone end"
156
157 elif [ "$1" = 'init' ]; then
158         verbose "init begin"
159         [ -z $2 ] && help && echo && echo "$SELF $1: error: please specify repository to work on" && return 0
160         export REPO_NAME="$2"
161         export GIT_DIR="$VCSH_BASE/$REPO_NAME.git"
162         init
163 #       vcsh use "$REPO_NAME"
164         verbose "init end"
165
166 #elif [ "$1" = 'exit' ]; then
167 #       verbose "exit begin"
168 #       if [ -n "$ZSH_VERSION" ] && [ "$VCSH_NO_IGNORE_EOF" = '1' ]; then
169 #               unset VCSH_NO_IGNORE_EOF
170 #               setopt NO_IGNORE_EOF
171 #       fi
172 #       leave
173 #       [ -n "$ZSH_VERSION" ] && [ "$USER" = richih ] && buildPS1
174 #       verbose "exit end"
175 #       exit 0
176
177 elif [ "$1" = 'seed-gitignore' ]; then
178         verbose "seed-gitignore begin"
179         [ -z $2 ] && help && echo && echo "$SELF $1: error: please specify repository to work on" && return 0
180         use "$2"
181         git config core.excludesfile ".gitignore.d/$REPO_NAME"
182         files=$(git ls-files)
183         gitignores=$(for file in $(git ls-files); do
184                 while true; do
185                         echo $file; new="${file%/*}"
186                         [ "$file" = "$new" ] && break
187                         file="$new"
188                 done;
189         done | sort -u | sed 's/^/!/')
190         [ -e .gitignore.d/$2 ] &&
191         echo "$SELF: info: .gitignore.d/$2 exists, moving it to .gitignore.d/$2.bak" &&
192         mv -f .gitignore.d/$2 .gitignore.d/$2.bak
193         echo '*' > .gitignore.d/$2
194         for gitignore in $gitignores; do
195                 echo $gitignore >> .gitignore.d/$2
196         done
197
198 else
199         verbose "defaulting to calling help()"
200         help
201         exit 3
202
203 fi
204