Show file status in zit list, and document it
[zit] / zit
1 #!/bin/bash
2
3 abort() {
4         echo $1
5         exit 1
6 }
7
8 cmd="$1"
9 shift
10
11 USAGE="usage: zit COMMAND FILE [ARGS...]"
12
13 zit_help() {
14         cmd="$1"
15         shift
16         case $cmd in
17                 git)
18                 git help "$@"
19                 ;;
20                 list|tracked)
21                 echo "usage: zit list"
22                 echo "Show tracked files, with a one-letter prefix indicating their status:"
23                 echo "   H   cached"
24                 echo "   M   unmerged"
25                 echo "   R   removed/deleted"
26                 echo "   C   modified/changed"
27                 echo "   K   to be killed"
28                 echo "   ?   other"
29                 ;;
30                 *)
31                 echo $USAGE
32                 echo ""
33                 echo "Set up a git repository under .zit.FILE to track changes for FILE."
34                 echo "File must be a regular file and in the current directory."
35                 echo ""
36                 echo "Zit commands:"
37                 echo "   init           Synonym for track"
38                 echo "   list           Synonym for tracked"
39                 echo "   track  Start tracking changes to FILE"
40                 echo "   tracked        List tracked files in current directory"
41                 echo ""
42                 echo "See 'zit help git' or 'git help' for git commands."
43                 ;;
44         esac
45 }
46
47 ZIT_DIR=.zit
48
49 zit_setup() {
50         ZIT_FILE="$1"
51         test $ZIT_FILE || abort "Please specify a file"
52         test -f $ZIT_FILE || abort "No such file $ZIT_FILE"
53         test $ZIT_FILE = "`basename $ZIT_FILE`" || abort "Sorry, Zit only works on files in the current directory"
54
55         export GIT_WORK_TREE="`pwd`"
56
57         # first, check if a repo exists already, looking for
58         # .zit/file.git or .file.git, in that order
59         # if neither is found, and .zit exists, set the repo dir
60         # to .zit/file.git, otherwise set it to .file.git
61         GIT_DIR="$ZIT_DIR/$ZIT_FILE.git"
62         if ! test -d "$GIT_DIR"; then
63                 GIT_DIR=".$ZIT_FILE.git"
64                 if ! test -d "$GIT_DIR"; then
65                         test -d "$ZIT_DIR" && GIT_DIR="$ZIT_DIR/$ZIT_FILE.git"
66                 fi
67         fi
68         export GIT_DIR
69 }
70
71 zit_init() {
72         if test "$1"; then
73                 zit_setup $1
74                 test -e $GIT_DIR && abort "$GIT_DIR exists, is $ZIT_FILE tracked already?"
75                 mkdir $GIT_DIR && echo "Initializing Zit repository in $GIT_DIR"
76                 test -d $GIT_DIR || abort "Failed to create $GIT_DIR"
77                 git init || abort "Failed to initialize Git repository in $GIT_DIR" 
78                 rm -rf $GIT_DIR/{hooks,info,branches,refs/tags,objects/pack,description}
79                 if test -d "$ZIT_DIR"; then
80                         ZIT_EXCLUDE="$ZIT_DIR/exclude"
81                 else
82                         ZIT_EXCLUDE="$GIT_DIR/exclude"
83                 fi
84                 if ! test -f "$ZIT_EXCLUDE"; then
85                         touch "$ZIT_EXCLUDE" || abort "Cannot create $ZIT_EXCLUDE file"
86                         echo "# Ignore patterns used by Zit repositories in the parent worktree." > "$ZIT_EXCLUDE"
87                         echo "# By default it's the single '*' glob, since we want to ignore all" >> "$ZIT_EXCLUDE"
88                         echo "# non-tracked files in the work-tree." >> "$ZIT_EXCLUDE"
89                         echo "# This file is autogenerated and there's usually no need to edit it." >> "$ZIT_EXCLUDE"
90                         echo "*" >> "$ZIT_EXCLUDE"
91                 fi
92                 git config core.excludesfile "$ZIT_EXCLUDE"
93                 git add -f $ZIT_FILE || abort "Failed to add $ZIT_FILE"
94                 git commit "$@" || abort "Failed to make first commit for $ZIT_FILE"
95         else
96                 if test -d "$ZIT_DIR"; then
97                         echo "$ZIT_DIR exists already"
98                         exit
99                 fi
100                 test -e $ZIT_DIR && abort "$ZIT_DIR exists but it's not a directory, cannot continue"
101                 mkdir $ZIT_DIR
102         fi
103 }
104
105 zit_list() {
106         export GIT_WORK_TREE="`pwd`"
107         GIT_DIR=""
108         for file in "$ZIT_DIR"/*.git .*.git; do
109                 if ! test -e $file; then
110                         continue
111                 fi
112                 export GIT_DIR="$file"
113                 file="${file#.}"
114                 file="${file#zit/}"
115                 file="${file%.git}"
116                 (git ls-files -m -d -t; git ls-files -t) | uniq -f 1
117         done;
118         # if $GIT_DIR is empty, no files were found
119         test "$GIT_DIR" || echo "(no files tracked by zit)"
120 }
121
122 case $cmd in
123         "")
124         echo $USAGE
125         ;;
126         help)
127         zit_help "$@"
128         ;;
129         init|track)
130         zit_init $1
131         ;;
132         list|tracked)
133         zit_list
134         ;;
135         # Most commands will work with the generic catch-all mechanism used
136         # below, but some of them require a more thorough analysis of the
137         # parameters to decide whether $ZIT_FILE should be put back into the
138         # parameter list or not. For example,
139         # $ zit commit somefile
140         # wouldn't do what one expects it to do, unless 'add' is run first,
141         # (except that
142         # $ zit add somefile
143         # wouldn't work either), however
144         # $ zit commit somefile -a
145         # would work correctly. So we handle some commands separately (for the
146         # moment just add and commit)
147         add|commit)
148         zit_setup $1
149         shift
150         git $cmd "$@" "$ZIT_FILE"
151         ;;
152         # the raw<command> method can be used to not replicate $ZIT_FILE in the
153         # parameter list
154         raw*)
155         zit_setup $1
156         shift
157         git ${cmd#raw} "$@"
158         ;;
159         *)
160         zit_setup $1
161         shift
162         git $cmd "$@"
163         ;;
164 esac