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