chiark / gitweb /
stg-cvs: update doc, and use correct setting for parent branch.
[stgit] / contrib / stg-cvs
1 #!/bin/bash
2 set -e
3
4 # stg-cvs - helper script to manage a mixed cvs/stgit working copy.
5
6 # Allows quick synchronization of a cvs mirror branch (does not try to
7 # reconstruct patchsets, creates "jumbo" commits), and commits stgit
8 # patches to CVS.
9
10 # Copyright (c) 2007 Yann Dirson <ydirson@altern.org>
11 # Subject to the GNU GPL, version 2.
12
13 # NOTES
14 # - you want to add a "CVS" line to .git/info/exclude
15 # - you may want to add a ".git" line to the top .cvsignore
16
17 # BRANCH INIT
18 # - ensure the cvs wc is clean (eg. with "cvsco")
19 # $ git init
20 # $ echo CVS >> .git/info/exclude
21 # $ git add .
22 # $ git commit -m "Initial import."
23 # $ git branch -m master cvs
24 # $ stg branch -c master cvs
25 # $ git config branch.master.stgit.parentbranch cvs (0.12.1 and earlier only)
26 # $ git config branch.cvs.description "CVS $(cat CVS/Root) $(cat CVS/Repository) $(cat CVS/Tag 2>/dev/null | echo HEAD)"
27 # $ git config branch.master.description "Changes for $(cat CVS/Repository) $(cat CVS/Tag 2>/dev/null | echo HEAD)"
28
29 # LIMITATIONS
30 # - this is only a proof-of-concept prototype
31 # - lacks an "init" command (see above)
32 # - "commit" does not ensure the base is uptodate before trying to
33 #   commit (but hey, it's CVS ;): better "stg-cvs pull" first
34 # - "commit" can only commit a single patch
35 # - not much robustness here
36 # - still no support for files removed in cvs (should catch "no
37 #   longer in the repository" message)
38 # - this only deals with CVS but could surely be extended to any other
39 #   VCS
40 # - lacks synchronisation of .cvsignore <-> .gitignore
41 # - no support for filenames with spaces (stg lacks --zero output format)
42 # - git-commit is too chatty when it finds nothing to commit
43 # - lacks a "quick cvs commit" feature
44
45 # DESIGN FLAWS
46 # - while fetching, if a file change was not git-update-index'd when
47 #   cvs-update'd (eg. because of a stg-cvs bug), it is not seen on further
48 #   fetches until it changes again, since we scan "cvs update" output.
49 #   This yields possible inconsistencies with CVS.
50 # - similarly, any conflict while cvs-updating (whether due to illegal
51 #   changes to the cvs-mirror-branch, or due to files added to cvs but
52 #   already-existing in working copy, or to directory moves inside the
53 #   cvs repository, or <fill here>) has to be dealt with by hand (although
54 #   the situation is better here: cvs sees the conflict on subsequent tries)
55 # - bad/no support for cvsutils:
56 #   - stg push/pop operations confuse cvsu because of timestamp changes
57 #   - cvspurge/cvsco would nuke .git => does not make it easy to ensure
58 #     synchronisation
59 # - should use a separate workspace for cvs branch like tailor does
60 # - confused by cvs keyword substitution
61
62 usage()
63 {
64     [ "$#" = 0 ] || echo "ERROR: $*"
65     echo "Usage: $(basename $0) <command>"
66     echo " commands: $(do_commands)"
67     exit 1
68 }
69
70 do_commands()
71 {
72     echo $(grep '^[a-z-]*)' $0 | cut -d')' -f1)
73 }
74
75 do_fetch()
76 {
77     local return=0
78     local path
79
80     local parent="$1"
81     local branch="$2"
82
83     # record changes from cvs into index
84     stg branch "$parent" || exit $?
85     cvs -fq update -dP | grep -v '^\? ' | tee /dev/tty | while read status path; do
86         if [ -e "$path" ]; then
87             git update-index --add "$path" || exit $?
88         else
89             git update-index --remove "$path" || exit $?
90         fi
91         # cvs update: `FELIN1_PEP/src/java/com/sagem/felin/ui/widget/PEPRifStateIcon.java' is no longer in the repository
92     done
93
94     # create commit
95     if git commit -m "stg-cvs sync"; then
96         :
97     else
98         return=$?
99     fi
100
101     # back to branch
102     stg branch "$branch" || exit $?
103
104     return $return
105 }
106
107 cvs_add_dir()
108 {
109     local parent=$(dirname "$1")
110     if [ ! -e "$parent/CVS" ]; then
111         cvs_add_dir "$parent"
112     fi
113
114     cvs add "$1"
115 }
116
117 # get context
118 branch=$(stg branch)
119 parent=$(git-config "branch.${branch}.stgit.parentbranch") || 
120     usage "no declared parent for '$branch' - set branch.${branch}.stgit.parentbranch"
121
122 # extract command
123
124 [ "$#" -ge 1 ] || usage
125 command="$1"
126 shift
127
128 case "$command" in
129 fetch)
130     do_fetch "$parent" "$branch"
131     ;;
132
133 pull)
134     if do_fetch "$parent" "$branch"; then
135         # update
136         #  --merged
137         stg rebase "$parent"
138         stg clean --applied
139     fi
140     ;;
141
142 commit)
143     # sanity asserts
144     [ $(stg applied | wc -l) = 1 ] ||
145         usage "you don't have exactly one patch applied"
146
147     # context
148     patch=$(stg top)
149     
150     # adds
151     stg files | grep ^A | cut -c3- | while read file; do
152         parent=$(dirname "$file")
153         if [ ! -e "$parent/CVS" ]; then
154             cvs_add_dir "$parent"
155         fi
156         cvs -f add "$file"
157     done
158
159     # removes
160     stg files | grep ^D | cut -c3- | xargs -r cvs -f remove
161
162     # commit
163     stg files --bare | xargs -r cvs -fq commit \
164         -F ".git/patches/$branch/patches/$patch/description"
165
166     # sync the parent branch
167     stg branch "$parent"
168     git-cherry-pick "patches/${branch}/${patch}"
169     stg branch "${branch}"
170
171     # update
172     # --merged
173     stg rebase "$parent"
174     stg clean --applied
175     ;;
176
177 _commands)
178     # hint for bash-completion people :)
179     do_commands
180     ;;
181
182 *)
183     usage "unknown command '$command'"
184     ;;
185 esac