Further work towards use of win32 file HANDLEs
[sbcl.git] / doc / GIT-FOR-SBCL-HACKERS.txt
1 Git For SBCL Hackers
2 ====================
3
4 Git is structured as a ton of programs called git-foo, accessible
5 either directly, or as "git foo". Commands "git help" and "git help
6 foo" provide the documentation -- which is there also as the manual
7 pages.
8
9 Make sure you have Git 1.5.something.
10
11 When running on tty the commands pipe their output through less
12 automatically, so you don't need to mentally add "| less" anywhere.
13
14 Let's get started. First off, we need a gitified SBCL repository to
15 clone. At the time of writing there are two Git mirrors for the CVS
16 history:
17
18  git://sbcl.boinkor.net/sbcl.git
19
20 and
21
22  git://repo.or.cz/sbcl.git
23
24 but the latter is actually a mirror of the first one, so it doesn't
25 matter which one you use, really.
26
27 The command
28
29  git clone git://sbcl.boinkor.net/sbcl.git sbcl-git
30
31 clones the SBCL Git mirror into the directory sbcl-git (there's a
32 naming convention in play here, but ignore that for now.) The clone
33 contains full history, and is an independent repository on its own
34 right. Doing the clone takes as long as downloading 25Mb takes on your
35 line, but after that things are very fast.
36
37 To update your clone from the original source at a later date, use
38 git-pull. Go ahead and try out now, to see that it works, and see how
39 snazzy a no-op pull is.
40
41  git pull
42
43 The directory .git inside the clone contains Git's view of the
44 repository -- no other Git files or directories are in the tree. Just
45 for kicks:
46
47  cd sbcl-git
48  rm -rf *                # leaves .git alone
49  time git reset --hard   # this takes < 2 seconds, restores everything
50
51 So, two commands so far:
52
53  git-clone
54    One-time operation to clone a repository.
55
56  git-reset
57    Used to restore state: using the --hard flag resets the entire tree
58    to the state of the last commit but doesn't delete new files which
59    may be in the tree. (It doesn't actually "restore state", or rather
60    does it as a side, effect, but you can learn the details on your
61    own.)
62
63 Let's hack a bit.
64
65  git branch hack-a-bit   # creates a new branch called "hack-a-bit"
66  git branch              # shows all branches and tells which one is active
67  git checkout hack-a-bit # switches to the "hack-a-bit" branch
68  git branch              # shows that we're now on "hack-a-bit"
69
70 Once you get your bearings you can do the create-branch-and-checkout
71 in one step, which you will be doing a lot, since branches are really
72 nice in Git! The magic is: "git checkout -b hack-a-bit-more" -- but
73 leave that for another time.
74
75 Let's do something. Edit BUGS, and maybe give SBCL some love.
76
77  git diff                # shows you the changes in your tree
78  git status              # shows you the state of files in the tree
79
80 git-status will tell you that some files have been modified, but it
81 has "no changes added to commit". If you tried git-commit right now,
82 nothing would happen. What's going on?
83
84 Git has a notion of a separate "staging area", from which commits are
85 made. You can add content to the it by using git-add:
86
87  git add BUGS
88  git status
89  git diff
90
91 Now git-status shows changes as part of a pending commit, but git-diff
92 is silent!
93
94 By default git-diff shows the differences between the working tree and
95 the staging area (which starts out identical to HEAD after a checkout).
96
97 Edit BUGS again. Now you have three versions of it (ignoring all the
98 historical versions for a second) to compare:
99
100  git diff               # between tree and staging area
101  git diff HEAD          # between tree and last commit
102  git diff --cached      # between staging area and last commit
103
104 If we were to do a git-commit now, it would commit the version in the
105 staging area, not the one in the tree.
106
107 We like our latest version, so do
108
109  git add BUGS
110
111 again. Now the latest version is in the staging area, and version that
112 used to be there is gone. You don't need to worry about the staging
113 area. Either you will find out that it's pretty neat (consider it a
114 temporary commit), or you can mostly ignore it. Do
115
116  git commit
117
118 now, and we'll move on in a second. Just to call spade a spade, the
119 staging area is really called "index".
120
121 Now, our changes are in the repository, and git-status should show a
122 clean tree. (By the way, can you imagine how long all the diffs and
123 statuses you've done during this tutorial would have taken with CVS?)
124
125 To get the differences between your current branch, and the master
126 branch, do
127
128  git diff master
129
130 To view the last commit on master, do
131
132  git diff master^..master
133
134 To view the commit logs, do
135
136  git log
137
138 You'll see long hex-string at the head of each commit. This is the
139 commit id, which is a SHA1 hash based on the content of the tree, so
140 you can share these with other hackers, and they can use the same
141 commit id to poke at their own repositories. Locally any unique prefix
142 of the hash is enough to identify a commit, so you don't need to use
143 the full hashes.
144
145 This is where the fun starts. Pick an interesting looking commit a
146 while back, copy the commit id, and do
147
148  git diff <<paste commit id here>>
149
150 Git will show you all the changes between the commit you selected and
151 current version as a single diff. Similarly,
152
153  git diff -w <<commit id 1>> <<commit id 2>>
154
155 can be used to compare two arbitrary versions. The -w switch tells Git
156 to ignore whitespace changes -- you can usually leave it out, but it's
157 nice when diffing across the great whitespacification patches.
158
159 Onwards: just so that we have a bit more history on the branch, edit
160 BUGS again, and git-commit again. You can use
161
162  git commit -a
163
164 to automatically add all the changed files to the staging area to
165 speed things up. Repeat. Now git-log should show a few local changes.
166
167 Let's see how merging works. To create a new branch based on master
168 and switch to it do
169
170  git checkout -b merge-experiment master
171
172 Merge the changes we did on the hack-a-bit branch.
173
174  git merge hack-a-bit
175
176 Bing-bada-bing! Done. Have a look at git-log. You see that we have
177 full branch history merged. If there had been conflicts, the merge
178 would not have been automatic, but you would have been called to
179 resolve conflicts, etc.
180
181 This is very nice for merging short-lived local branches, but not
182 always so good for merging things back onto master, or into "mainline"
183 history since you get all the commits that happened on the branch:
184
185   "first cut at x"
186   "first cut at y"
187   "oops, x was wrong"
188   "implemented z"
189   "aargh, x was still wrong"
190   ...
191
192 When merging a branch like this, with oopses in the history, it is far
193 better if we are able to merge it as a few logical patches -- the
194 resulting history will be easier to understand.
195
196 First option is to use --squash to squash all the commits into a
197 single one.
198
199  git checkout -b merge-experiment-2 master
200  git merge --squash hack-a-bit
201
202 This has the side-effect of not committing the changes immediately.
203
204 This is in effect similar to the usual way of merging back changes
205 from a CVS branch: if we're told that the patch came from a branch, we
206 can then go and look at the branch history, but we don't see the
207 evolution of the branch in the mainline history.
208
209 If the changeset is small, --squash is exactly what we want, but for
210 long-lived branches that are best merged in a few steps we can use
211
212  git merge --squash <<commit id>>
213
214 to merge the changes upto a certain commit. Repeat a few times, and
215 you have the whole branch merged. Other Git commands provide more
216 advanced options. See eg. git-cherry-pick, which you will end up
217 using sooner or later.
218
219 Now, let's assume we have a private Git repository in ~/sbcl-git, and
220 we want to publish it to the world. The easiest way is to fire up a
221 browser, and go to
222
223  http://repo.or.cz/w/sbcl.git
224
225 There, click on the "fork" link, and set up your own SBCL repository,
226 called sbcl/yourname. Select the "push" mode, and write something
227 along the lines of "My private SBCL tree. Pulls from main sbcl.git
228 repository, and trickles changes back to upstream CVS manually --
229 from where they end up in sbcl.git. Turtles, you see." in the comment
230 box. Then you will be directed to set up an account, which you will
231 then have to add as a "pusher" to your SBCL fork.
232
233 Finally, add the following snippet (adjusting for your own name) in
234 ~/sbcl-git/.git/config
235
236  [remote "public"]
237         url = git+ssh://repo.or.cz/srv/git/sbcl/yourname.git
238
239 After that is done, you're ready to publish your tree.
240
241  git push --all public
242
243 Now anyone can get at your repository at
244
245  git://repo.or.cz/sbcl/yourname.git
246
247 and you can publish your own hacks on it via git-push.
248
249  git push public <<name of branch to update>>
250
251 Since we're not (yet?) officially using Git, we want to get our
252 changes back into the CVS. git-cvsexport is the perfect tool for this.
253
254 First, to make things a bit easier, we add a command of our own to
255 Git, by adding the following to ~/sbcl-git/.git/config:
256
257  [alias]
258         sbcl-export = cvsexportcommit -w /home/yourname/sbcl-cvs -v
259
260 This assumes that you have a developer CVS checkout in ~/sbcl-cvs.
261
262 To commit the the changes you have wrought on branch foo-hacks
263 (compared to master):
264
265  # These three steps could be replaced by any other sequence that
266  # ends with all the changes you want to export to CVS at the top
267  # of the current branch (so that the final commit introduces all
268  # the changes.)
269  #
270  # In practice for small changes you may eg. just want to
271  #
272  #    git checkout -b wip-fix-bug-xxx master
273  #    ...fix bug on the branch...
274  #    git commit -a
275  #
276  git checkout -b foo-hacks-to-cvs master
277  git merge --squash foo-hacks
278  git commit -a
279
280  # This exports our stuff to the CVS tree. HEAD can be any <<commit id>>,
281  # so if you have a large number of commits on a branch that you want to
282  # commit to CVS one by one, you do that as well.
283  git sbcl-export HEAD
284
285  cd ../sbcl-cvs
286
287  Review, fix problems, etc. Edit version.lisp-expr, and add the
288  version number to .msg (which contains the commit message from Git.)
289
290  cvs commit -F .msg
291
292 git-cvsexportcommit is fairly conservative by default, and will fail
293 if the patch doens't apply cleanly. If that happens, you can fix the
294 issues manually:
295
296  .cvsexportcommit.diff   -- holds the patch
297  .msg                    -- holds the commit message
298
299 Finally, delete the foo-hacks-to-cvs branch after you've committed
300 code to CVS. Of course, instead of using git-cvsexportcommit you can
301 also manually make and apply patches, etc. For hairier cases it may
302 even be easier in the end:
303
304   git format-patch -p master..foo-hacks
305
306 Generates a patch for each commit between master and the HEAD of
307 foo-hacks, naming them
308
309   0001-first-line-of-commit-message.patch
310   0002-and-so-and-so-forth.patch
311   ...
312
313 Due to, among other things, the cvs->git synchronization lag it is
314 easy to get conflicts on version.lisp-expr so generally speaking you
315 never want to edit version-lisp.expr in Git, and only edit it (and add
316 the version to the commit message) just when you are about to commit
317 to CVS. It is, however, nice to have an idea how a given image came to
318 be, which you can take care of by putting the following code in
319 branch-version.lisp-expr:
320
321  #.(flet ((git (command &rest args)
322             (with-output-to-string (s)
323               ;; Adjust for your git installation location...
324               (sb-ext:run-program (merge-pathnames "bin/git" (user-homedir-pathname))
325                                   (cons command args) :output s))))
326      (format nil "~A.~A~@[-dirty~]"
327              (with-input-from-string (s (git "branch"))
328                (loop for line = (read-line s)
329                      when (eql #\* (char line 0))
330                      return (subseq line 2)))
331              (count #\newline (git "rev-list" "HEAD...master"))
332              (plusp (length (git "diff" "HEAD")))))
333
334 which leads to your Git tree build to have version names like
335
336   1.0.20.28.master.0-dirty
337
338     1.0.20.28 on branch master, uncommitted changes
339
340   1.0.20.19.wip-foo.4
341
342     1.0.20.19 on branch wip-foo, 4 commits between current HEAD and
343     master, no uncommitted changes.
344
345 To get latest changes from the CVS Git mirror you originally cloned
346 from, do
347
348   git pull
349
350 on the branch you want to update on your private repository.
351
352 Note that if you edit version.lisp-expr in the CVS tree and not before
353 then the cvs commit command that git-cvsexportcommit prints does not
354 list version.lisp-expr, so don't copy paste it.
355
356 This completes our whirlwind tour. I'm not saying this makes you
357 proficient in using Git, but at least you should be up and walking.
358 Reading
359
360  http://eagain.net/articles/git-for-computer-scientists/
361  http://www.kernel.org/pub/software/scm/git/docs/everyday.html
362  http://www.kernel.org/pub/software/scm/git/docs/user-manual.html
363
364 and various Git manual pages is a good idea.
365
366 Two commands I can in particular recommend getting familiar with are
367 git-rebase and git-cherry-pick.
368
369 git-gui, git-citool, and gitk provide graphical interfaces for
370 working with Git -- particularly gitk is an invaluable tool for
371 visualizing history.