· 9 years ago · May 22, 2017, 08:08 PM
1What readers are saying about
2Pragmatic Version Control using Subversion
3I expected a lot, but you surprised me with even more. Hav-
4ing used CVS for years I hesitated to try Subversion until
5now, although I knew it would solve many of the shortcom-
6ings of CVS. After reading your book, my excuses to stay
7with CVS disappeared. Oh, and coming from the Pragmatic
8Bookshelf this book is fun to read too. Thanks Mike.
9Steffen Gemkow
10Managing Director, ObjectFab GmbH
11I’m a long-time user of CVS and I’ve been skeptical of Sub-
12version, wondering if it would ever be “ready for prime time.â€
13Until now. Thanks to Mike Mason for writing a clear, con-
14cise, gentle introduction to this new tool. After reading this
15book, I’m actually excited about the possibilities for version
16control that Subversion brings to the table.
17David Rupp
18Senior Software Engineer, Great-West Life & Annuity
19This was exactly the Subversion book I was waiting for. As
20a long-time Perforce and CVS user and administrator, and
21in my role as an agile tools coach, I wanted a compact book
22that told me just what I needed to know. This is it.
23Within a couple of hours I was up and running against
24remote Subversion servers, and setting up my own local
25servers too. Mike uses a lot of command-line examples to
26guide the reader, and as a Windows user I was worried at
27first. My fears were unfounded though—Mike’s examples
28were so clear that I think I’ll stick to using the command line
29from now on! I thoroughly recommend this book to anyone
30getting started using or administering Subversion.
31Mike Roberts
32Project co-Lead, CruiseControl.NET
33Pragmatic Version Control
34using Subversion, 2nd Edition
35Mike Mason
36The Pragmatic Bookshelf
37Raleigh, North Carolina Dallas, Texas
38?? ?????
39?
40?
41?
42?
43?
44?
45Many of the designations used by manufacturers and sellers to distinguish
46their products are claimed as trademarks. Where those designations appear
47in this book, and The Pragmatic Programmers, LLC was aware of a trademark
48claim, the designations have been printed in initial capital letters or in all
49capitals. The Pragmatic Starter Kit, The Pragmatic Programmer, Pragmatic
50Programming, Pragmatic Bookshelf and the linking g device are trademarks
51of The Pragmatic Programmers, LLC.
52Every precaution was taken in the preparation of this book. However, the
53publisher assumes no responsibility for errors or omissions, or for damages
54that may result from the use of information (including program listings) con-
55tained herein.
56Our Pragmatic courses, workshops, and other products can help you and
57your team create better software and have more fun. For more information,
58as well as the latest Pragmatic titles, please visit us at
59http://www.pragmaticprogrammer.com
60Copyright © 2006 The Pragmatic Programmers LLC.
61All rights reserved.
62No part of this publication may be reproduced, stored in a retrieval system,
63or transmitted, in any form, or by any means, electronic, mechanical, photo-
64copying, recording, or otherwise, without the prior consent of the publisher.
65Printed in the United States of America.
66ISBN 0-9776166-5-7
67Printed on acid-free paper with 85% recycled, 30% post-consumer content.
68First printing, May 2006
69Version: 2006-5-12
70Contents
71Preface viii
721 Introduction 1
731.1 Version Control in Action . . . . . . . . . . . . . 2
741.2 Road Map . . . . . . . . . . . . . . . . . . . . . . 6
751.3 Why Choose Subversion . . . . . . . . . . . . . . 6
762 What is Version Control? 9
772.1 The Repository . . . . . . . . . . . . . . . . . . . 9
782.2 What Should We Store? . . . . . . . . . . . . . . 11
792.3 Working Copies and Manipulating Files . . . . . 12
802.4 Projects, Directories, and Files . . . . . . . . . . 15
812.5 Where Do Versions Come In? . . . . . . . . . . . 16
822.6 Tags . . . . . . . . . . . . . . . . . . . . . . . . . 18
832.7 Branches . . . . . . . . . . . . . . . . . . . . . . 19
842.8 Merging . . . . . . . . . . . . . . . . . . . . . . . 22
852.9 Locking Options . . . . . . . . . . . . . . . . . . 23
862.10 Configuration Management (CM) . . . . . . . . . 26
873 Getting Started with Subversion 28
883.1 Installing Subversion . . . . . . . . . . . . . . . 28
893.2 Creating a Repository . . . . . . . . . . . . . . . 33
903.3 Creating a Simple Project . . . . . . . . . . . . . 34
913.4 Starting to Work with a Project . . . . . . . . . . 37
923.5 Making Changes . . . . . . . . . . . . . . . . . . 39
933.6 Updating the Repository . . . . . . . . . . . . . . 41
943.7 When Worlds Collide . . . . . . . . . . . . . . . . 44
953.8 Conflict Resolution . . . . . . . . . . . . . . . . . 47
96CONTENTS vi
974 How To... 52
984.1 Our Basic Philosophy . . . . . . . . . . . . . . . 53
994.2 Important Steps When Using Version Control . 53
1005 Accessing a Repository 55
1015.1 Network Protocols . . . . . . . . . . . . . . . . . 55
1025.2 Choosing a Networking Option . . . . . . . . . . 60
1036 Common Subversion Commands 62
1046.1 Checking Things Out . . . . . . . . . . . . . . . 62
1056.2 Keeping Up-to-Date . . . . . . . . . . . . . . . . 64
1066.3 Adding Files and Directories . . . . . . . . . . . 66
1076.4 Properties . . . . . . . . . . . . . . . . . . . . . . 66
1086.5 Copying and Moving Files and Directories . . . 75
1096.6 Seeing What Has Changed . . . . . . . . . . . . 80
1106.7 Handling Merge Conflicts . . . . . . . . . . . . . 86
1116.8 Committing Changes . . . . . . . . . . . . . . . 91
1126.9 Examining Change History . . . . . . . . . . . . 91
1136.10 Removing a Change . . . . . . . . . . . . . . . . 95
1147 File Locking and Binary Files 99
1157.1 File Locking Overview . . . . . . . . . . . . . . . 99
1167.2 File Locking in Practice . . . . . . . . . . . . . . 100
1177.3 When to use Locking . . . . . . . . . . . . . . . . 106
1188 Organizing Your Repository 107
1198.1 A Simple Project . . . . . . . . . . . . . . . . . . 107
1208.2 Multiple Projects . . . . . . . . . . . . . . . . . . 108
1218.3 Multiple Repositories . . . . . . . . . . . . . . . 109
1229 Using Tags and Branches 111
1239.1 Tags and Branches . . . . . . . . . . . . . . . . . 112
1249.2 Creating a Release Branch . . . . . . . . . . . . 115
1259.3 Working in a Release Branch . . . . . . . . . . . 117
1269.4 Generating a Release . . . . . . . . . . . . . . . 119
1279.5 Fixing Bugs in a Release Branch . . . . . . . . . 121
1289.6 Developer Experimental Branches . . . . . . . . 124
1299.7 Working with Experimental Code . . . . . . . . 126
1309.8 Merging the Experimental Branch . . . . . . . . 126
131CONTENTS vii
13210 Creating a Project 128
13310.1 Creating the Initial Project . . . . . . . . . . . . 129
13410.2 Structure within the Project . . . . . . . . . . . 131
13510.3 Sharing Code between Projects . . . . . . . . . . 135
13611 Third-Party Code 141
13711.1 Binary Libraries . . . . . . . . . . . . . . . . . . 141
13811.2 Libraries with Source Code . . . . . . . . . . . . 144
13911.3 Keyword Expansion during Imports . . . . . . . 150
140A Install, Network, Secure, and Administer 151
141A.1 Installing Subversion . . . . . . . . . . . . . . . 151
142A.2 Networking with svnserve . . . . . . . . . . . . . 153
143A.3 Networking with svn+ssh . . . . . . . . . . . . . 154
144A.4 Networking with Apache . . . . . . . . . . . . . . 157
145A.5 Securing Subversion . . . . . . . . . . . . . . . . 163
146A.6 Backing Up Your Repository . . . . . . . . . . . 170
147B Migrating to Subversion 174
148B.1 Getting cvs2svn . . . . . . . . . . . . . . . . . . . 175
149B.2 Choosing How Much to Convert . . . . . . . . . 175
150B.3 Converting Your Repository . . . . . . . . . . . . 176
151C Third-Party Subversion Tools 178
152C.1 TortoiseSVN . . . . . . . . . . . . . . . . . . . . . 178
153C.2 IDE Integration . . . . . . . . . . . . . . . . . . . 185
154C.3 Other Tools . . . . . . . . . . . . . . . . . . . . . 186
155D Advanced Topics 188
156D.1 Programmatic Access to Subversion . . . . . . . 188
157D.2 Advanced Repository Management . . . . . . . 193
158E Command Summary and Recipes 197
159E.1 Subversion Command Summary . . . . . . . . . 197
160E.2 Recipes . . . . . . . . . . . . . . . . . . . . . . . 208
161F Other Resources 214
162F.1 Online Resources . . . . . . . . . . . . . . . . . . 214
163F.2 Bibliography . . . . . . . . . . . . . . . . . . . . 215
164Preface
165I was pretty excited when I heard about the Pragmatic Starter
166Kit—finally some guidance on the basic stuff all projects need
167to get right. The opportunity to produce a Subversion edition
168of Pragmatic Version Control was one I couldn’t miss. Sub-
169version had previously saved me (and my team) from version
170control hell, and I wanted to do my part to help promote a
171great new version control system.
172Version control adds an immense amount to a project. It gives
173you a safety net, helps your team collaborate effectively, lets
174you organize your builds and QA, and even allows you to do
175some detective work if things go wrong. I hope this new edition
176of Pragmatic Version Control will help you and your team get
177started and succeed with Subversion.
178Acknowledgments
179I’d like to thank Dave and Andy for taking a chance on my
180writing the book and to thank Dave for being such an excellent
181editor. I wasn’t really sure what I was getting myself into, and
182Dave’s advice and guidance were invaluable.
183The book received plenty of scrutiny by reviewers; I’d like to
184thank Brad Appleton, Branko
185ˇ
186Cibej, Martin Fowler, Steffen
187Gemkow, Robert Rasmussen, Mike Roberts, and David Rupp
188for their well-thought-out comments and suggestions. I’m
189frankly amazed by the quality of feedback I got—great sugges-
190tions, highly technical comments and plenty of people think-
191ing about the “bigger picture.â€
192Everyone at ThoughtWorks has been really supportive of my
193book writing efforts, including several people who took the
194time to look through early drafts of the book, and I’d like to
195P REFACE ix
196thank all those who gave me advice and guidance. I’d particu-
197larly like to thank the Calgary office for welcoming me into the
198fold this year and for enabling me to get stuff finished when
199the crunch point came.
200Finally I’d like to thank Martin, Mike, and Michelle for making
201me believe I could really write the book and for their encour-
202agement along the way.
203December 2004
204Acknowledgments for the Second Edition
205Subversion has come a long way since the first edition of this
206book. It has new features, performance and stability improve-
207ments, and most importantly has excellent integration with
208many leading tools and IDEs. Subversion is now probably
209the number one version control tool in use on ThoughtWorks
210projects and is a serious competitor to every commercial tool
211on the market.
212I’d like to thank everyone who has given me support and feed-
213back since the publication of the original book. It’s very grat-
214ifying to know people have used the book, enjoyed reading it,
215and that Subversion has brought them success. Please keep
216the feedback coming, it’s invaluable.
217The following people generously contributed time reading the
218updated manuscript, and provided fantastic feedback: Steve
219Berczuk, Nick Coyne, David Rupp and Nate Schutta. Thank
220you all for your time, effort, and great ideas.
221I’d like to thank Dave and Andy for the opportunity to update
222the book to cover new features in Subversion, and in partic-
223ular I’d like to thank Andy for taking on the editor’s job this
224time around. As I’ve told many friends and colleagues, a good
225editor is a crucial part of the writing process, and I feel very
226lucky to have worked with both Andy and Dave.
227Mike Mason
228May 2006
229mike@mikemason.ca
230P REFACE x
231Typographic Conventions
232italic font Italics indicate a term that is being defined, or
233borrowed from another language.
234files Files (and directories ) are indicated like this.
235commands Commands (and options such as -h ) are shown
236like this.
237output Output (as well as things you might need to type)
238is indicated like this. If commands are too long
239for a single line they’re split onto multiple lines
240using a \ (backward slash).
241CVS Hint: This kind of text indicates a hint for users famil-
242iar with CVS.
243This warning sign indicates this material is more
244advanced and can be skipped on your first read-
245ing.
246“Joe the developer,†our cartoon friend, asks a
247related question that you may find useful.
248Chapter 1
249Introduction
250This book tells you how to improve the effectiveness of your
251software development process using version control.
252Version control, sometimes called source code control, is the
253first leg of our project support tripod. We view the use of
254version control as mandatory on all projects.
255Version control offers many advantages to both teams and
256individuals:
257• It gives the team a project-wide undo button; nothing is
258final, and mistakes are easily rolled back. Imagine you’re
259using the world’s most sophisticated word processor. It
260has every function imaginable, except one. For some rea-
261son, they forgot to add support for a DELETE key. Think
262how carefully and slowly you’d have to type, particularly
263as you got near the end of a large document. One mis-
264take, and you’d have to start again. It’s the same with
265version control; having the ability to go back an hour, a
266day, or a week frees your team to work quickly, confident
267that they have a way of fixing mistakes.
268• It allows multiple developers to work on the same code
269base in a controlled manner. The team no longer loses
270changes when someone overwrites the edits made by
271another team member.
272• The version control system keeps a record of the changes
273made over time. If you come across some “surprising
274code,†it’s easy to find out who made the change, when,
275and (with any luck) why.
276V ERSION C ONTROL IN A CTION 2
277• A version control system allows you to support multiple
278releases of your software at the same time as you con-
279tinue with the main line of development. With a version
280control system, there’s no longer a need for the team to
281stop work during a code freeze just before release.
282• Version control is a project-wide time machine, allowing
283you to dial in a date and see exactly what the project
284looked like on that date. This is useful for research,
285but it is essential for regenerating prior releases for cus-
286tomers with problems.
287This book focuses on version control from a project perspec-
288tive. Rather than simply list the commands available in a
289version control system, we explain the tasks you need to per-
290form well in a successful project and then show how a version
291control system can help.
292Let’s start with a small story....
2931.1 Version Control in Action
294Fred rolls into the office eager to continue working on the new
295Orinoco book ordering system. (Why Orinoco? Fred’s com-
296pany uses the names of rivers for all internal projects.) After
297getting his first cup of coffee, Fred updates his local copy of
298the project’s source code with the latest versions from the cen-
299tral version control system. In the log that lists the updated
300files, he notices that Wilma has changed code in the basic
301Orders class. Fred gets worried that this change might affect
302his work, but today Wilma is off at the client’s site, installing
303the latest release, so he can’t ask her directly. Instead, Fred
304asks the version control system to display the notes associ-
305ated with the change to Orders . Wilma’s comment does little
306to reassure him:
307Added new deliveryPreferences field to the Orders class
308To find out what’s going on, he goes back to the version con-
309trol system and asks to see the actual changes made to the
310source file. He sees that Wilma has added a couple of instance
311variables, but they are set to default values, and nothing
312seems to change them. This might be a problem in the future,
313but it is nothing that will stop him today, so Fred continues
314working.
315V ERSION C ONTROL IN A CTION 3
316As he works on his code, Fred adds a new class and a cou-
317ple of test classes to the system. Fred adds the names of the
318files he creates to the version control system as he creates
319them; the files themselves won’t be added until he commits
320his changes, but adding their names now means he won’t for-
321get to add them later.
322A couple of hours into the day, Fred has completed the first
323part of some new functionality. It passes its tests, and it won’t
324affect anything in the rest of the system, so he decides to
325check it all into the version control system, making it available
326to the rest of the team. Over the years, Fred has found that
327checking code in and out frequently works best for him: it’s
328a lot easier to reconcile the occasional conflict if you have to
329worry about only a couple of files rather than a week’s worth
330of changes from the whole team.
331Why You Should Never Answer the Phone
332Just as Fred is about to start the next round of coding, his
333phone rings. It’s Wilma, calling from the client’s site. It looks
334like there’s a bug in the release she is installing: printed
335invoices are not calculating sales tax on shipping amounts.
336The client is going ballistic, and they need a fix now.
337...Unless You Use Version Control
338Fred double-checks the name of the release with Wilma and
339then tells the version control system to check out all the files
340in that version of the software. He puts it in a temporary
341directory on his PC, as he intends to delete it after he finishes
342the work. He now has two copies of the system’s source code
343on his computer: the trunk (the main line of development)
344and the version released to the client. Because he is about to
345fix a bug, he tells the version control system to tag his source
346code with a label. (He’ll add another tag when he has fixed
347the bug.) These tags act as flags you leave behind to mark
348significant points in the development. By using consistently
349named tags before and after he makes the change, other folks
350in his team will be able to see exactly what changed should
351they look at it later.
352V ERSION C ONTROL IN A CTION 4
353In order to isolate the problem, Fred first writes a test. Sure
354enough, it looks like no one ever checked the sales tax cal-
355culation when shipping was involved, because his test imme-
356diately shows the problem. (Fred makes a note to raise this
357during this iteration’s review meeting; this is something that
358should never have gone out the door.) Sighing, Fred adds
359the line of code that adds shipping to the taxable total, com-
360piles, and checks that his test passes. He reruns the whole
361test suite as a quick sanity test and checks the fixed code
362back into the central version control system. Finally, he tags
363the release branch indicating that the bug is fixed. He sends
364a note off to QA, who is responsible for shipping emergency
365releases to the client. Using his tag, they’ll be able to instruct
366the build system to produce a delivery disk that includes his
367fix. Fred then phones Wilma and tells her the fix is in the
368hands of QA and should be with her soon.
369Having finished with this little distraction, Fred removes the
370source for the released code from his local machine: there’s
371no point in cluttering things up, and the changes he has made
372are safely tucked back into the central server. He then gets to
373wondering: is the sales tax bug he found in the released code
374also present in the current development version? The quick-
375est way to check is to add the test he wrote in the released ver-
376sion to the development test suite. He tells the version control
377system to merge that particular change in the release branch
378into the appropriate file in the development copy. The merge
379process takes whatever changes were made to the release
380files and makes the same changes to the development ver-
381sion. When he runs the tests, his new test fails: the bug
382is indeed present. He then moves his fix from the release
383branch into the development version. (He doesn’t need the
384release branch’s code on his machine to do any of this; all
385the changes are being fetched from the central version control
386system.) Once he has the tests all running again, he commits
387this change into the version control system. That’s one less
388bug that’ll bite the team next time.
389Crisis over, Fred gets back to working on his own tasks for the
390day. He spends a happy afternoon writing tests and code and
391toward the end of the day decides he is done. While he has
392been working, other folks in his team have also been making
393V ERSION C ONTROL IN A CTION 5
394changes, so he uses the version control system to take their
395work and apply it to his local copy of the source. He runs
396the tests one last time and then checks his changes back in,
397ready to start work the next day.
398Tomorrow...
399Unfortunately, the next day brings its own surprises. Over-
400night Fred’s central heating finally gives up the ghost. As Fred
401lives in Minnesota, and as it’s February, this isn’t something
402to be taken lightly. Fred calls into work to say he’ll be out
403most of the day waiting for the repair folks to arrive.
404However, that doesn’t mean he has to stop working. Accessing
405his office network using a secure connection over the public
406Internet, Fred checks out the latest development code onto
407his laptop. Because he checked in before he went home the
408previous night, everything is there and up-to-date. He con-
409tinues to work at home, wrapped in a blanket and sitting by
410the fire. Before he stops for the day, he checks his changes in
411from the laptop so they’ll be available to him at work the next
412day. Life is good (except for the heating repair bill).
413Storybook Projects
414The correct use of version control on Fred and Wilma’s project
415was pretty unobtrusive, but it gave them control and helped
416them communicate, even when Wilma was miles away. Fred
417could research changes made to code and apply a bug fix to
418multiple releases of their application. Their version control
419system supports offline work, so Fred gained a degree of loca-
420tion independence: he could work from home during his heat-
421ing problems. Because they had version control in place (and
422they knew how to use it), Fred and Wilma dealt with a number
423of project emergencies without experiencing the panic that so
424often characterizes our response to the unexpected.
425Using version control gave Fred and Wilma the control and
426the flexibility to deal with the vagaries of the real world. That’s
427what this book is all about.
428R OAD M AP 6
4291.2 Road Map
430Chapter 2 introduces the concepts and terminology of version
431control systems. Many version control systems are available
432from which to choose. In this book we’re going to focus on
433Subversion, an open-source tool available for free over the
434internet. Subversion is the successor to CVS, which is itself
435one of the most popular version control systems available.
436Chapter 3, Getting Started with Subversion, is a tutorial intro-
437duction to using Subversion. The remainder of the book is a
438set of recipes for using Subversion in projects, divided into six
439main chapters. Each chapter contains a number of recipes:
440• Connecting to Subversion in different ways
441• Using common Subversion commands
442• Organizing files inside Subversion
443• Using tags and branches to handle releases and experi-
444mental code
445• Creating a project
446• Handling third-party code
447We end with a set of appendixes providing reference informa-
448tion and more in-depth discussion on using Subversion:
449• Networking, securing, and backing up your repository
450• Migrating to Subversion
451• Using Third-party Subversion tools
452• Summary of recipes and Subversion commands
453• Using other resources available on the Internet
4541.3 Why Choose Subversion
455Whilst this book is about version control in general, we’re
456choosing to focus on Subversion as our tool of choice. Since a
457significant number of different version control tools are avail-
458able, it’s probably worth mentioning why you’d want to pick
459Subversion.
460W HY C HOOSE S UBVERSION 7
461The Subversion project was started by a team of developers
462who had extensive experience with CVS (some of them had
463literally written books on the subject) but who had decided
464the time had come to replace the aging system. The Subver-
465sion developers were painfully aware of CVS’s shortcomings
466and made sure they designed a high-performance, modern
467version control system. Their goal was not to create a rad-
468ical new paradigm in version control—the CVS development
469model had proven highly successful—but to replace CVS with
470a new system that fixed all of CVS’s wrinkles.
471This might not sound like Subversion is anything ground-
472breaking, but bear in mind that CVS is already miles ahead
473of many other version control tools. Subversion’s feature set
474puts it at the forefront of what’s available today.
475Versioning for Files, Directories, and Metadata
476Directories, as well as files, are versionable objects in Subver-
477sion. This means that moving or renaming a directory is a
478first-class operation—files within the directory automatically
479move with it, and history is preserved correctly.
480Files and directories can also have metadata associated with
481them using Subversion properties. Properties can be textual
482or binary and are versioned in the same way as file con-
483tents, changing over time, being merged with newer revisions,
484etc. Properties are used extensively to control how Subversion
485handles files, keyword expansion, stuff you’d like it to ignore,
486and so on. The great thing about properties is that any Sub-
487version client can access them, allowing third-party tools to
488integrate much more elegantly with your repository.
489Atomic Commits and Changesets
490Subversion uses a database transaction analogy when a user
491commits a change to the repository, making sure that either
492the entire change is successfully committed or it’s aborted
493and rolled back. It’s also impossible to see half a change
494whilst someone is making a commit—you’ll see the state of
495the repository either before the change or after. This behavior
496is known as atomic commit and is useful because every devel-
497oper will always have a consistent view of the repository. If
498W HY C HOOSE S UBVERSION 8
499your network connection goes down whilst you’re committing
500a change, you won’t leave half your changes in the repository,
501and the change will be rolled back cleanly.
502As part of the atomic commit process, Subversion groups all
503of your changes into a revision (sometimes called a changeset) revision
504and assigns a revision number to the change. By grouping
505revision number
506changes to multiple files into a single logical unit, developers
507are able to better organize and track their changes.
508Excellent Networking Support
509Subversion has a highly efficient network protocol and stores
510pristine copies of your working files locally, allowing a user to
511see what changes they’ve made without even contacting the
512server. Subversion provides a variety of networking options,
513including the ability to leverage Secure Shell (SSH) and the
514Apache web server to make repositories available over a public
515network.
516Cheap Branching, Tagging, and Merging
517In many version control systems, creating a branch is a big
518deal. In CVS, for example, branching or labeling code requires
519the server to access and modify every file in the repository!
520Subversion uses an efficient database model to branch and
521merge files, making these operations quick and painless.
522True Cross-Platform Support
523Subversion is available for a wide variety of platforms, and,
524most important, the server will run well on Windows. This
525significantly lowers the barrier to entry for teams that don’t
526have a Unix server available and makes it much easier to get
527started—you can set up a server on a spare Windows box (or
528even one that’s in use!) and migrate to another machine once
529Subversion has proven itself.
530Chapter 2
531What is Version Control?
532A version control system is a place to store all the various revi-
533sions of the stuff you write while developing an application.
534They’re basically very simple. Unfortunately, over the years,
535people have started using different terms for the various com-
536ponents of version control. And this can lead to confusion. So
537let’s start by defining some of the terms we’ll be using.
5382.1 The Repository
539You may have noticed that we wimped out; we said that “a
540version control system is a place to store...the stuff you write,â€
541but we never said exactly where all this stuff is stored. In fact,
542it all goes in the repository. repository
543In almost all version control systems, the repository is a cen-
544tral place that holds the master copy of all versions of your
545project’s files. Some version control systems use a database
546as the repository, some use regular files, and some use a com-
547bination of the two. Either way, the repository is clearly a piv-
548otal component of your version control strategy. You need it
549sitting on a safe, secure, and reliable machine. And it should
550go without saying that it needs to get backed up regularly.
551In the old days, the repository and all its users had to share
552a machine (or at least share a filesystem). This turns out to
553be fairly limiting; it was hard to have developers working at
554different sites or working on different kinds of machines or
555operating systems. As a result, most version control systems
556today support networked operation; as a developer you can
557T HE R EPOSITORY 10
558Different Flavors of Networked Access
559The writers of version control systems sometimes have
560different definitions of what networked means. For
561some, it means accessing the files in a repository over
562shared network drives (such as Windows shares or NFS
563mounts). For others it means having a client-server
564architecture, where clients interact with server repos-
565itories over a network. Both can work (although the
566former is hard to design correctly if the underlying file-
567sharing mechanism doesn’t support locking reliably).
568However, you may find that deployment and security
569issues dictate which systems you can use.
570If a version control system needs access to shared
571drives, and you need to access it from outside your
572internal network, then you’ll need to make sure your
573organization allows you to access the data this way.
574Virtual Private Network (VPN) packages allow this kind
575of secure access, but not all companies run VPNs.
576Subversion uses the client-server model for remote
577access.
578access the repository over a network, with the repository act-
579ing as a server and the version control tools acting as clients.
580This is tremendously enabling. It doesn’t matter where the
581developers are; as long as they can connect over a network
582to the repository, they can access all the project’s code and
583its history. And they can do it securely; you can even use
584the Internet to access your repository without sharing your
585precious source code with a nosy competitor.
586This does lead to an interesting question, though. What hap-
587pens if you need to do development but you don’t have a
588network connection to your repository? The simple answer
589is, “it depends.†Some version control systems are designed
590solely for use while connected to the repository; it is assumed
591that you’ll always be online and that you won’t be able to
592change source code without first contacting the central repos-
593itory. Other systems are more lenient. The Subversion sys-
594tem, which we use for our examples in this book, is one of
595W HAT S HOULD W E S TORE ? 11
596the latter. We can edit away on our laptops at 35,000 feet
597and then resynchronize the changes when we get to our hotel
598rooms. This online/offline issue is a crucial one when choos-
599ing a version control system; make sure that whatever prod-
600uct you choose supports your style of working.
601Some version control systems support the notion of multiple
602repositories instead of a single central repository. Developers
603can swap sets of changes between the separate repositories.
604These are often called decentralized version control systems
605and are popular when large numbers of developers need to
606operate semiautonomously, most famously for developing the
607Linux kernel. Examples of decentralized version control sys-
608tems include BitKeeper, Arch, and SVK. These systems have
609a very different style of development, and we won’t discuss
610them further in this book.
6112.2 What Should We Store?
612All the things in your project are stored in the repository. But
613what exactly are the things we’re talking about?
614Well, you obviously need program source files to build your
615project: the Java, C#, Ruby, or whatever language you’re
616using to write your application. In fact, some folks think that
617this source code is such an important component of version
618control that they use the term source code control systems.
619The source code is certainly important, but many people make
620the mistake of forgetting all the other things that need to be
621stored under version control. For example, if you’re a Java
622programmer, you may use the Ant tool to compile your source.
623Ant uses a script, normally called build.xml , to control what
624it does. This script is part of the build process; without it
625you can’t build the application, so it should be stored in the
626version control system.
627Similarly, many projects use metadata to drive their config-
628uration. This metadata should be in the repository too. So
629should any scripts you use to create a release CD, test data
630used by QA, and so on.
631W ORKING C OPIES AND M ANIPULATING F ILES 12
632In fact, there’s an easy test when it comes to deciding what
633goes in and what stays out. Simply ask yourself “if we didn’t
634have an up-to-date version of x, could we build, test, and
635deliver our application?†If the answer is “no,†then x should
636be in the repository.
637As well as all the files that go toward creating the released
638software, you should also store your noncode project artifacts
639under version control (anything you’ll need to make sense
640of things later), including the project’s documentation (both
641internal and external). It might also include the text of signif-
642icant e-mails, minutes of meetings, information you find on
643the web—anything that contributes to the project.
6442.3 Working Copies and Manipulating Files
645The repository stores all the files in our project, but that
646doesn’t help us much if we need to add some magic new fea-
647ture into our application; we need the files where we can get
648to them. This place is called our local working copy. working copy
649The working copy is a local copy of all of the things that we
650need from the repository to work on our part of the project.
651For small- to medium-sized projects, the working copy will
652probably simply be a copy of all the code and other artifacts
653in the project. For larger projects, you may arrange things so
654that developers can work with just a subset of the project’s
655code, saving them time when building and helping to isolate
656subsystems of the system. You might also hear the working
657copy called the working directory or simply the workspace.
658In order to populate our working copy initially, we need to get
659things out of the repository. Different version control systems
660have different names for this process, but the most common
661(and the one used by Subversion) is checking out. When you checking out
662check out from the repository, you extract local copies of files
663into your working copy. Even if you do your work on the same
664computer that stores the repository, you’ll still need to check
665files out before using them; the repository should be treated
666as a black box. The checkout process ensures that you get
667up-to-date copies of the files you request and that these files
668are copied into a directory structure that mirrors that of the
669repository.
670W ORKING C OPIES AND M ANIPULATING F ILES 13
671Joe Asks...
672What about Generated Artifacts?
673If we store all the things needed to build the project,
674does that mean we should also be storing all the gen-
675erated files? For example, we might run JavaDoc to
676generate the API documentation for our source tree.
677Should that documentation be stored in the version
678control system’s repository?
679The simple answer is “no.†If a generated file can
680be reconstituted from other files, then storing it is sim-
681ply duplication. Why is this duplication bad? It isn’t
682because we’re worried about wasting disk space. It’s
683because we don’t want things to get out of step. If we
684store the source and the documentation, and then
685change the source, the documentation is now out-
686dated. If we forget to update it and check it back
687in, we’ve now got misleading documentation in our
688repository. So in this case, we’d want to keep a single
689source of the information, the source code. The same
690rules apply to most generated artifacts.
691Pragmatically, some artifacts are difficult to regener-
692ate. For example, you may have only a single license
693for a tool that generates a file needed by all the
694developers, or a particular artifact may take hours to
695create. In these cases, it makes sense to store the
696generated artifacts in the repository. The developer
697with the tool’s license can create the file, or a fast
698machine somewhere can create the expensive arti-
699fact. These can be checked in, and all other devel-
700opers can then work from these generated files.
701W ORKING C OPIES AND M ANIPULATING F ILES 14
702?????
703?
704?
705?
706?
707?
708??
709?
710?
711?
712??
713?
714?? ?
715??
716! "
717#
718$
719??
720?
721?
722?
723??
724?
725?? ?
726%
727&'
728%
729() *
730+
731,
732*- . /
733+
734'
735%
736)
7370
7380
7391
740+
7412
74234
7432
744567
7458
7469
7477 : ;<
7488
7494
750=>
751?
752?
753@
754A
755B
756?
757?C
758?
759?
760D
761E F
762Figure 2.1: The Repository and Working Copies
763It’s also possible to export files from the repository, which is export
764slightly different from checking out. When you do an export,
765you won’t end up with a working copy; you’ll just get a snap-
766shot of files from the repository. This is useful in certain situ-
767ations such as packaging code for distribution.
768As you work on a project, you’ll make changes to the project’s
769code in your working copy. Every now and then you’ll reach
770a point where you’ll want to save your changes back to the
771repository. This process is called committing your changes committing
772back into the repository.
773Of course, all the time you’re making changes, so are other
774members of your team. Just like you, they’ll be committing
775their changes to the repository. However, these changes do
776not affect your local working copy; it doesn’t suddenly change
777just because someone else saved changes into the repository.
778Instead, you have to instruct the version control system to
779update your working copy. During the update, you’ll receive update
780the latest set of files from the repository. And when your col-
781leagues do an update, they’ll receive your latest changes too.
782(Just to confuse things, however, some folks also use the term
783check out to refer to updating, because they are checking out
784the latest changes. Because this is a common idiom, we’ll also
785use this at times in this book.) These various interactions are
786shown in Figure 2.1 .
787P ROJECTS , D IRECTORIES , AND F ILES 15
788Of course there’s a potential problem here: what happens if
789you and a colleague both want to make changes to the same
790source file at the same time? It depends on the version control
791system you’re using, but all have ways of dealing with the
792situation. We talk about this more in Section 2.9, Locking
793Options, on page 23.
7942.4 Projects, Directories, and Files
795So far we’ve talked about storing things, but we haven’t talked
796about how those things are organized.
797At the lowest level, most version control systems deal with
798individual files. 1 Each file in your project is stored by name
799in the repository; if you add a file called Panel.java to the
800repository, then other members of your team can check out
801Panel.java into their own working copies.
802However, that’s pretty low-level. A typical project might have
803hundreds or thousands of files, and a typical company might
804have dozens of projects. Fortunately, almost all version con-
805trol systems allow you to structure the repository. At the top
806level, they typically divide your work into projects. Within
807each project, they let you work in terms of modules (and
808often submodules). For example, perhaps you are working
809on Orinoco, a large web-based book ordering application. All
810the files needed to build the application might be stored in the
811repository under the Orinoco project name. If you wanted to,
812you could check it all out onto your local disk.
813The Orinoco project itself might be broken down into a num-
814ber of largely independent modules. For example, there might
815be a team working on credit card processing and another
816working on order fulfillment. With any luck, the folks in
817the credit card subproject won’t need to have all the project’s
818source to do their job; their code should be nicely partitioned.
819So when they check out, they really want to see only the parts
820of the project that they’re working on.
8211 Some IDE-like environments perform versioning at the method level, but
822they’re fairly uncommon.
823W HERE D O V ERSIONS C OME I N ? 16
824Subversion organizes the repository into directories. A project
825might correspond to a top-level directory, with modules and
826submodules arranged as directories within your project. This
827might be enough for simple projects, but for more complex
828code sharing Subversion supports the notion of externals. An externals
829externals definition allows you to include another Subversion
830repository location in any directory in your project.
831CVS Hint: Subversion’s directory-based organization corresponds,
832roughly speaking, to CVS modules, with externals corresponding to
833alias modules. Organizing stuff by directory turns out to be just as pow-
834erful and a lot easier for people to understand.
835Subversion’s “everything is a directory†approach is discussed
836in more depth in Chapter 8, Organizing Your Repository, on
837page 107.
8382.5 Where Do Versions Come In?
839This book is all about version control systems, but so far all
840we’ve talked about is storing and retrieving files in a reposi-
841tory. Where do versions come in?
842Behind the scenes, a version control system’s repository is a
843fairly clever beast. It doesn’t just store the current copy of
844each of the files in its care. Instead it stores every version
845that has ever been checked in. If you check out a file, edit it,
846and then check it back in, the repository will hold both the
847original version and the version that contains your changes.
848In reality, most version control systems store the differences
849between versions of a file, rather than complete copies of each
850revision. Subversion stores the full text for the newest revision
851of a file, as well as cleverly picking historical revisions to store
852in full, so that it can retrieve any version of a file quickly.
853This helps minimize disk space requirements while keeping
854updates and checkouts fast.
855There are two common numbering schemes for version control
856systems: file-specific numbering and repository-wide number-
857ing. In a file-specific numbering scheme, the first revision of
858a file is named 1.1. When a change is checked in, the file is
859given the number 1.2, and so on. If you have version 1.2 of
860Node.cs and version 1.6 of Graph.cs , committing a change to
861W HERE D O V ERSIONS C OME I N ? 17
862Node.cs will make it revision 1.3. Graph.cs remains unchanged
863and at revision 1.6.
864In the repository-wide numbering scheme, the entire reposi-
865tory starts at revision 0, and checking in a change increases
866the repository revision number to 1, then 2, and so on. In
867this scheme, it’s more correct to talk about “ Panel.java at revi-
868sion 7†than to talk about “revision 7 of Panel.java .†Subver-
869sion uses this second numbering scheme, which turns out
870to be extremely useful for referring to changes once they’ve
871been committed. Section 9.5, Simple Bug Fixes, on page 121
872explains how to use revision numbers for merging bug fixes
873across branches.
874CVS Hint: CVS uses a file-specific numbering scheme, so people
875often look at the revision number of a file to try to gauge how much
876activity is occurring in the file or how much has changedover a period
877of time. Subversion’s repository-wide revision numbers make it impos-
878sible to do the same thing—you’ll have to use Subversion’s log com-
879mand to examine the history to look for changes.
880Subversion’s repository revision numbers act as a kind of
881marker pen, drawing a line through all the files in your repos-
882itory each time a commit is made. Figure 2.2 on the following
883page shows three files: Trains.java , Graph.java , and Node.java .
884First we commit a change to Graph.java (shown in the diagram
885as Graph.java ’s circle changing to a star), taking the reposi-
886tory to revision 2. If we then change Trains.java and Node.java ,
887we’ll bring the repository to revision 3. The key point is that
888Graph.java is at revision 3 as well, even though its content has
889not changed since revision 2.
890Subversion revision numbers aren’t much use for figuring out
891how much has changed in a particular file or group of files, 2
892so don’t try to use them for that purpose. People accustomed
893to the file-specific numbering scheme are often confused that
894the repository has jumped a bunch of revisions without their
8952 Using version numbers, no matter how they’re assigned, to try to track
896“how much change is happening†is pretty futile—a single change could affect
897every line in a file. You’re probably better off looking at the changes directly,
898using your version control system’s history browsing features, if you want to
899find out how much has changed.
900T AGS 18
901G
902H
903IJK
904L
905M
906INI
907O
908H
909I
910P
911QR
912L
913M
914IN I
915ST UV
916L
917M
918IN I
919W
920XY
921Z
922[
923Z
924\]^
925W
926X Y
927Z
928[
929Z
930\]_
931W
932X Y
933Z
934[
935Z
936\]`
937aa a
938bbb
939cc c
940de
941f
942g
943h
944i jkk
945f
946g
947d e
948f
949g
950h
951ij kk
952f
953g
954Figure 2.2: Revision Numbers in the Repository
955checking in anything. This makes sense when you realize the
956number applies to everyone’s checkins, not just your own.
957This system of storing revisions is remarkably powerful. Using
958it, the version control system can do things such as
959• Retrieve a specific revision of a file.
960• Check out all of the source code of a system exactly as it
961appeared two months ago.
962• Tell you what changed in a particular file between revi-
963sions 7 and 9.
964You can also use the revision system to undo mistakes. If
965you get to the end of the week and discover you’ve been going
966down a blind alley, you can back out all the changes you’ve
967made, reverting to the code as it was on Monday morning.
9682.6 Tags
969All these revision numbers are great, but as people we seem to
970be better at remembering names such as PreRelease2 rather
971than numbers such as r347.
972Tags to the rescue. Version control systems let you assign Tags
973names to a group of files (or directories or an entire project) at
974a particular point in time. If you assigned the tag PreRelease2
975to our group of three files, you could subsequently check them
976out using that same tag.
977B RANCHES 19
978lm no
979p
980qrs tt
981u
982p
983lmn o
984p
985qrst t
986u
987p
988v
989w
990x yz
991v
992{
993|}
994Figure 2.3: A Simple Trunk
995Tags are a great way of keeping track of significant events in
996the life of your project’s code. We’ll be using tags extensively
997later in this book. You can read about tags and branches
998(the topic of the next section) in Chapter 9, Using Tags and
999Branches, on page 111.
10002.7 Branches
1001In the normal course of development, most folks are working
1002on a common code base (although they’ll likely be working on
1003different parts of it). Developers will be checking out code,
1004making changes in their working copies, then checking the
1005changes back in, and everyone will share this work. This
1006main body of code is called the trunk. We show this in Fig- trunk
1007ure 2.3 . In this figure (and in the ones that follow) time flows
1008from left to right. The thicker horizontal line represents the
1009progression of code through time; it is the main line of the
1010development. Individual developers check in and check out
1011code from the trunk into their individual working copies.
1012But consider the time when a new release is about to be
1013shipped. One small subteam of developers may be preparing
1014the software for that release, fixing last-minute bugs, working
1015with the release engineers, and helping the QA team. During
1016this vital period, they need stability; it would set back their
1017efforts if other developers were also editing the code, adding
1018features intended for the next release.
1019B RANCHES 20
1020One option is to freeze new development while the release is
1021being generated, but this means the rest of the team is effec-
1022tively sitting idle.
1023Another option would be to copy the source software out onto
1024a spare machine and then have the release team just use this
1025machine. But if we do that, what happens to the changes they
1026make after the copy? How do we keep track of them? If they
1027find bugs in the release code that are also in the trunk, how
1028can we efficiently and reliably merge these fixes back in? And
1029once they’ve released the software, how do we fix bugs that
1030customers report; how can we guarantee to find the source
1031code in the same state as when we shipped the release?
1032A far better option is to use the branching capabilities built branching
1033into version control systems.
1034Branching is a bit like the hackneyed device in science fic-
1035tion stories where some event causes time to split. From that
1036point forward there are two parallel futures. Some other event
1037occurs, and one of these futures splits too. Soon you’re deal-
1038ing with a whole bunch of alternative universes (a great device
1039for resolving the story when you run out of plot ideas).
1040Branching in a version control system also allows you to cre-
1041ate multiple parallel futures, but rather than being populated
1042by aliens and space cowboys, they contain source code and
1043version information.
1044Take the case of the team about to release a new version of
1045the product. So far, the entire team has been working in the
1046trunk, the common thread of code shown in Figure 2.3 on
1047the page before. But the release subteam wants to isolate
1048themselves from the trunk. To do this, they create a branch in
1049the repository. From now until their work is done, the release
1050subteam will check out from and check into this branch. Even
1051after the application is released, this branch will stay active;
1052if customers report bugs, the team will fix them in this release
1053branch. This is shown in Figure 2.4 on the following page.
1054A branch is almost like having a totally separate repository:
1055people using that branch see the source code it contains and
1056operate independently of people working on other branches
1057or the trunk. Each branch has its own history and tracks
1058changes independently of the trunk (although obviously if you
1059B RANCHES 21
1060~
1061
1062€Â
1063‚
1064€
1065
1066€
1067ƒ
1068€  „ €
1069
1070† ‡ˆ
1071‰
1072
1073€Š Â
1074
1075€
1076‹
1077Œ
1078
1079
1080€
1081ƒ
1082€  „ €Â
1083€
1084ƒ
1085€  „€Ž ÂÂ
1086‹
1087‘
1088’€„
1089~Π
1090‚
1091‘
1092†
1093Â
1094€
1095Π
1096Â
1097Œ
1098‘
1099†
1100Â
1101“ € ”€
1102ƒ
1103ŒŠ • €†
1104‚
1105–
1106
1107Â
1108†—
1109ÂŽ
1110
1111†‡ ˆ
1112Figure 2.4: Trunk with a Release Branch
1113look back past the point where the branch was made you’ll see
1114that the branch and the trunk become one).
1115This is exactly what you want when you’re creating releases.
1116The team working on the release will have a stable code base
1117to polish and ship. In the meantime, the main group of devel-
1118opers can continue making changes to the main line of code;
1119there’s no need for a code freeze while the release takes place.
1120And when customers report problems in the release, the team
1121will have access to the code in the release branch so they can
1122fix the bugs and ship updated releases without including any
1123of the newly developed code from the trunk.
1124Branches are stored as named directories within Subversion;
1125you create a branch simply by copying the trunk to a new
1126location. Subversion’s internals use lazy copies to make this lazy copies
1127copying process efficient, and these lazy copies are the basis
1128of Subversion’s tagging support too. Whenever you copy a file
1129or directory, Subversion simply stores a link to the original.
1130When you make a change to the copy, Subversion records
1131those changes as differences against the original. Using lazy
1132copies Subversion can very quickly copy large trees of files
1133using almost zero space, ideal for branches and tags.
1134You can create branches off other branches, but typically you
1135won’t want to; we’ve come across many developers who have
1136been put off branching for life because of some bad experi-
1137ences with overly complicated branching in a project.
1138M ERGING 22
1139You should avoid excessive branching. Even though branches
1140might seem like a cheap way to hedge your bets during devel-
1141opment, they have significant costs when you need to merge
1142changes between branches. Not only do you need to merge dif-
1143ferent lines of development, you have to make sure you don’t
1144lose any changes in the process. Bear in mind that the need to
1145create multiple branches, especially for parallel lines of devel-
1146opment rather than releases, may be a sign that something is
1147going wrong.
1148In this book we’ll describe a simple scheme that does every-
1149thing you’ll need but that avoids unnecessary complexity.
11502.8 Merging
1151Back to the science fiction story with the multiple alternate
1152futures. In order to spice up the plot, writers often allow their
1153characters to travel between these different universes using
1154wormholes, polyphase deconfabulating oscillotrons, or just a
1155good strong cup of piping-hot tea.
1156You can also travel between alternate futures in a version
1157control system (the cup of tea is optional). Although each
1158checked-out version comes from a particular branch and gets
1159checked back into that same branch, it’s easy to have multi-
1160ple branches checked out on a single developer’s machine (in
1161different directories or folders on the hard drive, of course).
1162That way a developer can be working on both the trunk and
1163on (say) bug fixes in a release branch at the same time.
1164Even better, version control systems support merging. Say merging
1165you fix a bug in the release branch and realize that the same
1166bug will be present in the trunk code. You can tell the ver-
1167sion control system to work out the changes you made on the
1168release branch to fix the bug and then to apply those changes
1169to the code in the trunk. You can even merge them into differ-
1170ent release branches. This largely eliminates the need to cut
1171and paste changes back and forth between different versions
1172of a system. We’ll have a lot to say about merging later.
1173L OCKING O PTIONS 23
11742.9 Locking Options
1175Imagine two developers, Fred and Wilma, working on the same
1176project. Each has checked out the project’s files onto their
1177respective local hard drives, and each wants to edit their local
1178copy of File1.java . What happens when they come to check that
1179file in?
1180A bad scenario would be for the version control system to
1181accept Fred’s changes and then accept Wilma’s version of the
1182same file. As Wilma’s copy won’t have Fred’s changes in it,
1183storing Wilma’s copy in the repository will effectively forget all
1184Fred’s hard work.
1185To prevent this from happening, version control systems must
1186implement some form of conflict resolution system (probably
1187a good thing in the case of Fred and Wilma). There are two
1188common versions of conflict resolution.
1189The first is called strict locking. In a strict locking version con- strict locking
1190trol system, all files that are checked out are initially flagged
1191as being “read-only.†You can look at them, and you can use
1192them to build your application, but you can’t edit or change
1193them. To do that, you have to ask the repository’s permission:
1194“please can I edit File1.java ?†If no one else is editing that same
1195file, then the repository gives you permission and changes the
1196permissions of your local copy of the file to be “read/write.â€
1197You can then edit. If anyone else asks to edit that same file
1198while you have it flagged, they’ll be refused. After you’ve fin-
1199ished your changes and checked the file in, your local copy
1200reverts to being read only, and it becomes available for other
1201folks to edit.
1202The second form of conflict resolution is often called opti-
1203mistic locking, although it really is not locking at all. Here, optimistic locking
1204every developer gets to edit any checked-out file: the files are
1205checked out in a read/write state. However, the repository will
1206not allow you to check in a file that has been updated in the
1207repository since you last checked it out. Instead, it asks you
1208to update your local copy of the file to include the latest repos-
1209itory changes before checking in. This is where the cleverness
1210lies. Instead of simply overwriting all your hard work with the
1211latest repository version of the file, the version control system
1212attempts to merge the repository changes with your changes.
1213L OCKING O PTIONS 24
1214For example, let’s look at File1.java :
1215Line 1
1216public class File1 {
1217-
1218public String getName() {
1219-
1220return "Wibble";
1221- }
12225
1223public int getSize() {
1224-
1225return 42;
1226- }
1227- }
1228Wilma and Fred both check this file out. Fred changes line 3:
1229return "WIBBLE";
1230He then checks the file in. This means that Wilma’s copy of
1231the file is out-of-date. Not knowing this, Wilma changes line
12326, so it returns 99 instead of 42. When she goes to check the
1233file in, she’s told that her copy is out-of-date; she needs to
1234merge in the repository changes. This corresponds to the star
1235marked OUT OF SYNC in Figure 2.5 on the next page.
1236When Wilma merges the changes into her file, the version con-
1237trol system is clever enough to spot that Fred’s changes do not
1238overlap hers, so it simply updates her local copy with a new
1239line 3, leaving her changes still in her file. When she checks
1240in, she’ll be storing her changes and leaving Fred’s intact.
1241What happens if Fred and Wilma both updated line 3 but
1242made different changes to it? Assuming Fred checks in first,
1243his changes will be accepted. When Wilma goes to check in,
1244she’ll again be told that her copy is out-of-date. This time,
1245though, when she goes to merge in the repository version the
1246system will notice that she’s made a change to a line that has
1247also been changed in the repository. There’s a conflict. In this
1248case, Wilma will see some warning messages, and the conflict
1249will be marked up in her copy of the source file. She’ll have to
1250resolve it manually (probably by talking with Fred to find out
1251why they were both working on the same line of code).
1252Given this description, you might think that optimistic locking
1253is a somewhat reckless way of developing systems: multiple
1254people editing the same files at the same time. Often peo-
1255ple who haven’t tried it reason that it can’t work and insist
1256on working only with version control systems that implement
1257strict locking.
1258L OCKING O PTIONS 25
1259˜™ š
1260›
1261œ
1262Â Â
1263›
1264ž ŸŸ
1265œ
1266›
1267¡¢
1268£
1269˜™ š
1270›
1271œ
1272¤
1273Â¥
1274¦
1275œ
1276§¨¨¡
1277Â¥
1278© žª¡
1279«
1280¬
1281£
1282¦
1283¡
1284Â¥
1285™
1286¦
1287§
1288Â
1289®
1290œ
1291š š
1292›
1293¡
1294Â
1295¯
1296°
1297˜™ š
1298›
1299œ
1300Â
1301œ
1302§
1303Â¥
1304¨¡
1305Â¥
1306¤
1307œ
1308±¡
1309«
1310¬
1311£
1312¦
1313¡
1314Â¥
1315™
1316¦
1317§ ²³
1318¯
1319°
1320°
1321˜ ™š
1322›
1323œ
1324Â Â
1325›
1326ž ŸŸ
1327œ
1328›
1329¡ ¢
1330£
1331˜™š
1332›
1333œ
1334¤
1335Â¥
1336¦
1337œ
1338§¨¨¡
1339Â¥
1340© žª¡
1341«
1342¬
1343£
1344¦
1345¡
1346Â¥
1347™
1348¦
1349§
1350Â
1351®
1352œ
1353šš
1354›
1355¡
1356Â
1357¯
1358°
1359˜™š
1360›
1361œ
1362Â
1363œ
1364§
1365Â¥
1366¨¡
1367Â¥
1368¤
1369œ
1370±¡
1371«
1372¬
1373£
1374¦
1375¡
1376Â¥
1377™
1378¦
1379§²³
1380¯
1381°
1382°
1383˜™š
1384›
1385œ
1386ÂÂ
1387›
1388žŸŸ
1389œ
1390›
1391¡¢
1392£
1393˜™ š
1394›
1395œ
1396¤
1397Â¥
1398¦
1399œ
1400§ ¨ ¨¡
1401Â¥
1402©žª¡
1403«
1404¬
1405£
1406¦
1407¡
1408Â¥
1409™
1410¦
1411§
1412Â
1413®
1414œ
1415šš
1416›
1417¡
1418Â
1419¯
1420°
1421˜™ š
1422›
1423œ
1424Â
1425œ
1426§
1427Â¥
1428¨ ¡
1429Â¥
1430¤
1431œ
1432±¡
1433«
1434¬
1435£
1436¦
1437¡
1438Â¥
1439™
1440¦
1441§² ³
1442¯
1443°
1444°
1445´
1446´
1447´
1448˜™ š
1449›
1450œ
1451¤
1452Â¥
1453¦
1454œ
1455§ ¨ ¨¡
1456Â¥
1457©žª¡
1458«
1459¬
1460£
1461¦
1462¡
1463Â¥
1464™
1465¦
1466§
1467Â
1468®
1469µ
1470¶ ¶· ¸
1471Â
1472¯
1473´
1474´
1475´
1476´
1477´
1478˜™š
1479›
1480œ
1481Â
1482œ
1483§
1484Â¥
1485¨ ¡
1486Â¥
1487¤
1488œ
1489± ¡
1490«
1491¬
1492£
1493¦
1494¡
1495Â¥
1496™
1497¦
1498§¹¹
1499¯
1500´
1501´
1502´
1503˜™ š
1504›
1505œ
1506Â Â
1507›
1508ž ŸŸ
1509œ
1510›
1511¡¢
1512£
1513˜™ š
1514›
1515œ
1516¤
1517Â¥
1518¦
1519œ
1520§¨¨¡
1521Â¥
1522© žª¡
1523«
1524¬
1525£
1526¦
1527¡
1528Â¥
1529™
1530¦
1531§
1532Â
1533®
1534µ
1535¶¶·¸
1536Â
1537¯
1538°
1539˜™ š
1540›
1541œ
1542Â
1543œ
1544§
1545Â¥
1546¨¡
1547Â¥
1548¤
1549œ
1550±¡
1551«
1552¬
1553£
1554¦
1555¡
1556Â¥
1557™
1558¦
1559§ ²³
1560¯
1561°
1562°
1563˜ ™š
1564›
1565œ
1566Â Â
1567›
1568ž ŸŸ
1569œ
1570›
1571¡ ¢
1572£
1573˜™š
1574›
1575œ
1576¤
1577Â¥
1578¦
1579œ
1580§¨¨¡
1581Â¥
1582© žª¡
1583«
1584¬
1585£
1586¦
1587¡
1588Â¥
1589™
1590¦
1591§
1592Â
1593®
1594µ
1595¶ ¶ ·¸
1596Â
1597¯
1598°
1599˜™š
1600›
1601œ
1602Â
1603œ
1604§
1605Â¥
1606¨¡
1607Â¥
1608¤
1609œ
1610±¡
1611«
1612¬
1613£
1614¦
1615¡
1616Â¥
1617™
1618¦
1619§¹¹
1620¯
1621°
1622°
1623˜ ™š
1624›
1625œ
1626ÂÂ
1627›
1628žŸŸ
1629œ
1630›
1631¡ ¢
1632£
1633˜ ™š
1634›
1635œ
1636¤
1637Â¥
1638¦
1639œ
1640§ ¨¨ ¡
1641Â¥
1642©ž ª ¡
1643«
1644¬
1645£
1646¦
1647¡
1648Â¥
1649™
1650¦
1651§
1652Â
1653®
1654µ
1655¶¶ · ¸
1656Â
1657¯
1658°
1659˜ ™š
1660›
1661œ
1662Â
1663œ
1664§
1665Â¥
1666¨¡
1667Â¥
1668¤
1669œ
1670± ¡
1671«
1672¬
1673£
1674¦
1675¡
1676Â¥
1677™
1678¦
1679§¹ ¹
1680¯
1681°
1682°
1683º
1684»
1685¼½¾¼ ¿ÀÃ
1686Â
1687Ã
1688À
1689»
1690Ä Å
1691Â
1692Æ
1693ÇÈ
1694É
1695Ê Ë
1696É
1697ÃŒ ÃÃŽ
1698Ã
1699ÃÑÒ
1700ÃÓÔ Õ
1701Ö
1702רÙ
1703Ù
1704Ú
1705Û
1706ÜÃ
1707Þ
1708ß
1709Ü Ã
1710Þ
1711ß
1712à áâ
1713â
1714ã
1715ä
1716å æ çå è
1717éêëìÃî
1718à ï
1719ß
1720Üð
1721ñ Ü
1722ò
1723óÜ
1724ô õö
1725ö
1726÷
1727ø
1728Figure 2.5: Fred and Wilma make changes to the same file,
1729but the conflict is handled by a merge.
1730C ONFIGURATION M ANAGEMENT (CM) 26
1731In reality, though, strict locking turns out to be a lot of extra
1732hassle with no particular payback. If you try an optimistic
1733locking system (such as Subversion), you’ll be surprised at
1734just how rarely conflicts arise. It turns out that in practice
1735the normal ways of dividing work on a team mean that peo-
1736ple work on different areas of the code; they don’t bump into
1737each other that often. And when they do need to edit the same
1738file, they’re often working on different parts of it. In a strict
1739locking system, one would have to wait for the other to finish
1740and check in before proceeding. In an optimistic locking sys-
1741tem, both can proceed. We’ve tried both kinds of locking over
1742the years, and our strong recommendation is that the vast
1743majority of teams should use a version control system with
1744optimistic locking.
1745Subversion 1.2 introduced optional file locking, discussed in
1746Chapter 7, File Locking and Binary Files, on page 99. Using a
1747simple file property you can ask Subversion to enforce strict
1748locking on individual files, such as sound, graphics, or other
1749unmergeable files.
17502.10 Configuration Management (CM)
1751Sometimes you’ll hear folks talking about Configuration Man-
1752agement or Software Configuration Management systems (or
1753flinging about the abbreviations CM or SCM). At first sight
1754they seem to be talking about version control. And that’s
1755largely true; the practices of CM rely very heavily on having
1756good version control in place. But version control is just one
1757tool used by configuration management.
1758CM is a set of project management practices that enables you
1759to accurately and reproducibly deliver software. It uses ver-
1760sion control to achieve its technical goals but also uses a lot
1761of human controls and cross-checks to make sure things are
1762not forgotten. You can think of configuration management as
1763a way of identifying the things that get delivered and version
1764control as a means of recording that identification. CM is a
1765large topic, and we won’t be covering it more in this book. If
1766you’re interested in CM, Software Configuration Management
1767Patterns [BA03] is an excellent resource, and goes into greater
1768detail on many of the issues we don’t have room to cover here.
1769C ONFIGURATION M ANAGEMENT (CM) 27
1770Many of the techniques and recipes in this book correspond
1771to an SCM Pattern, which we’ll mention by name.
1772For now, though, let’s concentrate on how we can use version
1773control systems to get our jobs done. The next chapter is a
1774gentle introduction to one particular version control system,
1775Subversion.
1776Chapter 3
1777Getting Started with
1778Subversion
1779The best way to get familiar with a new software tool is to try
1780it, so this chapter will show you how to create and work with
1781a live Subversion repository. You’ll be learning the basic steps
1782in using Subversion whilst maintaining a trivial project.
1783Since Subversion is reasonably recent software, you will prob-
1784ably need to install it on your computer. Basic installation,
1785which we’ll cover in this chapter, is pretty simple. For more
1786advanced installation, networking, security, and administra-
1787tion instructions, see Appendix A on page 151.
1788Subversion ships with a command-line client, but there are
1789a variety of third-party tools for interacting with your repos-
1790itory. TortoiseSVN integrates with the Windows Explorer, for
1791example, and some IDEs now include Subversion support.
17923.1 Installing Subversion
1793Obviously you need to have Subversion installed before you
1794can use it. Depending on how Subversion is packaged for your
1795operating system, you might get the option to install the client
1796and server components separately. This is more common for
1797Unix platforms where an adminstrator might want to set up a
1798server without installing client tools.
1799I NSTALLING S UBVERSION 29
1800Joe Asks...
1801Shells, Prompts, Command Windows?
1802Terminology can get confusing when you’re dealing
1803with command lines, so let’s clear things up a bit.
1804A command processor, also called a shell, is a pro-
1805gram that accepts a command and executes it. The
1806command can have parameters, and the command
1807processor often has additional capabilities (such as
1808redirecting the application’s output to a file). Under
1809Windows, cmd and command are common com-
1810mand processors (which you use depends on which
1811version of Windows you use). On Unix boxes, there’s
1812a great choice of shells, from the original sh , through
1813csh , bash , tcsh , zsh , and so on.
1814Back before we had GUI systems, the command
1815processor or shell was how you interacted with your
1816computer. When you booted up DOS, you got the
1817DOS prompt, and you were talking with the command
1818application; your computer monitor was effectively a
1819dumb terminal.
1820Now that we have fancy front ends, we need a place
1821to run these command processors, so folks have writ-
1822ten terminal applications that run in windows. When
1823one of these terminal applications is running a com-
1824mand processor or a shell, you can type in commands
1825at the prompt and have them execute. Sometimes
1826we’ll call these windows executing a command pro-
1827cessor a command window.
1828I NSTALLING S UBVERSION 30
1829Figure 3.1: Windows Command Prompt
1830Our first step is to check if Subversion is already installed on
1831your computer. The easiest way to do this is with the com-
1832mand line. If you’re familiar with the command line, you can
1833skip the next section.
1834The Command Line
1835The command line is a low-level facility that lets you run com-
1836mands directly on your computer. The command line is a
1837powerful tool, but it can also be fairly cryptic: you’re working
1838down in the engine room when you’re issuing commands.
1839On Windows boxes, you can get to a command-line window by
1840using Start > Run and typing cmd as the name of the program
1841to run (on some older Windows versions you may have to type
1842command instead). You should see a window that looks like
1843Figure 3.1 .
1844On Unix boxes, you may be working at the command line
1845already. If instead you use a desktop environment such as
1846Gnome or KDE, look for the terminal , konsole , or xterm appli-
1847cation and run it. You should see a window like that in Fig-
1848ure 3.2 on the next page. If you’re using Mac OS X, your shell
1849application is hidden in /Applications/Utilities/Terminal .
1850You use the command-line window to enter commands and
1851view their output; no GUI front ends here. For example, in the
1852I NSTALLING S UBVERSION 31
1853Figure 3.2: Unix Shell Prompt
1854command-line window you just created, enter the following
1855command and hit the Enter key (sometimes labeled Return):
1856echo Hello
1857You should see the text “Hello†echoed back at you, and just
1858below it a new prompt where you can enter another command.
1859An example is shown in Figure 3.3 on the following page.
1860Prompts
1861One of the joys of the command window is that you can cus-
1862tomize the prompt that the shell uses to tell you it’s ready for
1863input. You can include the time, the current directory, your
1864username, and all sorts of other essential information in the
1865prompt. Unfortunately, this flexibility can also lead to confu-
1866sion: looking at the previous screenshots you can see that the
1867Windows prompt looks different from the Unix prompt.
1868In this book, we’ll try to simplify things by standardizing on
1869a generic prompt in our examples. We’ll show the name of
1870the current directory followed by a greater-than sign (>). For
1871example, we might give an example of a command as follows:
1872work > svn update
1873I NSTALLING S UBVERSION 32
1874Figure 3.3: After echoing “helloâ€
1875This means we’re in a directory called work and we issued the
1876command svn update . It should be simple to map this “logi-
1877cal†prompt to the prompt you actually see in your operating
1878system’s command window.
1879The commands in this book are generally not Windows or Unix
1880specific: they should work on both systems. The only differ-
1881ences are in the names of files; Windows uses drive letters
1882and backward slashes between the components of filenames,
1883and Unix uses forward slashes. Use appropriate filenames
1884for your environment, and things should work out fine. An
1885exception to this rule is when dealing with file:// -based
1886repositories—the Windows and Unix syntax is quite a bit dif-
1887ferent. When this is the case, we’ll include both Windows and
1888Unix versions of each command.
1889Checking If Subversion Is Installed
1890Bring up a command window on your computer, and type
1891the command svn --version , followed by the Return key. If the
1892Subversion client is installed correctly, you will see a response
1893similar to that shown in Figure 3.4 on the next page. Next try
1894C REATING A R EPOSITORY 33
1895Figure 3.4: Subversion Client Installed Correctly
1896svnadmin --version to see if the Subversion administration tools
1897are installed. If both of these commands worked, you can skip
1898ahead to the next section.
1899Most likely your computer complained that it couldn’t find svn
1900or svnadmin .That’s okay—Subversion is not yet a standard
1901part of most operating system installs, so it was a long shot
1902anyhow. Subversion is distributed both as source code and
1903as binary packages for different operating systems. Complete
1904instructions for your operating system should be available
1905from the package download page at http://subversion.
1906tigris.org/project packages.html . You can also down-
1907load the source code if you want to compile Subversion your-
1908self, but since Subversion relies on a number of other pack-
1909ages, it may be easiest to download a precompiled version.
19103.2 Creating a Repository
1911Subversion requires a repository to store your data. In this
1912section you’ll create a repository for storing your first project.
1913C REATING A S IMPLE P ROJECT 34
1914Subversion Versions
1915The Subversion developers are busy people, and
1916since the original publication of this book have
1917released Subversion 1.2 and 1.3. Most of the exam-
1918ples in the book will work with any version of Subver-
1919sion, but the file locking features require Subversion
19201.2 (or better) and the more advanced authentica-
1921tion features require Subversion 1.3 (or better).
1922Whena feature requires a particularversion of Subver-
1923sion we’ll include a note to remind you. We generally
1924recommend using the most recent release of Subver-
1925sion if you can, because it will be the most stable and
1926best supported.
1927First you need to create an empty directory for the repository
1928and then tell Subversion to create a new repository in the
1929directory. Let’s suppose you’re using /home/mike/svn-repos (for
1930Unix) or c:\svn-repos (for Windows).
1931Windows:
1932mkdir c: \ svn-repos
1933svnadmin create c: \ svn-repos
1934Unix:
1935mkdir /home/mike/svn-repos
1936svnadmin create /home/mike/svn-repos
1937Once the svnadmin command completes, you’ll end up with
1938a set of files in your repository directory. We’ll go into more
1939detail later on how the repository is stored on disk, but for now
1940you can safely treat the repository directory and its contents
1941as a black box.
1942Your Subversion repository is now set up—next we’ll start cre-
1943ating a project.
19443.3 Creating a Simple Project
1945Let’s populate your repository with a new project. In the spirit
1946of pioneering Internet startups, we’ll use a cryptic yet cool-
1947sounding project name—Sesame. We’ll start by creating a
1948C REATING A S IMPLE P ROJECT 35
1949Using Remote Filesystems
1950If you’re using a remote filesystem, such as a Windows
1951home directory on a network share or your Unix home
1952directory mounted over NFS, the Subversion client will
1953work great. You can check out a working copy to any
1954kind of networked drive with no problems.
1955If you’re running the Subversion server, however, you
1956need to be a little more careful. Subversion 1.0
1957shipped with Berkeley DB as the backend in which the
1958repository is stored. BDB doesn’t like using database
1959files on a network drive because of the way it maps
1960them into memory.
1961Subversion 1.1 introduced the “fsfs†filesystem–based
1962backend, which became the default in Subversion
19631.2. If you’re using Subversion 1.2 or 1.3, repositories
1964created using svnadmin create will work just fine on a
1965remote filesystem.
1966If you want to use the BDB backend instead of fsfs,
1967add the --fs-type bdb option when creating your
1968repository. When using BDB you must store your repos-
1969itory on a local drive.
1970couple of files and then import them into a sesame directory
1971in the repository. (The project name is officially Sesame, but
1972we’ll use the lowercase sesame in our repository.)
1973Create a temporary directory on your computer called tmpdir .
1974Inside that directory, use your favorite text editor to create
1975two files: Day.txt and Number.txt .
1976File Day.txt :
1977monday
1978tuesday
1979wednesday
1980thursday
1981friday
1982File Number.txt :
1983zero
1984one
1985two
1986three
1987four
1988C REATING A S IMPLE P ROJECT 36
1989These don’t look much like source programs, but remember
1990that we’re using our repository to store all the stuff we need
1991to build our project. It looks like Sesame needs to know the
1992names of the days of the week and a few small numbers, and
1993these are the data files that help it do this.
1994We now need to tell Subversion to import these files into a new
1995project in the repository. Subversion organizes everything in
1996the repository by directory, which we’ll explain in more detail
1997in Chapter 8, Organizing Your Repository, on page 107. For
1998now, we’ll use the convention recommended by the Subver-
1999sion developers and store our Sesame project in /sesame/trunk .
2000In your command prompt, change to the tmpdir directory. If
2001you’re on Windows, run
2002tmpdir > svn import -m "importing Sesame project" \
2003. file:///c:/svn-repos/sesame/trunk
2004Adding Number.txt
2005Adding Day.txt
2006Committed revision 1.
2007Don’t type the backward slash after the log message. We ran
2008out of space and couldn’t fit the whole command on one line,
2009so we used \ to separate it over several lines. You’ll see this
2010used quite often throughout the book.
2011If instead you’re on Unix, run
2012tmpdir > svn import -m "importing Sesame project" \
2013. file:///home/mike/svn-repos/sesame/trunk
2014Adding Number.txt
2015Adding Day.txt
2016Committed revision 1.
2017The import keyword tells Subversion we want to import some
2018files to our repository. The -m option allows you to associate a
2019message with this import. It’s a good idea to use a log message
2020indicating what kind of import you’ve performed.
2021The next parameter ( . ) tells Subversion to import the contents
2022of the current directory, tmpdir , into the repository. The final
2023parameter is a repository URL describing where we want to
2024import the files. Here we’re telling Subversion to look on the
2025local filesystem for the repository in our svn-repos directory
2026and to import into /sesame/trunk inside it. 1
20271 We’re importing to /sesame/trunk because in the future the Sesame project
2028S TARTING TO W ORK WITH A P ROJECT 37
2029Repository URLs
2030You may have noticed that when we imported our
2031files into the repository, we used a file://... URL
2032to tell Subversion where to put the new project. This
2033syntax looks a lot like Internet addresses you see in a
2034web browser, except instead of starting with http://
2035the URL starts with file:// . This tells Subversion to
2036look on the local filesystem for the repository, instead
2037of on the web.
2038In Chapter 5, Accessing a Repository, on page 55
2039you’ll see how you can use different URLs to access a
2040Subversion repository via a network, either on a web
2041server or via the custom svn protocol.
2042Subversion responds by letting us know that it has added the
2043two files and has committed the change into the repository.
2044So, now we’ve got these files safely tucked away in the repos-
2045itory. If we are brave (or foolish), we can go ahead and delete
2046the copies in our temporary directory. However, the prudent
2047(and pragmatic) developer would probably want to verify that
2048they are indeed correctly stored in the repository before delet-
2049ing them. And the easiest way to do that is to get Subversion
2050to check the files in the Sesame project out into your local
2051work area. Once we’ve confirmed that everything is there,
2052and that it looks correct, we can delete our originals. The
2053next section shows how this is done.
20543.4 Starting to Work with a Project
2055It doesn’t matter whether you’re starting work with a new
2056project (such as project Sesame, which we just created) or if
2057you’re joining a project that has been running for months and
2058has thousands of source files. What you do to start working
2059with the project’s files is the same:
2060will need to support branches, which will be stored in /sesame/branches . This
2061is discussed more fully in Chapter 8, Organizing Your Repository, on page 107.
2062S TARTING TO W ORK WITH A P ROJECT 38
2063ù ú
2064û
2065ü
2066ý
2067þ ÿ ?
2068?
2069?
2070ú ù ?
2071û
2072ý
2073?
2074ú
2075? ??
2076?
2077?
2078?
2079?
2080þ
2081?
2082þ??
2083?
2084ý
2085?
2086?
2087?
2088?
2089?
2090?
2091Figure 3.5: Working Directory Layout
20921. Decide where to put the working copies of the files on
2093your local machine.
20942. Check the project out of the repository into that location.
2095The first decision is normally fairly simple. We tend to have
2096a single directory on our boxes called work . We then check
2097out all projects somewhere under this directory. For simple
2098projects, we tend to check out directly under work . For more
2099complex ones, maybe involving code branches, we’d organize
2100things into a few subdirectories. For now, let’s assume we are
2101working with simple projects. If we have checked out three
2102separate projects called poppy , sesame , and sunflower , we’d end
2103up with directories that looked something like Figure 3.5 .
2104So, if you haven’t already got one, let’s start off by creating
2105a work directory, either from the command line or using your
2106File Manager.
2107Windows: mkdir c: \ work
2108Unix: mkdir /home/mike/work
2109Now we’ll check out the source into our working directory.
2110We use a file:// URL to specify our repository, so again
2111this command looks a little different on Windows and Unix.
2112M AKING C HANGES 39
2113Change to your work directory, and then on Windows run
2114work > svn co file:///c:/svn-repos/sesame/trunk sesame
2115A sesame \ Number.txt
2116A sesame \ Day.txt
2117Checked out revision 1.
2118On Unix, you need to run
2119work > svn co file:///home/mike/svn-repos/sesame/trunk sesame
2120A sesame/Number.txt
2121A sesame/Day.txt
2122Checked out revision 1.
2123The argument co tells Subversion that we want to perform
2124a checkout, the file:// URL specifies which repository we
2125want to check out from, and finally we tell Subversion where
2126we want to put our working copy, in this case inside a sesame
2127directory in our working directory.
2128You now have a local copy 2 of the Sesame project containing
2129the two files that we initially imported. From now on, we’ll be
2130working with these copies of the files, because these are the
2131ones that are being managed by Subversion. After checking
2132that they look correct, we can go ahead and delete the original
2133copies in our temporary directory. We’ve handed control of
2134these files over to our version control system, and it’s just
2135too confusing to have the original and the managed copies
2136lying around on our machine. We’ll make sesame our current
2137directory and work with the checked-out files.
21383.5 Making Changes
2139Despite all our hard work, our customer comes back com-
2140plaining; it appears our software needs to work on weekends.
2141So, fire up your favorite editor and add two lines to the end of
2142Day.txt :
2143monday
2144tuesday
2145wednesday
2146thursday
2147friday
2148saturday
2149sunday
21502 Subversion calls this a working copy of the repository files, and this cor-
2151responds to the SCM “private workspace†pattern.
2152M AKING C HANGES 40
2153After saving these changes to disk, let’s see what Subversion
2154now thinks about the state of our project. You can use the svn
2155status command to get the status of one or more files:
2156sesame > svn status Day.txt
2157M Day.txt
2158The M here is showing us that Subversion recognizes that this
2159file has been modified locally (and that these changes have
2160not yet been saved in the repository).
2161If we do all our work in small increments, it’s easy to remem-
2162ber what changes we made to individual files. However, if
2163you’ve forgotten why a file has been modified (or if you just
2164want to double-check), you can use the svn diff command to
2165show the changes between the repository version of the file
2166and your local copy:
2167sesame > svn diff Day.txt
2168Index: Day.txt
2169===================================================================
2170--- Day.txt (revision 1)
2171+++ Day.txt (working copy)
2172@@ -3,3 +3,5 @@
2173wednesday
2174thursday
2175friday
2176+saturday
2177+sunday
2178The output contains a bunch of information. The first line
2179tells us the name of the file being examined. This has a couple
2180of uses. First, if we’re examining a bunch of files with one
2181command, it helps us identify where we are. Second, it is also
2182used when generating patches (but that’s not something we’ll
2183be looking at for a while yet).
2184The two lines after the row of equals signs tell us the name
2185and revision number of the repository file and that we’re com-
2186paring it with the working copy.
2187The cryptic @@ -3,3 +3,5 @@ tells us where in the file the
2188differences are, followed by the actual difference. The lines
2189starting with + mean they’ve been added, and a line starting
2190with - would mean it has been removed.
2191This diff is shown in unified format, meaning that it contains
2192context information as well as lines that have been changed.
2193It’s a popular format because it’s easy to read, and the extra
2194U PDATING THE R EPOSITORY 41
2195context allows changes to be applied even if the original file
2196has been altered slightly. Subversion also allows us to specify
2197our own diff program using --diff-cmd . This is useful if we want
2198to use a graphical diff utility, for example.
2199This is an area where the GUI front ends to Subversion have a
2200distinct advantage: if you use such a tool, you should be able
2201to generate nice color-coded displays of file differences.
2202In addtion, the Subversion diff command can show differences
2203between your working copy and a specific repository version,
2204or between two versions within the repository. Section 6.6,
2205Using Subversion Revision Identifiers, on page 80 discusses
2206diff options in more detail.
22073.6 Updating the Repository
2208Having made our changes (and of course having run the unit
2209tests), we’re ready to save our latest version in the repository.
2210On a single-person project such as Sesame, this is really very
2211simple—you use the svn commit command:
2212sesame > svn commit -m "Client wants us to work on weekends"
2213Sending Day.txt
2214Transmitting file data .
2215Committed revision 2.
2216The commit function is used to save any changes we’ve made
2217back to the repository. The -m option is used to attach a
2218meaningful message to the changes.
2219Even though we asked Subversion to commit all files in the
2220Sesame project, it’s clever enough to know that Number.txt has
2221not changed, so only the changes in Day.txt are sent to the
2222repository.
2223Subversion tells us it has “committed revision 2.†It’s impor-
2224tant to note that this means revision 2 of the whole repository,
2225not just Day.txt . If we had changed both Day.txt and Number.txt ,
2226we’d still be at revision 2 in the repository. You can think of
2227Subversion revision numbers as kind of a global marker going
2228all the way through the repository, recording when each set of
2229changes went in.
2230Following the commit, you can use the log function to confirm
2231that the repository has indeed been updated:
2232U PDATING THE R EPOSITORY 42
2233sesame > svn log Day.txt
2234---------------------------------------------------------
2235r2 | mike | 2004-09-08 21:54:19 -0600 (Wed, 08 Sep 2004)
2236Client wants us to work on weekends
2237---------------------------------------------------------
2238r1 | mike | 2004-09-08 21:50:13 -0600 (Wed, 08 Sep 2004)
2239importing Sesame project
2240---------------------------------------------------------
2241We can see that mike was the last user to change Day.txt , in
2242revision 2 ( r2 ) of the repository, and we can see the log mes-
2243sage that was used when adding Saturday and Sunday to our
2244list of days. We can also see that Day.txt was changed in revi-
2245sion 1, when we imported the Sesame project. If you use
2246--verbose , Subversion will tell you exactly what changed with
2247each revision:
2248sesame > svn log --verbose Day.txt
2249---------------------------------------------------------
2250r2 | mike | 2004-09-08 21:54:19 -0600 (Wed, 08 Sep 2004)
2251Changed paths:
2252M /sesame/trunk/Day.txt
2253Client wants us to work on weekends
2254---------------------------------------------------------
2255r1 | mike | 2004-09-08 21:50:13 -0600 (Wed, 08 Sep 2004)
2256Changed paths:
2257A /sesame
2258A /sesame/trunk
2259A /sesame/trunk/Day.txt
2260A /sesame/trunk/Number.txt
2261importing Sesame project
2262---------------------------------------------------------
2263Now that Subversion is being extra talkative, we can see that
2264in revision 2 /sesame/trunk/Day.txt was modified—there’s an M
2265next to it. For revision 1, we can see that the /sesame directory
2266and contents were created. Because of the way Subversion
2267tracks commits—changes to a set of files, all saved at once
2268and associated with a single log message—it can display all
2269the files that were changed in each commit, even though we
2270asked only about Day.txt . This can be extremely useful, for
2271example, when reviewing historical information when tracking
2272down a bug.
2273Mixed Revision Working Copies
2274In the last example we used svn log to look at the history of
2275Day.txt . In fact, using svn log without any other arguments pro-
2276duces a log for the current directory and any subdirectories,
2277starting with the most recent changes and working backward.
2278U PDATING THE R EPOSITORY 43
2279Setting Up a Message Editor
2280Whenever you change the repository by importing
2281files, committing changes, or copying things around,
2282you need to enter a log message. If you don’t specify
2283the -m option, Subversion will try to open an editor for
2284you to type in a log message.
2285Subversion looks at environment variables to deter-
2286mine which editor it should use, trying SVN EDITOR ,
2287VISUAL , and EDITOR . If you’re on Windows andwould
2288like to set your editor to Notepad, open a command
2289prompt and type
2290work > set SVN EDITOR=notepad
2291This will set SVN EDITOR only for the lifetime of your
2292command window. If you want to set the environ-
2293ment variable permanently, you need to go into Win-
2294dows’ Control Panel (switch to Classic View if you’re
2295using Windows XP) and choose System. Under the
2296Advanced tab, hit the Environment Variables but-
2297ton, and create a new variable. The variable name
2298should be SVN EDITOR , and the value should be
2299notepad . After setting up the new environment vari-
2300able, you’ll need to close any open command win-
2301dows and re-open them for the new setting to take
2302effect.
2303If you’re a Unix user, you’ll set environment variables
2304differently depending on the shell you’re using. Try
2305looking at .profile , .bashrc , or .cshrc in your home direc-
2306tory for existing environment variables, and then add
2307a new one. You may need to log out and back in
2308again for a new setting to take effect.
2309W HEN W ORLDS C OLLIDE 44
2310If you ask for the log of the current directory immediately
2311after committing a change to Day.txt , Subversion won’t tell you
2312about your change. This is a bit counterintuitive—after all the
2313change is in the repository, we can see it if we ask for the log
2314for Day.txt —so why isn’t Subversion including it in the log for
2315the current directory?
2316The answer is that because Subversion tracks directories as
2317first-class objects, it remembers the revision number for each
2318directory in your working copy. When we commit a change to
2319Day.txt , Subversion knows the working copy is at revision 2,
2320but the actual directory is still at revision 1. In order to see
2321the log message, you’ll need to run svn update first, updating
2322the current directory to revision 2.
2323Most of the time you can just ignore mixed revisions. If you
2324do get tripped up by this behavior, a quick svn update will fix
2325the problem. In the recipes shown later in the book, we’ll
2326often include an update as the first step, helping to avoid this
2327problem altogether.
23283.7 When Worlds Collide
2329Everyone gets nervous when they first hear that Subversion
2330doesn’t lock files for editing. They wonder, “what happens if
2331two people edit the same file at the same time?†In this sec-
2332tion we’ll find out (and hopefully in the process put to rest any
2333worries you may have). To do this, we’ll need another user (so
2334that we can have multiple people editing a file at the same
2335time). Unfortunately, our supplier of do-it-yourself human
2336cloning kits is on the run, so we’ll have to make do with sim-
2337ulating the other you.
2338When it comes to handling conflicts, Subversion doesn’t really
2339know about users. Instead, it cares about making sure that
2340different working copies are consistent with the repository.
2341This means we can simulate our second user simply by check-
2342ing out a new copy of our project; we just need to put it in a
2343different place than the first copy. When we first checked out
2344our project, we put it in a directory called sesame , which is
2345the project name. To check it out again, we’ll need to specify
2346a different location, a directory parallel to the one we’ve been
2347W HEN W ORLDS C OLLIDE 45
2348working in. Let’s call that directory aladdin . To check out on
2349Windows, change to your work directory and run
2350work > svn co file:///c:/svn-repos/sesame/trunk aladdin
2351A aladdin \ Number.txt
2352A aladdin \ Day.txt
2353Checked out revision 2.
2354On a Unix system, you need to run
2355work > svn co file:///home/mike/svn-repos/sesame/trunk aladdin
2356A aladdin/Number.txt
2357A aladdin/Day.txt
2358Checked out revision 2.
2359We’ve checked out the project we’ve been working on all along
2360(Sesame) from the same repository. But we tell Subversion to
2361store the files in a new directory, called aladdin . Because we
2362checked in the files from our original directory, we now have
2363two copies of the project on our hard drive, one in sesame , the
2364other in aladdin . Right now the two sets of files are identical
2365(skeptical readers, feel free to check). Remember that two
2366different directories are our simulation of having two people
2367working on our project, each with their own checked-out copy
2368of the files.
2369Let’s first do a quick sanity check. We’ll alter a file in one
2370directory, check it in, and then ask Subversion to update our
2371local copy in the other directory.
2372First, edit the file Number.txt in the sesame directory, adding
2373two new lines (five and six):
2374zero
2375one
2376two
2377three
2378four
2379five
2380six
2381Now check this file into the repository:
2382sesame > svn commit -m "Customer wants more numbers"
2383Sending Number.txt
2384Transmitting file data .
2385Committed revision 3.
2386Now for the first moment of truth. Over in the aladdin direc-
2387tory, its version of Number.txt is now out-of-date (because the
2388repository now holds a more recent version). Let’s pop over
2389there and check:
2390W HEN W ORLDS C OLLIDE 46
2391sesame > cd ..
2392work > cd aladdin
2393aladdin > svn status --show-updates
2394* 2 Number.txt
2395Status against revision: 3
2396We’re using --show-updates (short form -u ) to get Subversion to
2397talk to the repository and find out if any updates are available
2398for files in the aladdin directory. We need to use this option
2399because by default Subversion just checks to see whether files
2400in the working copy have been locally modified, not whether
2401an updated version is available in the repository.
2402The asterisk shows that an update is available for Number.txt ,
2403which is currently at revision 2. Subversion also tells us that
2404the repository was at revision 3 when it performed the check.
2405Before we update to the latest version, we might ask Subver-
2406sion to tell us what’s different between our version of the file
2407and the version currently in the repository (as there are times
2408when you may want to defer an update if it affects stuff you’re
2409currently working on). Again, we use the svn diff command:
2410aladdin > svn diff -rHEAD Number.txt
2411Index: Number.txt
2412===================================================================
2413--- Number.txt (revision 3)
2414+++ Number.txt (working copy)
2415@@ -3,5 +3,3 @@
2416two
2417three
2418four
2419-five
2420-six
2421The -rHEAD option tells Subversion we want to compare our
2422local copy of Number.txt against whatever revision is the most
2423recent in the repository. After another one of those cryptic @@
2424-3,5 +3,3 @@ lines, we see that the two new lines are miss-
2425ing from our working copy (which shouldn’t be a surprise).
2426If we hadn’t specified the -r flag, Subversion would compare
2427our local copy of Number.txt against the repository version that
2428was checked out to produce it (r2 in this case). As we haven’t
2429altered the file in our Aladdin persona, this would show no
2430changes.
2431We can update our copy in the aladdin directory to merge in
2432the changes we made over in sesame :
2433aladdin > svn update
2434U Number.txt
2435Updated to revision 3.
2436C ONFLICT R ESOLUTION 47
2437Subversion prints U next to Number.txt to let us know that it
2438has updated it and tells us that our working copy has been
2439updated to revision 3. If we look at Number.txt , we’ll see that
2440we now have the two extra lines.
24413.8 Conflict Resolution
2442So, what happens if two people edit the same file at the same
2443time? It turns out that there are two scenarios. The first is
2444when the changes don’t overlap. Simulating this takes a little
2445effort, so hang in there.
2446First, edit the copy of Number.txt in the sesame directory. Make
2447the first line uppercase:
2448ZERO
2449one
2450two
2451three
2452four
2453five
2454six
2455Number.txt (in Sesame)
2456Now edit the version of Number.txt over in aladdin . This time
2457make the last line uppercase:
2458zero
2459one
2460two
2461three
2462four
2463five
2464SIX
2465Number.txt (in Aladdin)
2466What we’ve just done is simulate two developers each mak-
2467ing local changes to the same file. Right now, these changes
2468are independent, because the repository knows about neither.
2469Let’s change that. A coin toss told us that Aladdin checked in
2470his version of the changed file first:
2471aladdin > svn commit -m "Make ' six ' important"
2472Sending Number.txt
2473Transmitting file data .
2474Committed revision 4.
2475A short time later, the sesame developer tries to check in too.
2476(Remember, this version of the file has the first line in upper-
2477case.)
2478sesame > svn commit -m "Zero needs emphasizing"
2479Sending Number.txt
2480svn: Commit failed (details follow):
2481svn: Out of date: ' /sesame/trunk/Number.txt ' in transaction ' 7 '
2482C ONFLICT R ESOLUTION 48
2483Subversion is telling us that it tried to commit the change
2484from sesame , but it failed because /sesame/trunk/Number.txt is
2485out-of-date. Let’s try bringing our local version of the file up-
2486to-date with the repository. Remember that our file has an
2487uppercase zero, and the repository version has an upper case
2488six.
2489sesame > svn update
2490G Number.txt
2491Updated to revision 4.
2492Subversion prints a G to tell us it has merged our changes
2493with the repository version (previously, it printed U to let us
2494know it had updated our working copy with a new version
2495from the repository). Let’s look at our local version:
2496ZERO
2497one
2498two
2499three
2500four
2501five
2502SIX
2503Magic! Our version now contains both our changes and the
2504Aladdin changes. We both edited a file at the same time, and
2505Subversion worked it out.
2506Before we get too smug, though, remember that our local
2507change (the ZERO ) hasn’t yet been stored in the repository. We
2508ask Subversion to commit our change, and this time it suc-
2509ceeds, because our local version contains the latest repository
2510revisions:
2511sesame > svn commit -m "Zero needs emphasizing"
2512Sending Number.txt
2513Transmitting file data .
2514Committed revision 5.
2515The next time Aladdin updates, he’ll get our changes too:
2516sesame > cd ..
2517work > cd aladdin
2518aladdin > svn update
2519U Number.txt
2520Updated to revision 5.
2521Butting Heads—When Changes Clash
2522In the previous example, the changes made by the two (vir-
2523tual) developers didn’t overlap. What happens if two develop-
2524ers edit the same lines in the same file at the same time? Let’s
2525find out.
2526C ONFLICT R ESOLUTION 49
2527Go into the sesame directory and change the second line in
2528Number.txt from one to ichi. Don’t check this change in. Now
2529go across to the aladdin directory and change the same line
2530from one to uno. Let’s assume that once again Aladdin gets to
2531check in his changes first:
2532aladdin > svn commit -m "User likes Italian one"
2533Sending Number.txt
2534Transmitting file data .
2535Committed revision 6.
2536Now let’s go back to the sesame directory. Remembering that
2537we’re supposed to be simulating two separate users, we pre-
2538tend we don’t know about the changes made by Aladdin, and
2539so try to check in our changes:
2540sesame > svn commit -m "One should be Japanese"
2541Sending Number.txt
2542svn: Commit failed (details follow):
2543svn: Out of date: ' /sesame/trunk/Number.txt ' in transaction ' c '
2544We’ve seen this message before: we need to update to get the
2545repository changes:
2546sesame > svn update
2547C Number.txt
2548Updated to revision 6.
2549Subversion tells us it has managed to update Sesame’s work-
2550ing copy to revision 6, but the C next to Number.txt tells us
2551that there was a conflict when it tried to merge the repository
2552changes with our local changes. Have we lost all our hard
2553work? No.
2554CVS Hint: When CVS detects a conflict, it’ll print a whole bunch of
2555warning messages and generally tell you the sky is falling. This is to
2556remind you to fix the conflict, as it’s very easy to check in a file that
2557still has conflict markers left in it. Subversion tracks the file’s state so it
2558knows whether you’ve resolved the conflict, and won’t let you check
2559in until things are okay.
2560When conflicts happen, it’s most often because two develop-
2561ers had some kind of misunderstanding. In this case, one
2562developer wanted to change the line to Italian, and the other
2563wanted Japanese. If you think about this, it becomes appar-
2564ent that what we have here is a breakdown in communication;
2565there’s a problem in the team (or at least in the team’s pro-
2566cess). Whatever the cause, we’re left wondering, “what should
2567the line really be?†Subversion doesn’t have a hot line to the
2568C ONFLICT R ESOLUTION 50
2569truth, so it can’t solve the problem. Instead, it adds special
2570annotations to the file to show what the conflict is. In this
2571case if we look at the file Number.txt , we’ll see it now looks like:
2572ZERO
2573<<<<<<< .mine
2574ichi
2575=======
2576uno
2577>>>>>>> .r6
2578two
2579three
2580four
2581five
2582SIX
2583The lines with the <<<<<<< and >>>>>>> show where the
2584conflict occurred. Between them we can see both our change
2585and the conflicting change in the repository.
2586Time to do some detective work. The first thing we need to do
2587is to find out who made the change in the repository. We’ll use
2588svn log to help us find out what happened here. The conflict
2589markers seem to suggest r6 is causing the problem:
2590sesame > svn log -r6 Number.txt
2591---------------------------------------------------------
2592r6 | mike | 2004-09-08 23:01:03 -0600 (Wed, 08 Sep 2004)
2593User likes Italian one
2594---------------------------------------------------------
2595Looking at the log entry, we can see the name of the author
2596of the change, along with their check in comment. We wander
2597over and ask him about the change. A quick call to the cus-
2598tomer resolves the problem: the customer wanted the word
2599one in Japanese, and two in Italian. Aladdin must have mis-
2600heard.
2601Armed with this new information, we can now resolve the con-
2602flict. Edit Number.txt in the sesame directory, remove Subver-
2603sion’s conflict markers, and make the changes requested by
2604the customer:
2605ZERO
2606ichi
2607due
2608three
2609four
2610five
2611SIX
2612Having removed the conflict markers, we can tell Subversion
2613we’ve resolved the conflict and then commit the file:
2614sesame > svn resolved Number.txt
2615Resolved conflicted state of ' Number.txt '
2616C ONFLICT R ESOLUTION 51
2617sesame > svn commit -m "One is Japanese, two Italian"
2618Sending Number.txt
2619Transmitting file data .
2620Committed revision 7.
2621Subversion actually helped us discover a misunderstanding.
2622We resolved the conflict, and everyone is happy. Optimistic
2623locking may actually deserve its name. And, just to make
2624things even less scary, we need to emphasize that conflicts
2625rarely happen on real projects.
2626However, it’s also worth noting that Subversion is not a mind-
2627reader. It might happen that two people fix the same bug
2628in two different ways. If these changes don’t conflict at the
2629source code level, Subversion will happily accept both, even
2630though it may make no sense to have both fixes in the same
2631code. The lack of a conflict means you haven’t trodden on
2632anyone else’s changes at the textual level, but you should still
2633rely on unit tests to verify that the change works.
2634Subversion also supports strict locking for unmergeable files
2635such as sound, graphics and video. Chapter 7, File Locking
2636and Binary Files, on page 99 discusses file locking in more
2637detail.
2638That’s all for our quick tour around Subversion. However, you
2639may want to leave your test repository lying around. Later,
2640you might find it helpful if you want to experiment with a par-
2641ticular facility before doing it for real in the project repository.
2642Chapter 4
2643How To...
2644Even though version control sounds great in theory, many
2645teams don’t use it. Sometimes this is because the theory
2646doesn’t seem to translate into practice too well. It’s all very
2647well reading a document that says something like “generate
2648a release branch,†but what does that actually mean when it
2649comes down to typing in the correct Subversion commands?
2650Another problem is that teams sometimes embrace version
2651control too vigorously, creating very complex structures to
2652hold their source, with correspondingly frightening lists of
2653instructions for achieving even the simplest task. The result?
2654Eventually (and in our experience that means very quickly),
2655the team gives up; using the version control system is seen to
2656be just too much hassle.
2657The remaining chapters in this book address both of these
2658problems. They present a simple way to organize your version
2659control system and a set of basic practices for doing the every-
2660day things a team needs to do. We suggest to start you use
2661these basic practices as a set of recipes; follow them whenever
2662you need to achieve a certain result. Try hard not to deviate
2663too much from them; if you find yourself wanting to create a
2664scenario we don’t cover, think hard before proceeding. Per-
2665haps you don’t really need it.
2666As with any set of recipes, you’ll soon find yourself feeling
2667more and more comfortable following them. This is the time
2668to start some gentle experimenting. However, we suggest you
2669don’t try something new directly in a real project’s repository.
2670O UR B ASIC P HILOSOPHY 53
2671Instead, set up the scenario in a test repository (such as the
2672one we set up in the previous chapter), and try things out
2673there.
26744.1 Our Basic Philosophy
2675We think version control is one of the three essential techni-
2676cal practices; every team needs to be proficient in all three (the
2677others are Pragmatic Unit Testing [HT03], [HT04], and Prag-
2678matic Project Automation [Cla04]). Every team should be using
2679version control—all the time, and for everything they pro-
2680duce. So we have to make it simple, obvious, and lightweight
2681(because if we don’t, people will eventually stop doing it).
2682Simplicity means that doing something that should be simple
2683will actually be simple. Checking in our changes is a simple
2684(and common) operation, so the basic operation should be one
2685or two actions. Creating a new customer release is a some-
2686what more complex concept, so it’s okay to use a few more
2687steps doing it, but it should still be as simple as possible.
2688Version control has to be obvious: we need to arrange things
2689so that it is clear what we’re doing and what version of the
2690software we’re doing it to. There should be no guessing when
2691it comes to the source.
2692Finally, we’re describing a lightweight process; we don’t want
2693version control to get in the way of getting real work done.
26944.2 Important Steps When Using Version
2695Control
2696Here is our basic set of rules for organizing your source in a
2697Subversion repository:
2698• Before you start, you need to establish an effective and
2699secure way to access your repository.
2700• Once you’ve gained access, there is a simple set of Sub-
2701version commands that you’ll be using daily.
2702• Each project that your company develops must be stored
2703in a distinct directory within the Subversion repository.
2704I MPORTANT S TEPS W HEN U SING V ERSION C ONTROL 54
2705You should be able to check out a project’s complete
2706source from a single point.
2707• If projects contain subcomponents that can be worked
2708on in isolation, or if you intend to share components
2709between projects, these components should be stored as
2710projects in their own right and included as an external
2711resource in other projects.
2712• If your project incorporates code from third parties (ven-
2713dors, or perhaps open-source projects) you need to man-
2714age this as a resource.
2715• Developers should use branches to separate the main
2716line of development from code lines that have different
2717life cycles, such as release branches and major code
2718experiments. Tags are used to identify significant points
2719in time, including releases and bug fixes.
2720We cover each of these topics in the chapters that follow.
2721Chapter 5
2722Accessing a Repository
2723In Chapter 3, Getting Started with Subversion, on page 28,
2724we created a repository and learned how to access it via a
2725file-based URL. This is great for a single user but doesn’t
2726really help a whole development team collaborate properly.
2727In this chapter we’ll discuss the three main ways you can
2728make an existing repository available over the network, what
2729they mean for a user accessing a repository, and the pros and
2730cons of the various access mechanisms.
2731Appendix A on page 151 includes a guide for administrators
2732who are installing, networking, and securing Subversion.
27335.1 Network Protocols
2734After creating our sandbox repository, we used a repository
2735URL to tell Subversion what we wanted to check out. This repository URL
2736URL included both a definition of where the repository was
2737and also what path inside the repository we were interested
2738in. Once we had a working copy we didn’t need to keep using
2739the repository URL, since Subversion remembers where our
2740working copy came from.
2741Repository URLs are important whenever we want to directly
2742access a repository (when we’re creating branches and tags or
2743merging big sets of changes, for example). Figure 5.1 on the
2744following page shows how the URL for our sandbox repository
2745is composed.
2746The first part of this URL is file . This specifies the scheme scheme
2747we’re using to locate the repository, in this case the local
2748N ETWORK P ROTOCOLS 56
2749????????????????? ?? ?? ? ?????
2750? ? ? !"#$%
2751&
2752'
2753$
2754(
2755)
2756*
2757$?+
2758'
2759&
2760$,-+
2761'
2762? .
2763&
2764'
2765?
2766&
2767,
2768(
2769#$%
2770&
2771'
2772$
2773(
2774)
2775Figure 5.1: Components of a Repository URL
2776filesystem. The next part, c:/svn-repos , tells Subversion
2777the repository database files are in a particular directory on
2778the C: drive. Finally, /sesame/trunk/ specifies the path
2779within the repository that we’re interested in.
2780Subversion supports a number of different schemes in repos-
2781itory URLs and even allows you to define custom extensions
2782yourself. Each different scheme tells Subversion to access
2783the repository via a particular network protocol. We’ll start by
2784looking at the simple svn protocol.
2785svn
2786The easiest way to network a repository is to use the svn
2787scheme. Subversion comes with svnserve , a small server that
2788listens for network connections, allows repository access over
2789the network, and supports simple authentication of users.
2790svnserve is probably most suitable for teams on a private LAN
2791who want to get going quickly.
2792If an administrator (possibly you!) has used the instructions
2793in Section A.2, Networking with svnserve, on page 153 to put
2794the Sesame repository online, you can check it out by running
2795work > svn co svn://olio/sesame/trunk vizier
2796A vizier/Number.txt
2797A vizier/Day.txt
2798Checked out revision 7.
2799Success! We used the svn scheme to access a repository on a
2800machine called olio , and we checked out the Sesame project
2801to a new vizier working directory.
2802If you’ve tried playing with the working copy on your client
2803machine, you might find that Subversion doesn’t let you com-
2804N ETWORK P ROTOCOLS 57
2805mit any changes. For example, try adding a new data file,
2806Month.txt , to the project:
2807vizier > svn add Month.txt
2808A Month.txt
2809vizier > svn commit -m "Added month data"
2810svn: Commit failed (details follow):
2811svn: Connection is read-only
2812If this happens, your administrator has forgotten to enable
2813write access to the repository (it’s read-only by default). Get
2814them to look at Section A.5, svnserve, on page 163 and set up
2815some users. Once they’ve done this, you should be asked for
2816a username and password when you try to commit a change:
2817vizier > svn commit -m "Added month data"
2818Authentication realm: < svn://olio:3690 > sesame/trunk
2819Password for ' mike ' :
2820Adding Month.txt
2821Transmitting file data .
2822Committed revision 8.
2823Subversion decided to try username mike because that’s my
2824username on the client machine. If this isn’t right, just hit
2825Enter at the password prompt, and Subversion will let you
2826specify a different username.
2827svn+ssh
2828svnserve does a great job of getting a repository up on the net-
2829work, but it has a couple of drawbacks. Firstly, although
2830passwords are never transmitted in clear text over the net-
2831work, the contents of your files travel unencrypted. Anyone
2832who can sniff your network traffic can see what your files con-
2833tain. This might be okay for a team all on the same LAN, but if
2834you want to use the public Internet for accessing your repos-
2835itory it simply isn’t secure. Secondly, passwords are stored
2836in plain text in the server’s conf directory and can only be
2837changed by an administrator with access to the password file.
2838Subversion solves both of these security problems by leverag-
2839ing the Secure Shell (SSH). If you’re a Unix user, you might Secure Shell
2840already have SSH infrastructure in place for connecting to
2841your server. SSH employs strong encryption to protect the
2842contents of a client-server session. It is widely used for admin-
2843istering servers over the Internet. Figure 5.2 on the next page
2844shows how Subversion secures an svn connection using SSH.
2845N ETWORK P ROTOCOLS 58
2846/ 0 1
2847/ /2
2848/01/ 3
28494
285003
2851// 2 5
2852678
28539
2854: ;
2855<
2856=7
285711 3
2858:
2859>
28609
28617
28621
2863?@ A
2864B
2865C D
2866E
2867F GHI @ @FA
2868E
2869J
2870I@
2871Figure 5.2: Tunnel Subversion Over SSH
2872Subversion needs an SSH client installed on your machine
2873in order for you to access a repository using svn+ssh . Unix
2874users are likely to have SSH already installed, but if you’re on
2875Windows, you’ll need to do a bit of work. Putty is an excel-
2876lent SSH client and is available from http://www.chiark.
2877greenend.org.uk/ ˜ sgtatham/putty/ . Download plink.exe ,
2878and save it somewhere in your path; C:\Windows\system32 usu-
2879ally works. If you’re using TortoiseSVN you don’t need to
2880worry about installing an SSH client since Tortoise comes with
2881TortoisePlink .
2882Next you need to edit your Subversion client configuration
2883settings. Windows applications store user-specific data inside
2884a special folder, which changes location depending upon how
2885your computer is set up and which version of Windows you’re
2886using. If you’re not sure where your application data directory
2887is, open a command prompt and run the following:
2888work > echo %APPDATA%
2889C: \ Documents and Settings \ mike \ Application Data
2890Once you’ve found your application data directory, open the
2891Subversion subdirectory, and edit the config file that’s inside.
2892Edit the section on tunnels so it looks like this:
2893[tunnels]
2894ssh=plink
2895You need to specify a svn+ssh scheme if you’d like Subversion
2896to use SSH to protect your connections. If your server accepts
2897SSH connections, try running
2898N ETWORK P ROTOCOLS 59
2899work > svn checkout \
2900svn+ssh://olio/home/mike/svn-repos/sesame/trunk \
2901princess
2902mike@olio ' s password:
2903A princess/Month.txt
2904A princess/Number.txt
2905A princess/Day.txt
2906Checked out revision 8.
2907This looks just like the repository URL we used earlier with
2908svnserve , except we changed the scheme to svn+ssh . If you’re
2909having problems accessing your repository, Section A.3, Trou-
2910bleshooting an SSH Connection, on page 156 contains a guide
2911to diagnosing the problem.
2912Subversion is now using SSH to open a connection to the
2913server and authenticate you as a Unix user. Subversion uses
2914the standard Unix user and group permissions to determine
2915whether the user with which we connect has permission to
2916access the repository. If you’re using SSH public/private keys
2917or an SSH agent to manage your credentials, the Subver-
2918sion client automatically takes advantage of this, which might
2919mean you don’t get asked for a password at all.
2920Using svn+ssh is appealing if you already have SSH accounts
2921for your users, because you can leverage all your existing
2922infrastructure. The extra security lets you connect over the
2923Internet without fear that someone might steal your Sesame
2924project code and without all the hassle of setting up a full
2925VPN. svn+ssh is a straightforward solution that should have
2926you up and running pretty fast.
2927http
2928Subversion can also host a repository over the web by using
2929the Apache web server. A special Subversion module, called
2930mod dav svn , does the hard work and allows Subversion to
2931share the web server with traditional web sites. Apache is
2932highly configurable, and Subversion takes full advantage of
2933its built-in security and scalability. You can host a reposi-
2934tory using standard http and https and leverage any of the
2935authentication mechanisms already supported by Apache.
2936You may have heard that Subversion requires Apache—this
2937actually isn’t true; neither svn nor svn+ssh need anything
2938C HOOSING A N ETWORKING O PTION 60
2939extra to network your repository. Most prebuilt Unix pack-
2940ages have a dependency on Apache because they install all
2941three networking options, which is where the misunderstand-
2942ing comes from. Using Subversion with Apache is probably
2943the most popular solution for sharing a repository over the
2944Internet.
2945Apache provides a wealth of authentication options for users.
2946From basic authentication using password files to integra-
2947tion with a Windows domain or an LDAP server, Apache is
2948supremely flexible. You can even set up directory-based secu-
2949rity, dividing your repository into read-only or even completely
2950private sections. You can take advantage of standard SSL
2951certificates for encrypting connections to the server and avoid
2952firewall hassles by using standard web server port numbers.
2953To access a repository hosted by Apache on server olio , use
2954the following command:
2955work > svn checkout \
2956http://olio.mynetwork.net/svn-repos/sesame/trunk \
2957sesame
2958Authentication realm: ... Subversion repository
2959Password for ' mike ' : ******
2960A sesame/Month.txt
2961A sesame/Number.txt
2962A sesame/Day.txt
2963Checked out revision 8.
2964This particular repository requires an authenticated user even
2965for read-only access. Subversion automatically tries user-
2966name mike ; if that’s wrong, just hit Enter instead of typing a
2967password, and Subversion will let you specify the username.
29685.2 Choosing a Networking Option
2969All three network protocols for Subversion ( svn , svn+ssh and
2970http ) offer different trade-offs in terms of ease of setup, secu-
2971rity, and administration overhead. Which you choose will
2972depend on what kind of infrastructure you already have, your
2973security needs, and your familiarity with Apache.
2974It’s important to note that the networking option you choose
2975today doesn’t have to be the one you stick with tomorrow. Net-
2976working a repository simply puts it on the network—you can
2977change between svnserve and Apache (for example) as often as
2978C HOOSING A N ETWORKING O PTION 61
2979you like. It’s also possible to support multiple different access
2980mechanisms at the same time, although you have to be careful
2981with permissions.
2982If your team is on a reasonably secure LAN, or even a larger
2983network connected by a VPN, using the simple svnserve server
2984and svn protocol is a quick way to get up and running with
2985Subversion. You’ll have some administrative overhead when
2986adding new users or changing passwords, but this should be
2987offset by the easy startup. Subversion 1.3 added directory-
2988based authorization to svnserve making it almost as flexible as
2989Apache for teams on the same LAN.
2990If you already have existing SSH infrastructure in place, using
2991svn+ssh makes a lot of sense. You get strong crypto protect-
2992ing your connections and can take advantage of all of the key-
2993management and authentication options that SSH provides.
2994Make sure your Unix administrator understands how groups,
2995umasks, and sticky bits need to be set up before proceeding,
2996though.
2997If you want to host a repository over the Internet, leverage
2998Apache’s wide range of authentication mechanisms, or simply
2999play with the big boys and run a “real†server, using Apache
3000to host your Subversion repository is the way to go. You’ll be
3001able to use SSL and client-server certificates for encryption
3002and verifying you’re really talking to whom you think you’re
3003talking to, and you’ll be able to authorize users using a Win-
3004dows domain, LDAP, or any other authentication mechanism
3005that Apache supports. You’ll also be able to be much more
3006precise about which parts of a repository users have access
3007to, by leveraging the mod authz svn Apache module. Using
3008Apache on standard HTTP ports also means fewer holes need
3009to be opened on your firewalls. Your network administrator
3010will thank you for that.
3011Chapter 6
3012Common Subversion
3013Commands
3014In Chapter 3, Getting Started with Subversion, on page 28 we
3015created a simple project and experimented with basic Sub-
3016version commands. In this chapter we’ll take this further by
3017presenting a set of recipes: the Subversion commands that
3018you use to do everyday tasks.
3019This section is not exhaustive. Later in this book we’ll be look-
3020ing at more advanced issues, such as release management,
3021workspaces, and third-party code. However, the commands
3022and techniques in this chapter should handle 90 percent of
3023the work you do with Subversion.
3024These examples assume you have your repository up and run-
3025ning and that you’ve enabled network access. We’ll assume
3026the Sesame project’s main code line (the trunk) is located at
3027svn://olio/sesame/trunk . You’ll need to use your own
3028server name instead of olio and the right access scheme if
3029you’re using http or svn+ssh instead of the basic svn .
30306.1 Checking Things Out
3031The svn checkout command (often abbreviated co ) gets Subver-
3032sion to create a new working copy from a directory stored in
3033the repository. In its simplest form, the checkout command
3034creates a working copy in a directory with the same name as
3035the repository directory:
3036C HECKING T HINGS O UT 63
3037work > svn checkout svn://olio/sesame/trunk
3038A trunk/Month.txt
3039A trunk/Number.txt
3040A trunk/Day.txt
3041Checked out revision 8.
3042Here, Subversion created the working copy in a local trunk
3043directory, because that’s the name of the directory in the
3044repository. This might not be what you want, especially if
3045you’re following the conventions recommended in Chapter 8,
3046Organizing Your Repository, on page 107. You can use an
3047extra argument when checking out to specify the name of the
3048directory Subversion should use for your working copy:
3049work > svn checkout svn://olio/sesame/trunk sesame
3050A sesame/Month.txt
3051A sesame/Number.txt
3052A sesame/Day.txt
3053Checked out revision 8.
3054By default, Subversion checks out the latest revision stored in
3055the repository. If you’d like an older version, use the -r option
3056to specify the revision number or date you’d like. Section 6.6,
3057Using Subversion Revision Identifiers, on page 80 contains full
3058details on how to refer to a particular revision.
3059To check out a copy of the Sesame project before we added
3060Month.txt , we can specify revision 7:
3061work > svn checkout -r 7 svn://olio/sesame/trunk old-sesame
3062A old-sesame/Number.txt
3063A old-sesame/Day.txt
3064Checked out revision 7.
3065If you’re like us, you’ll probably end up with a bunch of differ-
3066ent working copies in your work directory. To figure out where
3067a working copy came from, use the svn info command:
3068work > svn info sesame
3069Path: sesame
3070URL: svn://olio/sesame/trunk
3071Repository UUID: d6959e13-a0e3-0310-8d55-a8c2e0b5e323
3072Revision: 34
3073Node Kind: directory
3074Schedule: normal
3075Last Changed Author: mike
3076Last Changed Rev: 7
3077Last Changed Date: 2004-10-05 13:07:15 -0700 (Tue 5 Oct 2004)
3078The important bit here is the URL on the second line. Sub-
3079version is telling us that the sesame directory on the local
3080machine originally came from svn://olio/sesame/trunk/ .
3081K EEPING U P - TO -D ATE 64
30826.2 Keeping Up-to-Date
3083If you’re not the only person working on a project, the chances
3084are pretty good that the repository is being updated by others
3085even as you are working. It’s a good idea to incorporate their
3086changes into your working copy fairly frequently; the longer
3087you leave it, the bigger the hassle of fixing any conflicts. 1 We
3088typically update our working copies every hour or so through-
3089out the day.
3090The svn update command is used within a working copy and
3091brings all the files in the directory (and its subdirectories) up-
3092to-date with the repository. Files and directories added to
3093the repository will be added to the working copy, and files
3094and directories removed from the repository will be removed
3095from the working copy. The following command updates the
3096working copy of the Sesame project:
3097work > cd sesame
3098sesame > svn update
3099You can choose to update just part of your checked-out tree.
3100If you issue the command in a subdirectory of a project, then
3101only files at or below that point will be updated. This may
3102save time, but it also leaves you exposed to working on an
3103inconsistent set of files.
3104You can also specify one or more individual files or directories
3105to update by naming them on the command line:
3106main > svn update build.xml src/ test/
3107During the update process, Subversion will show the status
3108of each file with significant activity. For example, the follow-
3109ing is the logging produced when updating the directory tree
3110containing the Subversion source code itself:
3111subversion > svn update
3112U include/svn repos.h
3113G libsvn client/status.c
3114A bindings/java/javahl/build
3115A bindings/java/javahl/build/build.xml
3116U bindings/swig/perl/native/Repos.pm
31171 Frequent merges serve another purpose. If another developer is going
3118down the wrong path, or if their changes are promising to be problematic in
3119the long term, you’ll find out sooner if you merge often. The earlier you get
3120this feedback, the less the pain involved in fixing the problem.
3121K EEPING U P - TO -D ATE 65
3122U bindings/swig/perl/native/Base.pm
3123A bindings/swig/perl/native/Makefile.PL.in
3124UU bindings/swig/perl/native/h2i.pl
3125U bindings/swig/perl/native/Ra.pm
3126D bindings/swig/perl/native/Makefile.PL
3127U bindings/swig/perl/native
3128U clients/cmdline/propedit-cmd.c
3129A po/pt BR.po
3130U po/zh TW.po
3131Updated to revision 11141.
3132Subversion prints the following characters to indicate what
3133has happened to each file or directory:
3134• A indicates Subversion has added a file to your working
3135copy in order to bring it up-to-date with a new file in the
3136repository.
3137• U shows a file that was out-of-date in your working copy
3138because a newer version was checked into the repository.
3139Subversion has updated your working copy of the file to
3140the new version.
3141• D indicates that Subversion has removed a file from your
3142working copy because the file has been deleted from the
3143repository.
3144• G shows a file that was out-of-date in your working copy,
3145which you had modified locally. Subversion successfully
3146merged the changes from the repository with your local
3147modifications.
3148• C shows a file that was out-of-date in your working copy,
3149which you had also modified locally. Subversion tried to
3150merge the changes from the repository with your local
3151modifications but encountered a conflict. You’ll need to
3152resolve the conflict before you can check in.
3153You might have noticed the line Subversion printed for h2i.pl
3154starts with UU and that the line for the bindings/swig/perl/native
3155directory has a space followed by a U . These aren’t typeset-
3156ting errors—Subversion is actually printing two columns of
3157information. The second column indicates changes to a file’s
3158properties, rather than to a file itself. Subversion properties
3159are discussed in more detail in Section 6.4, Properties, on the
3160following page.
3161A DDING F ILES AND D IRECTORIES 66
31626.3 Adding Files and Directories
3163The svn add command tells Subversion to add files and direc-
3164tories to the repository. When you add a directory, Subversion
3165automatically adds all the files within the directory and its
3166subdirectories, unless you specify the --non-recursive option:
3167sesame > mkdir timelib
3168sesame > cd timelib
3169timelib > # ..create and edit Time.java..#
3170timelib > cd ..
3171sesame > svn add timelib
3172A timelib
3173A timelib/Time.java
3174Note that at this point Subversion has just remembered the
3175names of the files you’d like to add to the repository; it hasn’t
3176actually added the files or made the change visible to anyone
3177else. You need to use svn commit to commit the new files into
3178the repository.
3179Subversion stores all files in the repository in a binary format,
3180using an efficient binary-delta algorithm to figure out what
3181has changed between revisions. This works great for text as
3182well as real binaries, so you don’t need to tell Subversion if a
3183file is binary when adding it to the repository.
3184Subversion treats text and binary files differently as we’ll see
3185in Section 6.4, Setting Mime Types, on page 73, which means
3186it’s sometimes worth checking that Subversion detected the
3187“binaryness†of a file correctly. When you add a file that Sub-
3188version thinks is binary, it’ll automatically set the svn:mime-
3189type property to application/octet-stream . The next sec-
3190tion covers properties in detail.
31916.4 Properties
3192Whilst we are mostly concerned with Subversion storing file
3193contents it can also store metadata associated with each file
3194(and directory) in the repository. 2 Subversion calls this meta-
3195data properties and manages changes to properties in the properties
3196same way as a file’s contents. Properties can be changed
31972 Subversion actually stores properties on revisions too. For example, the
3198log message associated with a particular commit is stored in a text property
3199on the revision.
3200P ROPERTIES 67
3201by different users and are updated in each working directory
3202when users run svn update . This can lead to merges and con-
3203flicts just like those encountered when changing file contents.
3204Properties are named using simple strings and can contain
3205any content that a normal file could contain—this specifically
3206includes binary content. Properties can be used to associate
3207extra data with a file, in whatever format you’d like. For exam-
3208ple, a Java source file could have an associated Reviewer prop-
3209erty that tells you who last performed a code review on that
3210file. A repository storing music files might have a short sam-
3211ple of each file stored in a binary property, rather than storing
3212the samples in files alongside the main file and using some
3213naming convention to link the two.
3214You can use Subversion’s properties however you like, but you
3215should be aware of a few special properties. These properties
3216change the way Subversion behaves when it encounters a file,
3217and all start with the svn: prefix.
3218Manipulating Properties
3219To set a property on a file, use the svn propset command:
3220sesame > svn propset checked-by "Mike Mason" Number.txt
3221property ' checked-by ' set on ' Number.txt '
3222sesame > svn status
3223M Number.txt
3224Here we’re setting the checked-by property on Number.txt to
3225value Mike Mason . Maybe our project’s release procedure
3226requires each of our files to have this property set so that
3227we can figure out who approved the contents. It’s important
3228to note that we’re making a change to the file’s properties,
3229which Subversion handles in the same way as a change to
3230the contents. Subversion records the file in our local copy as
3231modified, and we must commit the change to the repository if
3232we want anyone else to see it.
3233To edit a property, use svn propedit . This will bring up an editor
3234so that you can easily manage multiline text properties:
3235sesame > svn propedit checked-by Number.txt
3236# .. edit the property, then save and quit the editor ..
3237Set new value for property ' checked-by ' on ' Number.txt '
3238P ROPERTIES 68
3239The svn proplist and svn propget commands list all the properties
3240for a file and print out the current value of a property:
3241sesame > svn proplist Number.txt
3242Properties on ' Number.txt ' :
3243checked-by
3244sesame > svn propget checked-by Number.txt
3245Mike
3246Ian
3247Finally, you can use svn propdel to delete a property entirely.
3248Remember that the property is not lost forever—Subversion
3249tracks changes to properties just like changes to files, so you
3250can always go back in time and find any previous revision.
3251Keyword Expansion
3252If you’ve used another version control system, you may be
3253familiar with keyword expansion. This basically means get- keyword expansion
3254ting your version control system to modify your working copy
3255files as it checks them out and updates them so it can fill
3256in useful information for you. Each of these useful pieces of
3257information is represented by a keyword, usually surrounded keyword
3258by dollar signs, which you put strategically inside the files
3259you’re storing in version control. Keywords in Subversion
3260are stored unexpanded in the repository to make diffing and
3261merging a little easier.
3262We really recommend not using this Subversion feature, since
3263it can get you into lots of bother. We tried to make this page of
3264the book perforated so readers could tear it out and forget all
3265about keyword expansion, but our printers said it’d add too
3266much to the production costs....
3267To switch on keyword expansion, you need to set svn:keywords
3268on each file containing keywords. The property value should
3269list the keywords you’d like to expand for that particular file.
3270Subversion offers the following keywords:
3271$LastChangedDate$
3272Also abbreviated $Date$ , this keyword describes the last
3273time the file was committed to the repository. It expands
3274to a string such as 2004-09-26 18:11:03 -0700 (Sun, 26 Sep
32752004) .
3276$LastChangedRevision$
3277Also known as $Revision$ or $Rev$ , this keyword expands
3278P ROPERTIES 69
3279to the revision number the last time the file was commit-
3280ted to the repository.
3281$LastChangedBy$
3282Also abbreviated $Author$ , this keyword expands to the
3283name of the last user to have committed the file.
3284$HeadURL$
3285Also abbreviated $URL$ , this keyword expands to the full
3286URL of the file in the repository.
3287$Id$
3288This keyword expands to a short summary of the other
3289keywords, suitable for use in a file’s header section.
3290Let’s suppose we want to turn on keyword expansion for the
3291file Number.txt in our Sesame project. First we need to set
3292svn:keywords to the list of keywords we want to expand:
3293sesame > svn propset svn:keywords "HeadURL Id" Number.txt
3294property ' svn:keywords ' set on ' Number.txt '
3295Now edit Number.txt , and add two header lines with the key-
3296words we want expanded. Here we’re using $HeadURL$ and
3297$Id$ :
3298# $ HeadURL $
3299# $ Id $
3300ZERO
3301ichi
3302due
3303three
3304four
3305five
3306SIX
3307Now when we commit our changes, Subversion will notice that
3308we’ve asked for keyword expansion and modify the working
3309copy file. Each keyword is expanded to the latest information
3310Subversion has for the file:
3311sesame > svn commit -m "Added file keywords"
3312Sending Number.txt
3313Transmitting file data .
3314Committed revision 10.
3315sesame > cat Number.txt
3316# $ HeadURL: svn://olio/sesame/trunk/Number.txt $
3317# $ Id: Number.txt 10 2004-09-27 00:09:05Z mike $
3318ZERO
3319ichi
3320due
3321three
3322four
3323five
3324SIX
3325P ROPERTIES 70
3326Joe Asks...
3327Where’s the $Log$ keyword?
3328The keywords available in other version control sys-
3329tems, including CVS, often include a $ Log $ keyword.
3330This expands to list all of the log messages ever used
3331when committing changes to the file.
3332The practical problem is that all this extra stuff in the
3333source files gets in the way of reading the code.
3334We’ve seen source with two or three full pages of log
3335messages at the top of it, all before you get to a sin-
3336gle line of real code. Code is there to be read, and
3337anything that gets in the way of reading it is bad.
3338The philosophical problem is that you’re duplicating
3339information. Everything that can be inserted using
3340keywords is already stored within Subversion (it has to
3341be; otherwise Subversion couldn’t add it in the first
3342place). So why not just go to the horse’s mouth and
3343ask Subversion directly? That way you’ll get authorita-
3344tive information that’s guaranteed to be up-to-date.
3345The Subversion developers think the use of keywords,
3346especially anything that includes verbose possibly
3347long commit messages, should not be encouraged.
3348The result is they haven’t included a $Log$ keyword.
3349Keyword expansion really doesn’t have many bene-
3350fits, and it has several drawbacks. We recommend
3351not using it.
3352Whilst writing this book using the Pragmatic Program-
3353mers’ CVS-based system, Mike got caught out by the
3354expansion of $ Log $ and $ Id $ keywords and had to
3355switch it off for various chapters. The irony of using
3356CVS to write a Subversion book is not lost on him.
3357Editor’s note: Mike’s first edition of this book moved us
3358so deeply that we now do all book production using
3359Subversion.
3360P ROPERTIES 71
3361If you want to use keyword expansion on lots of files, say, all
3362your . java files, that’s a lot of property setting to remember
3363to do. Fortunately, Subversion has a feature called autoprops autoprops
3364that can set properties for you. Autoprops are explained in
3365detail in Section 6.4, Automatic Property Setting, on page 74.
3366Ignoring Certain Files
3367Most of the time your working copy will contain both files you
3368want under version control (source code, build scripts, graph-
3369ics for your application, and so on) and files that you’re happy
3370to have lying around but that don’t need to be stored in the
3371repository (temporary files, compiled code, and logfiles). Some
3372Subversion commands, notably svn status , svn add , and svn
3373import assume you’re interested in all the files in your working
3374copy. For example, svn status displays files that aren’t under
3375revision control in case you’ve forgotten to add them.
3376This extra output for files you really don’t want Subversion
3377to worry about can be annoying, or just plain dangerous (try
3378accidentally adding a few large temporary files to your repos-
3379itory, and see if your administrator comes running your way
3380with a big stick...). Fortunately, there’s an easy way to avoid
3381these problems: setting the svn:ignore property on a directory
3382specifies files you’d like Subversion to ignore.
3383Suppose we’ve been working on the time library in our Sesame
3384project. Ask Subversion for a status report, and we might see:
3385sesame > svn status timelib/
3386? timelib/Time.class
3387? timelib/Time.java.bak
3388M timelib/Time.java
3389Here we can see that we’ve changed Time.java but that Subver-
3390sion is also reporting on Time.class and Time.java.bak , neither of
3391which we actually care much about.
3392Use svn propedit svn:ignore timelib to bring up an editor for the
3393svn:ignore property on timelib . Enter the following contents:
3394*.class
3395*.bak
3396Now running svn status will ignore the . class and . bak files:
3397sesame > svn status
3398M timelib
3399M timelib/Time.java
3400P ROPERTIES 72
3401The timelib directory is listed as modified because we changed
3402its svn:ignore property.
3403Once your changes are committed, everyone will receive the
3404update to the svn:ignore property on timelib , causing Subver-
3405sion to ignore files in their working copies too. The svn:ignore
3406property applies only to the contents of a particular directory;
3407it doesn’t apply recursively to subdirectories.
3408Setting End-of-Line Style
3409Computer systems store text files using a combination of nor-
3410mal characters—the alphabet, numbers, and so on—and spe-
3411cial control characters.A combination of up to two of these control characters
3412are used to denote the end of a line of text. Depending on
3413the operating system, a computer will use a carriage-return
3414followed by a linefeed (CRLF, used by Windows computers),
3415simply a linefeed (LF, used by Unix and Mac OS X), or some-
3416times just a plain carriage-return (CR, used by older versions
3417of Mac OS).
3418If you’re storing files that should be usable on clients where
3419the line-ending style differs, you might be worried about how
3420line endings are stored. Subversion stores all files, whether
3421they’re text, graphics, compiled object code, or movies, using a
3422binary format in the repository. Unless you ask it to, Subver-
3423sion will never convert a file’s line-ending style, which might
3424mean you can ignore this section entirely.
3425If you do need to share files across different operating sys-
3426tems, you may already have noticed strange behavior. Open-
3427ing a Unix-formatted file using Windows’ Notepad, for exam-
3428ple, produces a file with lots of little squares in it instead of
3429newlines. Opening a Windows-formatted file in Unix might
3430result in lots of ˆM characters at the end of each line.
3431Whilst your editor or IDE might claim to be able to do conver-
3432sions for you, or to maintain the end-of-line style that exists
3433in a file when editing it, we often find the best thing is to stick
3434with native linefeed formats for each operating system. Sub-
3435version will do a conversion for you if you set the svn:eol-style
3436property to one of the values in the following table.
3437P ROPERTIES 73
3438native Subversion will translate end-of-line characters to
3439whatever the client operating system expects, and so
3440will use CRLF on Windows and LF on Unix.
3441CRLF Subversion will always use CRLF as an end-of-line
3442marker when it creates files in the working copy.
3443LF Subversion will always use LF as an end-of-line
3444marker on the client.
3445CR Subversion will always use CR as an end-of-line
3446marker on the client.
3447Setting Mime Types
3448Setting the svn:mime-type property on a file tells Subversion
3449exactly what type of content a file has. Mime types are used a
3450lot on the Internet—especially by e-mail and web servers—to
3451describe files that are being transferred around or sent as e-
3452mail attachments. For example, XML documents have a mime
3453type of text/xml, JPEG graphics are of type image/jpeg, and
3454Microsoft Word documents have an application/msword mime
3455type.
3456Setting svn:mime-type on a file is useful for a couple of reasons.
3457Firstly, Subversion assumes files that don’t have a text mime
3458type (starting text/) have binary contents, so it should treat
3459them differently on the client when merging and displaying
3460diffs. A diff on a binary file probably won’t be human readable,
3461so Subversion skips trying to show you a diff and just tells
3462you the file has changed. A merge on a binary file is equally
3463unlikely to work very well, so when you’re receiving changes
3464from the repository to a binary file you’ve changed in your
3465working directory, Subversion renames your version of the
3466file with a . orig file extension and replaces your file with new
3467data from the repository.
3468Secondly, when Subversion is being used with Apache as its
3469network server, you can browse the repository using a normal
3470web browser. When you click on a link, Subversion uses the
3471svn:mime-type property to figure out what the type of the file
3472P ROPERTIES 74
3473should be when Apache returns it to your web browser. This
3474helps avoid seeing a screenful of binary data when you click
3475on a zip file in the repository.
3476Executable Flags
3477Some operating systems, most notably Unix, treat simple data
3478files differently than program files. To be able to run a pro-
3479gram on Unix it must have its “execute bit†set. If you’re
3480checking executable files or scripts into your repository, users
3481checking the files out won’t automatically get the execute bit
3482set. Setting the svn:executable property on a file means that
3483Subversion will set the execute bit for you whenever that file is
3484checked out. It doesn’t matter what the property is set to—if
3485it’s set at all, Subversion will set the execute bit.
3486On Windows, all files are executable, so you probably won’t
3487have to worry about this.
3488Automatic Property Setting
3489Subversion properties are very useful, but unfortunately they
3490need to be applied to each file or directory we’re interested in.
3491It’s easy to forget to set a property, and that might lead to
3492problems later.
3493Fortunately, Subversion includes a feature called autoprops
3494that allows you to specify properties that should be added
3495automatically. For example, you might decide that . java files
3496should have svn:keywords set to LastChangedDate and have
3497svn:eol-style set to native. You might also decide that whenever
3498someone adds a . gpg file to the repository it should have its
3499svn:mime-type set to application/pgp-encrypted.
3500Autoprops are a client-side setting, so if you want all your
3501developers to use them you’ll need some kind of policy for
3502making sure everyone is set up correctly. Unfortunately, Sub-
3503version doesn’t (yet) have the ability to “broadcast†configura-
3504tion settings from the server to clients, so you’ll have to do
3505this by hand.
3506Subversion stores your settings in a user-specific application
3507data folder. Where this actually is depends on whether you’re
3508using Unix or Windows. Section 5.1, svn+ssh, on page 57
3509C OPYING AND M OVING F ILES AND D IRECTORIES 75
3510covers finding the folder on Windows, and on Unix Subversion
3511uses
3512˜ /.subversion .
3513Edit Subversion’s config file, and uncomment the following
3514line:
3515enable-auto-props = yes
3516Next scroll down a little, and uncomment the autoprops sec-
3517tion, adding whatever properties you’d like to set. To enable
3518a mime type on . gpg files and native end-of-line style on . java
3519files, you’d want a section like this:
3520[auto-props]
3521*.java = svn:eol-style=native
3522*.gpg = svn:mime-type=application/pgp-encrypted
35236.5 Copying and Moving Files and Directories
3524Subversion remembers every file and directory you ever com-
3525mit to the repository. This is great in most cases, but if
3526you make a mistake and add a file to the wrong directory,
3527or add it with the wrong name, you might want to move or
3528rename something. Modern programming includes a tech-
3529nique called refactoring, which often involves renaming a pro-
3530gram file when you come up with a better name for what that
3531file does or a more logical location for it in your project.
3532Fortunately, Subversion includes copy and move commands
3533allowing you to move and rename 3 files and directories. Sub-
3534version’s history tracking also knows about these operations,
3535so it’s much better to move a file using a Subversion command
3536than to move it yourself manually.
3537Copying a File
3538Whilst you could manually copy a file using Windows Explorer
3539or the Unix cp command, then add the new file to version
3540control, Subversion provides the svn copy command to allow
3541copying of files.
35423 A “rename†is just a “move†that happens to move a file to the same
3543directory. Unix gurus will probably be able to explain exactly why this makes
3544sense, but Subversion’s move and rename commands do the same thing.
3545C OPYING AND M OVING F ILES AND D IRECTORIES 76
3546Copying is the fundamental operation in Subversion upon
3547which everything else is based. Successive revisions of a file
3548are copies of the file with the contents changed. Branches are
3549copies of entire directories to a new location. Tags are copies
3550of a set of files that provide a snapshot of the repository at a
3551particular point in time.
3552Given that copying is such an epic activity, why would you
3553want to do it just to add another copy of a file to your reposi-
3554tory? Ultimately you might not, but when you copy a file using
3555svn copy , Subversion can track the history of both the original
3556and the copy back to the same source. In fact, Subversion
3557doesn’t even store a complete copy of the file; it just stores a
3558reference to where it was copied from. This might be useful if
3559you have a lot of big files that came from the same source and
3560have just been changed a little.
3561Enough evangelism. Using svn copy is a good idea, and it
3562works like this:
3563sesame > svn copy Number.txt Data.txt
3564A Data.txt
3565sesame > svn commit -m "Created example data file"
3566Adding Data.txt
3567Committed revision 24.
3568Copying a file or directory creates copies in your local working
3569directory and schedules them for addition to the repository. A
3570normal svn commit will check them in and complete the copy.
3571Since Subversion remembers the shared history of the files,
3572asking for the log for Data.txt also gives us the history for the
3573file Number.txt :
3574sesame > svn log Data.txt
3575----------------------------------------------------------
3576r24 | mike | 2004-11-17 16:00:37 -0700 (Wed, 17 Nov 2004)
3577Created example data file
3578----------------------------------------------------------
3579r11 | mike | 2004-10-04 21:05:37 -0600 (Mon, 04 Oct 2004)
3580Added Ian as reviewer
3581----------------------------------------------------------
3582r10 | mike | 2004-09-26 18:09:05 -0600 (Sun, 26 Sep 2004)
3583Added file keywords
3584----------------------------------------------------------
3585r7 | mike | 2004-09-08 23:22:06 -0600 (Wed, 08 Sep 2004)
3586One is Japanese, two Italian
3587----------------------------------------------------------
3588C OPYING AND M OVING F ILES AND D IRECTORIES 77
3589Renaming a File
3590Let’s suppose that our Sesame project’s Time.java has actually
3591become more of a “clock†class and that we’d like to rename
3592it. We could rename the file in our working copy using Win-
3593dows Explorer or the Unix mv command, then use svn delete
3594to delete Time.java and svn add to add Clock.java , but that won’t
3595allow Subversion to track the file history for us.
3596First let’s examine the history for Time.java :
3597timelib > svn log Time.java
3598----------------------------------------------------------
3599r14 | mike | 2004-10-04 21:12:48 -0600 (Mon, 04 Oct 2004)
3600Added freeze/unfreeze time methods
3601----------------------------------------------------------
3602r13 | mike | 2004-10-04 21:10:50 -0600 (Mon, 04 Oct 2004)
3603Added getCurrentDate() method
3604----------------------------------------------------------
3605Our most recent change to the file, adding methods for freez-
3606ing and unfreezing the system time, really means that our
3607class would be better named Clock . We know that things can
3608get out of hand if we don’t name our classes well, so we decide
3609to make the change sooner rather than later. Use the svn move
3610command to rename the file:
3611timelib > svn move Time.java Clock.java
3612A Clock.java
3613D Time.java
3614Here Subversion is letting us know that our “move†is really an
3615add and a delete. Someday Subversion may support renames
3616as first-class operations, but for the moment a Subversion
3617move is stored in the repository as a history-aware copy from
3618the old name to the new name and a delete of the old name.
3619Before you get all excited and commit the change, you should
3620crank up your unit tests and make sure you didn’t break
3621anything. At the very least, this Java file now won’t com-
3622pile because it contains a Time class in a file called Clock.java .
3623Open your favorite editor, and change the class name to Clock .
3624Then make sure your tests pass. You might need to change
3625code that references the class so it uses the new name too. 4
36264 Renaming a Java file requires quite a few steps, as does a rename in
3627other programming languages. Fortunately, some development environments
3628integrate directly with version control and will perform all the renames, adds,
3629and deletes for you automatically. Check your IDE for “refactoring support.â€
3630C OPYING AND M OVING F ILES AND D IRECTORIES 78
3631What’s in a Name?
3632Subversion’s move command can also be referred to
3633as svn mv , rename , and ren . The svn copy command
3634can be shortened to svn cp if you’re into the whole
3635brevity thing.
3636While we’re on the subject of naming, it’s worth point-
3637ing out that naming things (classes, variables, meth-
3638ods, tests, data files, machines, processes, etc.) is
3639both really difficult and really important. Most peo-
3640ple don’t name stuff completely right the first time
3641around, but a well-named object helps avoid misun-
3642derstanding and speeds communication. Once you
3643realize there’s a better name for something, make the
3644effort to rename it. Your colleagues will thank you!
3645Once everything is working, commit your changes:
3646timelib > svn commit -m "Renamed Time to Clock"
3647Adding timelib/Clock.java
3648Deleting timelib/Time.java
3649Transmitting file data .
3650Committed revision 15.
3651Now if we view the history for the new Clock.java , we’ll see the
3652hard work has paid off, as Subversion follows the history of
3653the file across the rename:
3654timelib > svn log -v Clock.java
3655----------------------------------------------------------
3656r15 | mike | 2004-10-04 21:13:40 -0600 (Mon, 04 Oct 2004)
3657Changed paths:
3658A /sesame/trunk/timelib/Clock.java
3659(from /sesame/trunk/timelib/Time.java:14)
3660D /sesame/trunk/timelib/Time.java
3661Renamed Time to Clock
3662----------------------------------------------------------
3663r14 | mike | 2004-10-04 21:12:48 -0600 (Mon, 04 Oct 2004)
3664Changed paths:
3665M /sesame/trunk/timelib/Time.java
3666Added freeze/unfreeze time methods
3667----------------------------------------------------------
3668r13 | mike | 2004-10-04 21:10:50 -0600 (Mon, 04 Oct 2004)
3669Changed paths:
3670M /sesame/trunk/timelib/Time.java
3671Added getCurrentDate() method
3672----------------------------------------------------------
3673C OPYING AND M OVING F ILES AND D IRECTORIES 79
3674Renaming a Directory
3675With Subversion, directories are first-class objects just like
3676files. We can happily move or rename a directory using the
3677svn move command. Maybe the time library has had a few
3678extra utilities added to it and should be renamed util .
3679timelib > cd ..
3680sesame > svn move timelib util
3681A util
3682D timelib/Clock.java
3683D timelib
3684sesame > svn commit -m "Renamed timelib to util"
3685Deleting timelib
3686Adding util
3687Adding util/Clock.java
3688Committed revision 16.
3689Using Repository URLs
3690The svn move command we’ve seen so far has been running on
3691the working copy—moves, renames, adds, and deletes hap-
3692pen on the client before being committed to the server. This is
3693appropriate in most cases, because program code often needs
3694to be edited after being moved so that the code will still com-
3695pile and the tests will still pass.
3696Subversion also allows you to run these commands using a
3697repository URL, without the need for a working copy at all.
3698The changes are made instantly in the repository and require
3699a commit message. It might be appropriate to use this kind
3700of renaming if you have a lot of big files and don’t want to
3701move them around using a working copy. If you’re moving
3702code, however, think twice—you won’t be able to run your
3703tests without a working copy and might well break stuff.
3704To perform a repository-based rename, use two URLs like the
3705one initially used for a checkout. Let’s rename the util directory
3706common instead:
3707work > svn move -m "Renamed util to common" \
3708svn://olio/sesame/trunk/util \
3709svn://olio/sesame/trunk/common
3710Committed revision 17.
3711Back in the Sesame working copy, performing an update will
3712get the new common directory and delete the old util directory:
3713sesame > svn update
3714A common
3715A common/Clock.java
3716D util
3717Updated to revision 17.
3718S EEING W HAT H AS C HANGED 80
37196.6 Seeing What Has Changed
3720The svn diff command shows you the differences between ver-
3721sions of files. You can compare the version of a file in the
3722repository with your locally modified copy, and you can see
3723the differences between two versions of a file in the reposi-
3724tory.
3725Seeing What You’ve Changed in Your Working Copy
3726The simplest use of svn diff is to show you what you’ve changed
3727since you last updated your working copy from the repository:
3728common > svn diff Clock.java
3729Index: Clock.java
3730==========================================================
3731--- Clock.java (revision 21)
3732+++ Clock.java (working copy)
3733@@ -20,6 +20,11 @@
3734frozen = true;
3735}
3736+ public static void setTime(long time)
3737+ {
3738+ frozenTime = time;
3739+ }
3740+
3741public static void unfreezeTime()
3742{
3743frozen = false;
3744Here we can see that we last updated to revision 21 of the file
3745Clock.java and that since then we added the setTime () method.
3746The basic svn diff command shows the changes between the file
3747in your workspace and the version to which you last updated.
3748Subversion can do this without contacting the server because
3749it stores a pristine, local copy of each file in your working
3750directory. If someone else has changed the file and committed
3751their changes into the repository, however, you won’t see them
3752in the diff. We’ll see how to handle this shortly.
3753Using Subversion Revision Identifiers
3754We looked at Subversion’s -r option when checking out and
3755updating, and it turns out referring to revisions is something
3756we’ll be doing a lot with Subversion. The option you supply
3757after -r is called a revision identifier. When you’re using a revision identifier
3758revision identifier, Subversion will accept revision numbers,
3759dates, and a few symbolic names, shown in the following
3760table.
3761S EEING W HAT H AS C HANGED 81
3762number A revision number within the repository, for
3763example 87 .
3764{ date } A revision at the start of the date, for exam-
3765ple { "2004-09-26 13:35:06" }. The curly
3766braces tell Subversion you’re using a date,
3767and the quotes are required if you’re using
3768a date format containing spaces. Subversion
3769supports a variety of date formats, including
3770the basic HH:mm denoting a particular time
3771on today’s date.
3772HEAD The latest revision stored in the repository.
3773BASE The base revision of an item’s working copy—
3774this is the revision you last checked out or
3775updated to.
3776COMMITTED The last revision in which an item changed at
3777or before BASE.
3778PREV The revision just before COMMITTED.
3779Some commands accept a revision range, which is simply two revision range
3780revision identifiers separated by a colon. Revision ranges are
3781used to refer to two revisions separated over time.
3782The symbolic revisions BASE, COMMITTED, and PREV can be
3783used only to refer to an item in a working copy, because they
3784don’t make sense otherwise.
3785Figure 6.1 on the following page shows Subversion’s symbolic
3786revisions. In this scenario, you have revision 2 of Graph.java
3787in your working copy, and another developer checks in some
3788changes, creating revision 3 in the repository. Since you
3789haven’t updated your working copy, the BASE revision for
3790your copy of Graph.java is revision 2. The PREV revision is
3791one earlier than this, namely revision 1. HEAD is always the
3792newest version in the repository, in this case revision 3.
3793S EEING W HAT H AS C HANGED 82
3794K
3795L
3796MN
3797O
3798P
3799QR S
3800T
3801U
3802Q V Q
3803W
3804X
3805W
3806Y
3807W
3808Z
3809W
3810Y [ \
3811W
3812]
3813^
3814_ `a
3815\b c
3816d efg
3817h f ie
3818jkel
3819mn o p
3820q
3821r
3822q
3823s
3824t
3825u
3826Figure 6.1: Symbolic Revisions for a Working Copy File
3827Finding Differences between Versions
3828To compare two revisions of a particular file, use the -r option
3829to specify a revision range:
3830common > svn diff -r19:21 Clock.java
3831Index: Clock.java
3832==========================================================
3833--- Clock.java (revision 19)
3834+++ Clock.java (revision 21)
3835@@ -1,9 +1,11 @@
3836package timelib;
3837+import java.util.Date;
3838+
3839public class Clock
3840{
3841- private boolean frozen = false;
3842- private long frozenTime = 0;
3843+ private static boolean frozen = false;
3844+ private static long frozenTime = 0;
3845public static Date getCurrentDate()
3846{
3847Here we used a file in the working copy to produce the diff,
3848even though a working copy doesn’t contain any historical
3849information. Under the hood, Subversion translates the file
3850path into a repository URL so it can retrieve the earlier ver-
3851sions as needed.
3852If you don’t have a working copy, you can diff directly against
3853the repository:
3854S EEING W HAT H AS C HANGED 83
3855common > svn diff -r19:21 \
3856svn://olio/sesame/trunk/common/Clock.java
3857Index: Clock.java
3858==========================================================
3859--- Clock.java (revision 19)
3860+++ Clock.java (revision 21)
3861@@ -1,9 +1,11 @@
3862package timelib;
3863+import java.util.Date;
3864+
3865public class Clock
3866{
3867- private boolean frozen = false;
3868- private long frozenTime = 0;
3869+ private static boolean frozen = false;
3870+ private static long frozenTime = 0;
3871public static Date getCurrentDate()
3872{
3873Earlier we noted that a common gotcha with svn diff is that it
3874doesn’t show changes that have happened in the repository.
3875To get Subversion to compare your working copy against the
3876latest revision in the repository, use the HEAD keyword:
3877common > svn diff -r HEAD Clock.java
3878Index: Clock.java
3879==========================================================
3880--- Clock.java (revision 26)
3881+++ Clock.java (working copy)
3882@@ -1,6 +1,7 @@
3883package timelib;
3884import java.util.Date;
3885+import java.util.Calendar;
3886public class Clock
3887{
3888@@ -24,6 +25,11 @@
3889frozenTime = System.currentTimeMillis();
3890}
3891+ public static void switchToGMT()
3892+ {
3893+ frozenTime -= Calendar.getInstance()
3894+ .get(Calendar.ZONE OFFSET);
3895+ }
3896+
3897public static void setTime(long time)
3898{
3899frozenTime = time;
3900@@ -38,10 +44,5 @@
3901{
3902frozen = false;
3903}
3904-
3905- public static boolean isFrozen()
3906- {
3907- return frozen;
3908- }
3909}
3910S EEING W HAT H AS C HANGED 84
3911In our working copy of Clock we’ve added the switchToGMT ()
3912method. Meanwhile, another developer added the isFrozen ()
3913method and checked in. When we ask for a diff against HEAD,
3914we can see our local changes as additions and the other devel-
3915oper’s changes as deletions—if we check in Clock.java exactly
3916as it is in our working copy, we’ll undo the change adding
3917isFrozen ().
3918Fortunately, Subversion won’t let us do this—we’ll need to
3919update before checking in, which will add the isFrozen () method
3920to our working copy.
3921Sometimes it’s useful to see the most recent change to a file
3922before you start working on it. You can do this by using the
3923PREV symbolic revision:
3924common > svn diff -r PREV:BASE Clock.java
3925Index: Clock.java
3926==========================================================
3927--- Clock.java (revision 22)
3928+++ Clock.java (working copy)
3929@@ -26,6 +26,11 @@
3930frozenTime = time;
3931}
3932+ public static void setTime(Date date)
3933+ {
3934+ frozenTime = date.getTime();
3935+ }
3936+
3937public static void unfreezeTime()
3938{
3939frozen = false;
3940Here Subversion is showing us that the previous change to
3941Clock.java was the addition of the setTime () method.
3942Subversion’s diff command can also examine changes between
3943different development branches or show you what changed
3944since a certain version of the code was tagged. Chapter 9,
3945Using Tags and Branches, on page 111 covers diffing and
3946merging across tags and branches.
3947Diffs and Patch
3948If you’ve spent any time in the open-source community, you’ll
3949have come across folks flinging source patches around the
3950world. These patches are based on the same diffs that Sub-
3951version generates, which turns out to be remarkably useful.
3952S EEING W HAT H AS C HANGED 85
3953Perhaps you’re working with an open-source library, and you
3954need to make a change. The library is on CodeHaus, 5 which
3955among other things provides free Subversion repositories for
3956open-source developers. As a member of the public, Code-
3957Haus lets you check the source code of the project out of the
3958repository, but because you aren’t on the list of developers,
3959you can’t check changes back in.
3960This is where patches come in. Simply ask Subversion to give
3961you a list of all the changes you’ve made (using svn diff ). E-
3962mail the file containing the diff output to the library’s main-
3963tainer, who will be able to use the patch program to apply
3964those patches to their source.
3965The following command creates a file called mychanges.patch
3966containing all the changes that have been made to files in or
3967below the directory oslibrary :
3968oslibrary > svn diff > mychanges.patch
3969You can then e-mail this file to the maintainer, who can apply
3970the patch to his or her version of the source using (surprise!)
3971the patch command:
3972oslibrary > patch -p0 -i mychanges.patch
3973Correct use of patch is a mystic art that probably cannot be
3974taught in a book this size, but here’s a rough breakdown of
3975what’s going on:
3976• The patch is being applied in oslibrary , the same directory
3977in which it was created.
3978• The -p0 option is instructing patch to strip zero direct-
3979ories from files named in the patch before applying it. If
3980you don’t include this option, patch will complain about
3981being unable to find the right files.
3982• The -i option is telling patch to use mychanges.patch as
3983input.
3984patch is pretty clever and can usually ignore “garbage†text
3985surrounding a patch, so you can save an e-mail containing
3986someone’s changes and apply the whole thing. What most
39875 http://codehaus.org/
3988H ANDLING M ERGE C ONFLICTS 86
3989people forget is the magic -p0 that lets patch find the right
3990files.
3991Patches are useful outside the context of open source. You
3992can use patches to send suggested changes to other members
3993of your project team. If your clients have your source code,
3994you can even use patches to distribute those urgent three-
3995in-the-morning fixes that seem to crop up from time to time.
3996Just remember to check in the changes you’ve made into the
3997repository as well.
39986.7 Handling Merge Conflicts
3999Subversion doesn’t lock files: 6 everyone in a project can edit
4000any file at any time. This feature of Subversion seems to give
4001some people sleepless nights. “What stops two people editing
4002the same file at the same time?†they ask. “Won’t work get
4003lost?â€
4004The simple answers are “nothing, and no.†If they edit differ-
4005ent parts of that same file, Subversion will happily merge the
4006two changes together, and life carries on.
4007Sometimes, however, two people edit the same parts of the
4008same file (although it happens far more rarely than you might
4009first think). When that happens, Subversion cannot automat-
4010ically perform a merge: it wouldn’t know whose changes to
4011keep. In these cases, Subversion declares that the two ver-
4012sions of a file conflict and passes the matter back to a human
4013(you) to solve.
4014To illustrate a conflict, we’ll use our old friend Numbers.txt
4015again. This time, we’ll check it out into two separate work-
4016ing directories: 7
40176 At least, Subversion doesn’t lock files by default. Subversion 1.2 sup-
4018ports optional locking, sometimes known as reserved checkouts, which we
4019discuss in Chapter 7, File Locking and Binary Files, on page 99.
40207 Eagle-eyed readers will notice these examples take us back to revision 1
4021of the repository, when we had only two files and no timelib directory. This was
4022possible through some Subversion administration magic—we made a backup
4023of our repository including just revision 1 and loaded the backup into a new
4024repository. Section A.6, Backing Up Your Repository, on page 170 covers this
4025magic in detail.
4026H ANDLING M ERGE C ONFLICTS 87
4027work > svn checkout svn://olio/sesame/trunk sesame1
4028A sesame1/Number.txt
4029A sesame1/Day.txt
4030Checked out revision 1.
4031work > svn checkout svn://olio/sesame/trunk sesame2
4032A sesame2/Number.txt
4033A sesame2/Day.txt
4034Checked out revision 1.
4035In the sesame1 directory, we’ll change the first line of Num-
4036bers.txt so that it contains the following:
4037ZERO
4038one
4039two
4040We’ll check this change in:
4041sesame1 > svn commit -m "Made zero uppercase"
4042Sending Number.txt
4043Transmitting file data .
4044Committed revision 2.
4045Now we’ll bop over to sesame2 . Remember that we want to
4046create a merge conflict, so we’ll pretend that we don’t know
4047that someone changed the file we’re about to work on. In
4048sesame2 we’ll alter Numbers.txt , changing the first line to read
4049Zero :
4050sesame2 > svn commit -m "Capitalized ' Zero ' "
4051Sending Number.txt
4052Transmitting file data .svn: Commit failed (details follow):
4053svn: Out of date: ' /sesame/trunk/Number.txt ' in transaction ' 9 '
4054So far, so good. Subversion has detected that Number.txt is
4055out-of-date, so we do an svn update :
4056sesame2 > svn update
4057C Number.txt
4058Updated to revision 2.
4059Subversion marks the file with a C to let us know there’s a
4060conflict in the merge, and it’s our job to fix it.
4061Fixing a Conflict
4062The first question to be answered when fixing a merge conflict
4063is, “why did this happen in the first place?†This isn’t an issue
4064of blame, but it often is one of communication. What are two
4065developers doing editing the same lines of code in the same
4066file at the same time?
4067Sometimes there’s a good reason. Perhaps they both discover
4068the same bug at the same time, and both decide to fix it. Or
4069H ANDLING M ERGE C ONFLICTS 88
4070perhaps they’re both adding functionality which uses a com-
4071mon data structure, and both add fields to that structure at
4072the same time. These are reasonable changes, and they might
4073lead to a conflict.
4074But often conflicts happen because folks aren’t doing a good
4075job of letting others know what’s going on. So, we strongly
4076recommend that if you come across a merge conflict without a
4077sensible explanation you make a point of mentioning it at the
4078next team meeting. The goal here is to discuss the cause and
4079to come up with ways of improving communication so that
4080the chances of something similar happening in the future are
4081reduced.
4082Now that’s all fine, but you’re still left with a conflict. Subver-
4083sion marks these in the local copy of the file using sequences
4084of <<< and >>> characters:
4085<<<<<<< .mine
4086Zero
4087=======
4088ZERO
4089>>>>>>> .r2
4090one
4091two
4092Number.txt
4093Here we can see our change, Zero , helpfully labeled mine ,
4094and the change from the repository, ZERO , with the hint that
4095it came from revision 2.
4096We now have to decide how to fix this. In the real world, this
4097involves a negotiation with the other person who made the
4098change; simply blowing their hard work away and replacing it
4099with yours is a great way to jeopardize your invitation to the
4100next project picnic.
4101The resolution could go a number of ways:
4102• You decide to scrap your changes and use the version
4103in the repository. All you have to do is svn revert your
4104changes—Subversion will back out your change and use
4105the version of the file from the repository:
4106sesame2 > svn revert Number.txt
4107Reverted ' Number.txt '
4108sesame2 > svn update Number.txt
4109At revision 2.
4110• You decide to keep your changes and lose those in the
4111repository. Subversion saves a copy of each version of
4112H ANDLING M ERGE C ONFLICTS 89
4113Conflicts and Curly Brace Wars
4114Suppose two developers like to lay their code out dif-
4115ferently. Fred likes his code indented with two spaces
4116and likes all his curly braces to sit on the same line as
4117a declaration. His code would look like this:
4118for (i = 0; i < max; i++) {
4119if (values[i] < 0) {
4120process(values[i]);
4121}
4122}
4123Wilma, however, likes her code indented with four
4124spaces and doesn’t appreciated the cluttered look
4125of Fred’s code. She puts her curly braces on a dif-
4126ferent line to declarations. If Wilma were writing the
4127same piece of code, it would look like this:
4128for (i = 0; i < max; i++)
4129{
4130if (values[i] < 0)
4131{
4132process(values[i]);
4133}
4134}
4135One day Fred is editing some of Wilma’s code and
4136decides he dislikes the indentation. He tells his editor
4137to reindent the whole file to two-character offsets and
4138to put the curly braces where he likes them. He then
4139makes a small change to one line, saves the file, and
4140commits the changes to the repository.
4141The problem is that as far as Subversion is concerned,
4142every line in the file has changed. If Wilma (or any-
4143one else) changes something, they’ll get a merge
4144conflict, because Fred’s change to the indentation
4145means that the corresponding line in the repository is
4146different from the line in Wilma’s workspace.
4147Now you can get around this: you can tell Sub-
4148version to use an external diff program that ignores
4149changes in whitespace when determining the dif-
4150ference between files, for example. However, this
4151doesn’t get around the fact that you have changed
4152the whole file and that folks with local changes to that
4153file will get conflicts the next time they update.
4154H ANDLING M ERGE C ONFLICTS 90
4155Conflicts and Curly Brace Wars (continued)
4156The rule is simple: don’t wantonly change the layout
4157of a shared file. If you absolutely must change the
4158indentation, first make sure no one else on the team
4159has made local changes to the file. Then change the
4160layout and check in the changed file, without chang-
4161ing anything else. Then tell folks to update, so they’ll
4162all be working on the new version. This’ll cut down on
4163the number of conflicts people experience, and will
4164reduce the amount of hate mail you receive.
4165the file when a conflict arises, with extensions . mine , . r1 ,
4166. r2 , etc. Copy your version of the file, the one with the
4167. mine extension, over the original, and tell Subversion
4168you’ve fixed the conflict:
4169sesame2 > cp Number.txt.mine Number.txt
4170sesame2 > svn resolved Number.txt
4171Resolved conflicted state of ' Number.txt '
4172Subversion will clean up all the various . mine and . r2 files
4173when you tell it you’ve resolved the conflict.
4174• If you decide you want to use parts of both versions, then
4175you’ll need to do some manual editing. Simply edit the
4176file that contains the conflict markers, making it look the
4177way you want. Be sure to remove the conflict markers.
4178For example, in our case we might decide that the first
4179line shouldn’t be Zero or ZERO but Empty :
4180<<<<<<< .mine Empty
4181Zero one
4182======= becomes = > two
4183ZERO
4184>>>>>>> .r2
4185one
4186two
4187Subversion won’t let you commit a file that is still in a con-
4188flicted state. 8 In order to let Subversion know you’ve fixed a
41898 This is probably reassuring for folks who have big projects and lots of
4190files—“What if I don’t see a C next to a file as it scrolls past my screen?†is
4191a common question. If you miss the conflict, and by some chance having
4192a bunch of <<< characters in your code doesn’t horribly break your build,
4193C OMMITTING C HANGES 91
4194conflict, use the svn resolved command:
4195sesame2 > svn resolved Number.txt
4196Resolved conflicted state of ' Number.txt '
41976.8 Committing Changes
4198After you make a set of changes (and, in an ideal world, after
4199you’ve tested they don’t break anything), you’ll want to store
4200them in the repository. We’ve already done this many times in
4201this book; you simply use svn commit .
4202However, we’d like to recommend a slightly more complex
4203sequence of commands to follow at every commit:
4204myproject > svn update
4205myproject > #... resolve conflicts ...
4206myproject > #... run tests ...
4207myproject > svn commit -m "check in message"
4208The first line brings our local workspace into step with the
4209current state of the repository. This is important; although
4210our code may work fine with the project files as they were
4211when we last updated our workspace, other folks may have
4212changed things that break our new code. After updating, we
4213might have to resolve conflicts.
4214Even if there are no conflicts, we should compile and test our
4215code again, fixing any problems that arise. This ensures that
4216when we do check in we’ll be checking in something that actu-
4217ally works in the larger project context. You’ll need a fast test
4218suite for this to work—developers won’t want to hang around
4219more than a few minutes while their tests run.
4220Once we’ve checked that everything is correct, we can commit
4221our changes, using the -m option to add a meaningful mes-
4222sage. If you omit the -m option, Subversion will bring up an
4223editor and let you type in a longer comment.
42246.9 Examining Change History
4225You can look at the log messages that you and your team have
4226entered using the svn log command:
4227Subversion will complain about any files remaining unresolved when you try
4228to commit.
4229E XAMINING C HANGE H ISTORY 92
4230Meaningful Log Messages
4231What makes a good log message? To answer this
4232question, imagine you are another developer com-
4233ing to this code base a couple of years from now. You
4234are puzzling over a particular piece of the system, try-
4235ing to work out why something is done a certain way.
4236You notice that changes were made in this area, and
4237hope that the log messages will give you hints as to
4238the motivation for the particular design chosen.
4239Now, back to the present. What little breadcrumbs
4240can you drop into the log messages today to help
4241your fellow developers a couple of years from now?
4242Part of the answer comes from realizing that Subver-
4243sion already stores the actual details of the changes
4244you made to the code. There’s no point in writing
4245a log message that says “changed timeout to 42.â€
4246when a simple diff could show that setTimeout(10)
4247became setTimeout(42) . Instead, use the log mes-
4248sage to answer the question “why?â€:
4249If the round-robin DNS returns a machine that
4250is unavailable, the connect() method attempts
4251to retry for 30mS. In these circumstances our
4252timeout was too low.
4253If a change is being made in response to a bug
4254report, include the tracking number in the log mes-
4255sage: the description of the problem is already in
4256the bug database and doesn’t need to be repeated
4257here.
4258E XAMINING C HANGE H ISTORY 93
4259sesame > svn log Number.txt
4260---------------------------------------------------------
4261r4 | mike | 2004-09-08 22:45:16 -0600 (Wed, 08 Sep 2004)
4262Make ' six ' important
4263---------------------------------------------------------
4264r3 | mike | 2004-09-08 22:05:32 -0600 (Wed, 08 Sep 2004)
4265Customer wants more numbers
4266---------------------------------------------------------
4267r1 | mike | 2004-09-08 21:50:13 -0600 (Wed, 08 Sep 2004)
4268---------------------------------------------------------
4269If you’d just like to get a general idea of what has changed
4270recently, you can ask Subversion for a log of everything that
4271happened in a particular directory. Doing this at the top of a
4272large tree might produce quite a bit of output, so use a pipe 9
4273through the more command to paginate Subversion’s output:
4274work > svn log sesame | more
4275Subversion will accept a -r option to specify which revisions
4276you’re interested in. Using a single revision number will show
4277just what changed in that revision, and using a revision range
4278will show a section of history:
4279sesame > svn log -r 19:24 Clock.java
4280----------------------------------------------------------
4281r19 | mike | 2004-10-04 21:47:09 -0600 (Mon, 04 Oct 2004)
4282Renamed util to common
4283----------------------------------------------------------
4284r21 | mike | 2004-10-09 16:33:00 -0600 (Sat, 09 Oct 2004)
4285Fixed compilation problems
4286----------------------------------------------------------
4287r22 | dave | 2004-10-09 16:48:23 -0600 (Sat, 09 Oct 2004)
4288Added setTime() method
4289----------------------------------------------------------
4290r23 | ian | 2004-10-09 17:00:23 -0600 (Sat, 09 Oct 2004)
4291Added setTime() method taking a Date
4292----------------------------------------------------------
4293r24 | dave | 2004-10-10 18:07:08 -0600 (Sun, 10 Oct 2004)
4294Added Log class
4295----------------------------------------------------------
4296Here we asked to see revisions 19 through 24 of Clock.java . We
4297didn’t actually change Clock.java in revision 20 of the reposi-
4298tory, which is why we’re missing a revision here. Also notice
4299how Subversion printed the revisions with the newest at the
4300bottom—retrieving a log without using the -r option prints
4301the newest revision at the top.
4302The final message says “Added Log class†but is being shown
4303as part of the history for Clock.java . This looks a bit strange,
43049 The pipe character is Shift+\ on a U.S. keyboard.
4305E XAMINING C HANGE H ISTORY 94
4306so let’s get more information using the -v (verbose) option:
4307common > svn log -r 24 -v Clock.java
4308----------------------------------------------------------
4309r24 | dave | 2004-10-10 18:07:08 -0600 (Sun, 10 Oct 2004)
4310Changed paths:
4311M /sesame/trunk/common/Clock.java
4312A /sesame/trunk/common/Log.java
4313Added Log class
4314----------------------------------------------------------
4315Now that Subversion is being more talkative, we can see that
4316revision 24 added Log.java and also made a change to the
4317file Clock.java . In this case, the new Log class depends on
4318some extra functionality in Clock . When Dave committed his
4319change, he committed both the files at once, since they make
4320logical sense together.
4321Subversion’s ability to track changes to multiple files in a sin-
4322gle commit is extremely powerful. If you’re browsing history
4323for a particular file and see a change you’re interested in,
4324adding the -v option to svn log will show all the files that were
4325changed in that particular commit. This comes in handy when
4326tracking down what needed to be changed for a particular bug
4327fix, for example.
4328Line-by-Line History
4329The svn blame 10 command displays the contents of one or
4330more files. For each line in each file it shows the latest revi-
4331sion number to change that line, along with the author of the
4332change:
4333sesame > svn blame Number.txt
433410 mike # $ HeadURL $
433510 mike # $ Id $
43365 dave ZERO
43377 mike ichi
43387 mike due
43391 mike three
43401 mike four
43413 andy five
43424 ian SIX
4343This is a great tool when you’re involved in software archeol-
4344ogy; you can quickly find the patterns to changes and identify
4345exactly which lines were changed by a particular revision.
434610 It’s called blame because it’s often used to determine who is responsible
4347for a particular piece of code (or a particular bug!). svn blame , praise , annotate
4348and ann all mean the same thing.
4349R EMOVING A C HANGE 95
4350svn blame accepts a -r option specifying a revision or revision
4351range to use when displaying the file. This stops Subversion
4352from examining the entire history of the file when displaying
4353annotations.
43546.10 Removing a Change
4355Sometimes we make changes to code that we’d rather forget.
4356If the change is a set of changes in our local workspace that
4357have yet to be checked in, then we can simply throw the
4358changes away using svn revert .
4359CVS Hint: CVS users will be used to simply deleting a file with local
4360modifications and then doing an update to restore the file. Whilst
4361this will work with Subversion too, doing an actual revert is safer and
4362faster—an update will contact the server and possibly pull down new
4363changes that you’re not ready to receive, whilst a revert will not need
4364to contact the server and will not retrieve new changes from the
4365repository.
4366If the change is already committed, Subversion can help us
4367remove it. There are a number of ways of doing this; here
4368we’ll show a sequence of steps that we consider to be the sim-
4369plest and least error prone. For this example, let’s assume
4370we’re working on a contact management system. We’ve been
4371making preliminary releases to beta sites, and things have
4372been going well until a client phones up in a panic; when they
4373removed a client contact from their address list, it removed all
4374the client’s information from the database too.
4375The first step is to make sure we’re up-to-date.
4376contacts > svn update
4377U Contacts.java
4378Updated to revision 28.
4379Then we identify the exact revision we want to remove. svn
4380log is useful for this. Let’s have a look at the log for the main
4381contact manager class:
4382contacts > svn log Contacts.java
4383----------------------------------------------------------
4384r28 | mike | 2004-10-11 10:54:08 -0600 (Mon, 11 Oct 2004)
4385Reformat PMB Addresses
4386----------------------------------------------------------
4387r27 | fred | 2004-10-11 10:52:47 -0600 (Mon, 11 Oct 2004)
4388Remove from database too
4389----------------------------------------------------------
4390r26 | ian | 2004-10-11 10:51:38 -0600 (Mon, 11 Oct 2004)
4391R EMOVING A C HANGE 96
4392Sort clients into alpha order (Bug 2942)
4393----------------------------------------------------------
4394Revision 27 looks suspicious, so we use svn diff to see exactly
4395what changed between revisions 26 and 27:
4396contacts > svn diff -r 26:27 Contacts.java
4397Index: Contacts.java
4398==========================================================
4399--- Contacts.java (revision 26)
4400+++ Contacts.java (revision 27)
4401@@ -25,6 +25,7 @@
4402public void removeClient(Client client)
4403{
4404+ database.deleteAll(client);
4405clientList.remove(client);
4406}
4407}
4408This looks like the problem. However, before we start wan-
4409tonly hacking someone else’s change, let’s do some investi-
4410gating. Looking at the log, we see that this particular change
4411was made by Fred, so we wander over and chat. It turns out
4412that this was a simple misunderstanding; Fred hadn’t real-
4413ized that the call would delete all the client records. It’s okay
4414to remove the change. 11
4415We now have to remove the changes to Contacts.java that were
4416made in revision 27. We use the svn merge command to back
4417out the change:
4418contacts > svn merge -r 27:26 Contacts.java
4419U Contacts.java
4420We’re asking Subversion to calculate the changes between
4421revisions 27 and 26 for Contacts.java and apply those changes
4422to our working copy. We used revision range 27:26 because
4423we’d like to reverse the change. We can use svn diff to verify
4424that Subversion has correctly undone the change:
4425contacts > svn diff Contacts.java
4426Index: Contacts.java
4427==========================================================
4428--- Contacts.java (revision 28)
4429+++ Contacts.java (working copy)
4430@@ -26,7 +26,6 @@
4431public void removeClient(Client client)
4432{
4433- database.deleteAll(client);
4434clientList.remove(client);
4435}
443611 It would also be prudent to do a quick search of the rest of the code to
4437see if Fred has used the deleteAll () call in other places.
4438R EMOVING A C HANGE 97
4439At this point, we’re back into a normal flow. We’ve made a
4440change to the source, so we should test it then commit the
4441change to the repository:
4442contacts > svn commit -m "Revert deleteAll change from r27"
4443Sending contacts/Contacts.java
4444Transmitting file data .
4445Committed revision 29.
4446Reverting Bigger Changes
4447The recipe we just showed was for reverting changes to a sin-
4448gle file. How can we handle changes that involve many files?
4449Fortunately, Subversion tracks all the files we changed in
4450each commit; as long as changes are grouped together in log-
4451ical chunks, they’re easy to undo. If r27 had actually been
4452a change to a bunch of different files in the contacts direc-
4453tory, we can undo all those changes by using “ . †(the current
4454directory) as the target:
4455contacts > svn merge -r 27:26 .
4456U Contacts.java
4457U Database.java
4458It’s very important to commit related changes together in a
4459single revision. If a single logical change, such as “add date of
4460birth field,†is spread over several commits, it becomes more
4461difficult to revert the change and also more difficult to track
4462which files the change touched. When browsing history, you
4463can use the -v (verbose) option to list all the files that changed
4464in a particular revision.
4465The svn merge command also allows you to specify repository
4466URLs when merging. We’ll be using this in Chapter 9, Using
4467Tags and Branches, on page 111 for merging changes between
4468branches.
4469Checking Your Workspace
4470You work in your local working copy, editing files and adding
4471new files (and occasionally deleting files too). At the same
4472time, other folks on your team are doing the same thing,
4473checking their changes into the repository. As a result, it’s
4474easy to lose track of the state of your working copy. In partic-
4475ular, a common problem is forgetting to add new files in your
4476working copy to the repository.
4477R EMOVING A C HANGE 98
4478The svn status command can get information about the files in
4479your working directory:
4480proj > svn status
4481? common/Calendar.java
4482M contacts/Contacts.java
4483Here Subversion is telling us that Calendar.java is in our work-
4484ing directory but that it has not been added to version control.
4485We can also see that we’ve modified Contacts.java .
4486By default Subversion just displays information about your
4487working copy and doesn’t need to hit the network to do so. If
4488someone else has changed a file in the repository and we’re
4489out-of-date we won’t know about it. However, Subversion will
4490talk to the server and display extra information if you specify
4491the --show-updates option (you can use -u if you’re trying to
4492avoid RSI):
4493proj > svn status --show-updates
4494? common/Calendar.java
4495* 26 common/Log.java
4496M * 27 contacts/Contacts.java
4497Status against revision: 30
4498Now we know that both Log.java and Contacts.java are out-
4499of-date in our working copy. We have revision 26 of Log.java
4500and revision 27 of Contacts.java (which we’ve also modified).
4501The repository is currently at revision 30, and when we do
4502an update, we’ll get those extra changes incorporated into our
4503working copy.
4504Chapter 7
4505File Locking and Binary Files
4506A common question when learning about version control is,
4507“But what happens if two people edit the same file? Won’t
4508we waste our time undoing each others’ changes?†Thanks to
4509the magic of text merging, most of the time it isn’t a problem.
4510But what if the file is a picture or CAD model and cannot
4511be merged? Subversion 1.2 introduced optional file locking
4512which can help avoid problems with unmergeable files.
45137.1 File Locking Overview
4514Many projects contain unmergeable files. Sound, graphics,
4515and even many document formats cannot be merged in any
4516meaningful way. If Alice and Bob both decide to edit Currency-
4517ConversionRates.xls at the same time, one of them will be first to
4518commit and the other will have to re-do their changes.
4519Fundamentally, this problem is about your team not commu-
4520nicating effectively. It’s unlikely that Alice and Bob should
4521both be editing the project theme song audio file at the same
4522time, but without asking everyone else on the team whether
4523they have that file open there’s a chance they might be wast-
4524ing their time. Subversion provides a mechanism to help the
4525team communicate through optional file locking. file locking
4526Any file can be set to require a lock before it is edited by set-
4527ting its needs-lock property (it doesn’t matter what the property
4528contains—if it’s set, Subversion will enable locking on that
4529file). Any file with locking enabled will be checked out read-
4530F ILE L OCKING IN P RACTICE 100
4531only in the working copy. Most modern editors will refuse to
4532edit a read-only file, or will at least warn that you are doing
4533so, in an effort to remind the user that the file needs to be
4534locked before editing.
4535We can issue a svn lock command to obtain a lock on the file.
4536The Subversion client will chat with the server ensuring the
4537file isn’t already locked, obtain a lock token, and then mark lock token
4538the file read-write in the working copy. Additionally we can
4539specify a lock comment informing other users why we locked
4540the file.
4541If a file is locked, another user cannot lock the file or commit
4542a change to it without first destroying the original lock (we’ll
4543talk more about situations in which this is appropriate later).
4544When the user who locked the file is done and commits their
4545changes, the lock is released.
4546Let’s see how this works in practice. If you want to follow
4547along with these examples, create separate working copies for
4548Alice and Bob similar to those we created in Section 6.7, Han-
4549dling Merge Conflicts, on page 86.
45507.2 File Locking in Practice
4551The Sesame project is moving up in the world. In addition
4552to all of its existing features, our customers now want the
4553software to work in many different countries. As part of this
4554initiative we’ll need to convert between local currencies. The
4555real system will use some kind of web service to find out what
4556the exchange rates are, but for testing, Bob would like to use
4557something simple such as an Excel spreadsheet.
4558Why File Locking is Important
4559Bob creates a spreadsheet file, CurrencyConversionRates.xls , and
4560adds it to the repository:
4561sesame > svn add CurrencyConversionRates.xls
4562A (bin) CurrencyConversionRates.xls
4563sesame > svn commit -m "Added conversion rates for testing"
4564Adding (bin) CurrencyConversionRates.xls
4565Transmitting file data .
4566Committed revision 32.
4567F ILE L OCKING IN P RACTICE 101
4568Subversion automatically detects that the spreadsheet is a
4569binary file when it’s added, which also flags it as being non-
4570mergeable. If Alice checks out revision 32 and both Bob and
4571Alice change the file and attempt to commit, only one of them
4572will succeed. Here’s what Bob might see:
4573sesame > svn commit -m "Added Norwegian Krona conversion rate"
4574Sending CurrencyConversionRates.xls
4575Transmitting file data .svn: Commit failed (details follow):
4576svn: Out of date: ' /trunk/CurrencyConversionRates.xls '
4577in transaction ' 43-1 '
4578Bob’s working copy is out of date because Alice snuck her
4579changes in first. If this were a text file, Bob could simply
4580update his working copy and Subversion would merge Alice’s
4581committed changes with Bob’s pending changes. This doesn’t
4582work for the spreadsheet, however; it just produces a conflict:
4583sesame > svn up
4584C CurrencyConversionRates.xls
4585Updated to revision 33.
4586Subversion tells Bob his copy of CurrencyConversionRates.xls is
4587conflicting with the new revision in the repository. Bob has
4588some options now. He can do some detective work with svn log
4589to see who else changed the file, and he can choose to keep
4590his changes, keep Alice’s changes, or manually merge the two
4591files. All of this seems to be quite a lot of work.
4592Enabling Locking on a File
4593Bob decides he’ll throw away his changes and redo them.
4594After all, he only added a single line to the spreadsheet and
4595can quickly re-apply his change to the latest version. He’d like
4596to avoid the same problem in the future, though, so he adds
4597the svn:needs-lock property to the spreadsheet.
4598sesame > svn propset svn:needs-lock true CurrencyConversionRates.xls
4599property ' svn:needs-lock ' set on ' CurrencyConversionRates.xls '
4600sesame > svn commit -m "Enabled locking for spreadsheet"
4601Sending CurrencyConversionRates.xls
4602Committed revision 34.
4603Bob sets svn:needs-lock to “true†(remember it doesn’t actually
4604matter what the property contains; if it is present Subversion
4605enables locking for the file). This property change doesn’t take
4606effect until it is committed to the repository. If you’re adding
4607an unmergeable file and would like to enable locking, it’s good
4608F ILE L OCKING IN P RACTICE 102
4609practice to set the svn:needs-lock property right away. Subver-
4610sion’s autoprops, covered in Section 6.4, Automatic Property
4611Setting, on page 74, can help with this.
4612Basic File Locking
4613Once Alice and Bob update their working copies, Subver-
4614sion will make the CurrencyConversionRates.xls file read-only.
4615The idea behind making the working copy read-only is that
4616next time a user edits the file, they will be reminded they are
4617attempting to change a read-only file and remember to lock
4618the file before continuing. Depending on the application used
4619to edit the file you may or may not get a warning. Excel will
4620happily open a read-only file and let you change it without giv-
4621ing any warning—it’s only when you come to save the mod-
4622ified spreadsheet that you’re prompted for a new filename.
4623This isn’t usually too much of a problem, though, as many
4624users instinctively hit “save†quite often. Other applications
4625such as graphics or sound editors may treat read-only files
4626differently. You will have to experiment with your particular
4627application to find out.
4628After setting svn:needs-lock , Bob decides to add the Norwegian
4629Krona exchange rate again. This time, he locks the file before
4630editing it. 1
4631sesame > svn lock CurrencyConversionRates.xls \
4632-m "Adding Norwegian Krona"
4633' CurrencyConversionRates.xls ' locked by user ' bob ' .
4634It’s advisable to always include a comment indicating why you
4635are locking the file. Subversion can provide the lock comment
4636to other users and it’s a good way to improve communication.
4637Bob can now examine the file and see that it’s locked:
4638sesame > svn info CurrencyConversionRates.xls
4639Path: CurrencyConversionRates.xls
4640Name: CurrencyConversionRates.xls
4641URL: svn://olio/sesame/trunk/CurrencyConversionRates.xls
4642Repository Root: svn://olio/sesame
4643Repository UUID: 63a31077-dc47-8e48-8372-099aabc6682c
4644Revision: 34
4645Node Kind: file
4646Schedule: normal
4647Last Changed Author: bob
46481 Subversion will only let you lock a file if it is up to date—you cannot lock
4649an old revision.
4650F ILE L OCKING IN P RACTICE 103
4651Last Changed Rev: 34
4652Last Changed Date: 2006-03-06 15:31:04 -0700 (Mon, 06 Mar 2006)
4653Text Last Updated: 2006-03-06 15:29:58 -0700 (Mon, 06 Mar 2006)
4654Properties Last Updated: 2006-03-06 15:30:40 -0700 (Mon, 06 Mar 2006)
4655Checksum: 7cd95b6dcf6b3ce39baf073f56253e20
4656Lock Token: opaquelocktoken:42eef8ec-0355-d548-805b-16b5a8e830aa
4657Lock Owner: bob
4658Lock Created: 2006-03-06 17:10:17 -0700 (Mon, 06 Mar 2006)
4659Lock Comment (1 line):
4660Adding Norwegian Krona
4661There’s a lot of information here, but the stuff we’re interested
4662in is the final five lines. We can see that Bob’s working copy
4663has a lock token and that Bob is the lock owner. We can also
4664see when the lock was created and Bob’s comment explaining
4665why he locked the file.
4666If Alice now attempts to lock the file, she’ll receive an error.
4667sesame > svn lock CurrencyConversionRates.xls \
4668-m "Adding Euro conversion rate"
4669svn: warning: Path ' /trunk/CurrencyConversionRates.xls '
4670is already locked by user ' bob '
4671in filesystem ' /home/svnroot/sesame/db '
4672Subversion lets her know that Bob has already locked the file.
4673If Alice runs svn info on her working copy she won’t see a lock
4674token, indicating she doesn’t have a lock (she couldn’t, Bob
4675has a lock already). For Alice to find out more about why the
4676file is locked, she can ask Bob directly (improving team com-
4677munication) or she can ask the Subversion server. Running
4678svn info with the full URL for the file yields more information:
4679sesame > svn info svn://olio/sesame/trunk/CurrencyConversionRates.xls
4680Path: CurrencyConversionRates.xls
4681Name: CurrencyConversionRates.xls
4682URL: svn://olio/sesame/trunk/CurrencyConversionRates.xls
4683Repository Root: svn://olio/sesame
4684Repository UUID: 63a31077-dc47-8e48-8372-099aabc6682c
4685Revision: 34
4686Node Kind: file
4687Last Changed Author: bob
4688Last Changed Rev: 34
4689Last Changed Date: 2006-03-06 15:31:04 -0700 (Mon, 06 Mar 2006)
4690Lock Token: opaquelocktoken:42eef8ec-0355-d548-805b-16b5a8e830aa
4691Lock Owner: bob
4692Lock Created: 2006-03-06 17:10:17 -0700 (Mon, 06 Mar 2006)
4693Lock Comment (1 line):
4694Adding Norwegian Krona
4695Alice needs to use the full URL to find out about Bob’s lock—
4696if she uses just the file name, Subversion shows information
4697about her working copy. Alice’s working copy doesn’t have the
4698F ILE L OCKING IN P RACTICE 104
4699lock, so she needs to ask the server about the latest version
4700of the file.
4701Once Bob is done editing the file he can commit. When you
4702commit a file or directory, Subversion automatically releases
4703any locks you are holding. 2
4704Breaking Locks
4705The owner of a lock can always use svn unlock to release it.
4706But what if the lock owner isn’t currently available? Suppose
4707Alice tries to lock the exchange rates file to add some data.
4708Subversion warns her the file is already locked, so she does a
4709bit of investigation:
4710sesame > svn info \
4711svn://olio/sesame/trunk/CurrencyConversionRates.xls | grep Lock
4712Lock Token: opaquelocktoken:42eef8ec-0355-d548-805b-16b5a8e830aa
4713Lock Owner: bob
4714Lock Created: 2006-03-06 17:10:17 -0700 (Mon, 06 Mar 2006)
4715Lock Comment (1 line):
4716Alice can see that Bob has a lock on the file, but he created it
4717yesterday and still hasn’t released the lock. Since Bob is off
4718sick today, Alice decides to break the lock so she can make
4719her change. She also makes a mental note to remind Bob not
4720to leave important files locked for too long in the future.
4721The svn unlock command can be used to release someone else’s
4722lock on a file. Alice needs to pass the --force option because
4723she doesn’t own the lock herself:
4724sesame > svn unlock svn://olio/sesame/trunk/CurrencyConversionRates.xls
4725svn: warning: User ' alice ' is trying to use a lock owned
4726by ' bob ' in filesystem ' /home/svnroot/sesame/db '
4727sesame > svn unlock --force \
4728svn://olio/sesame/trunk/CurrencyConversionRates.xls
4729' CurrencyConversionRates.xls ' unlocked.
4730If Alice forgets to tell Bob that she broke his lock, when he
4731tries to commit the change Subversion will let him know he no
4732longer has a matching lock token. The token in Bob’s working
4733copy corresponds to the lock that Alice broke, so Bob will have
4734to attempt to lock the file again before he can commit it.
47352 Subversion releases locks for all files in your working copy, not just those
4736you are committing. This encourages users to release locks as quickly as
4737possible, but might catch you by surprise the first few times you do it.
4738F ILE L OCKING IN P RACTICE 105
4739sesame > svn commit -m "Added Norwegian Krona"
4740Sending CurrencyConversionRates.xls
4741Transmitting file data .svn: Commit failed (details follow):
4742svn: Cannot verify lock on path ' /trunk/CurrencyConversionRates.xls ' ;
4743no matching lock-token available
4744Given that Alice can just forcibly unlock the file, you might
4745think that Subversion’s file locking is a bit pointless. Bob is
4746in the same situation as if there were no locking at all—he
4747has to decide whether to throw away his changes or overwrite
4748Alice’s. What we have achieved, however, is better commu-
4749nication between people editing the file. Alice knew she was
4750breaking Bob’s lock, and did so for a good reason—Bob wasn’t
4751at work that day and Alice needed to get on with the project.
4752Subversion allows you to restrict who can lock and unlock
4753files, and who can break locks, through the use of special
4754hook scripts. The pre-lock and pre-unlock hooks run before
4755a file is locked or unlocked (respectively). These hooks can
4756examine whether a file is already locked and, depending on
4757site policy, restrict lock breaking operations to certain users.
4758The post-lock and post-unlock hooks can be used, for example,
4759to send email after a lock is broken. That way Alice can’t forget
4760to tell Bob she broke his lock, there will be an email waiting
4761for him to let him know.
4762After forcibly releasing Bob’s lock, Alice should then lock the
4763spreadsheet so she can make modifications to it. But there’s
4764a small chance someone else will lock the file in between Alice
4765typing those two commands, so Subversion also provides the
4766ability to steal the lock from another user.
4767Using the --force option with svn lock will steal the lock without
4768giving anyone else the chance to lock the file.
4769sesame > svn lock --force CurrencyConversionRates.xls
4770' CurrencyConversionRates.xls ' locked by user ' alice ' .
4771sesame > svn info CurrencyConversionRates.xls | grep Lock
4772Lock Token: opaquelocktoken:b8c434ce-98ef-1046-a553-7479abccdbca
4773Lock Owner: alice
4774Lock Created: 2006-03-07 14:44:26 -0700 (Tue, 07 Mar 2006)
4775It’s important to note that a lock is specific to a working copy
4776as well as being owned by a particular user. If Bob locks a file
4777using his office computer, then works from home the next day
4778on his laptop, the lock is still stored on the office machine. If
4779W HEN TO USE L OCKING 106
4780he wants to edit the file at home he’ll have to break the lock
4781held by the office working copy.
47827.3 When to use Locking
4783Subversion’s optional locking is very useful for controlling
4784access to unmergeable files. Adding svn:needs-lock to a file
4785can help your team communicate more effectively about who
4786is working on the file, and can help prevent wasted effort.
4787Try to lock as few files as possible for as short a time as possi-
4788ble. Don’t be like Bob—locking a file and then going home for
4789the night. The longer a file is locked, the greater the chance
4790someone else has to wait around before they can make their
4791changes. In the worst case, Alice might be waiting for Bob to
4792finish work on a file while Bob waits for Alice to finish work
4793on a different file. The two of them will wait forever for the
4794other’s lock to be released. Developers moving to Subversion
4795from systems such as Visual Source Safe will be familiar with
4796this “deadlock†situation.
4797If your files are text, such as program code, Subversion can
4798usually merge changes for you and you don’t need to lock
4799them. There can be cases where it seems attractive to start
4800locking mergeable files, such as an important source code
4801file that developers update quite often and which seems to
4802encounter a lot of conflicts. Usually the best solution isn’t
4803to start locking the file, it’s to figure out how to split the file
4804into several logical pieces so the whole team doesn’t need to
4805continually trip over each other when making changes.
4806Chapter 8
4807Organizing Your Repository
4808When using a version control system, you’ll most likely want
4809to store more than one project. A single Subversion repository
4810can be used to store files used by developers across an orga-
4811nization, whether those developers are working on the same
4812team or not. Version control systems use a variety of tech-
4813niques for splitting a repository into projects, subprojects,
4814modules, and so on. Subversion uses a fairly simple mech-
4815anism, organizing everything into directories.
48168.1 A Simple Project
4817Throughout this book, we’ve been using the Sesame project
4818as our main example. Back in Section 3.3, Creating a Simple
4819Project, on page 34, we imported our Sesame project files to
4820/sesame/trunk inside the repository. At the time we deferred
4821explanation of why we needed trunk instead of putting files
4822directly in the sesame directory—now it’s time to explain a
4823little more.
4824Most projects will have a main line of development, where the main line
4825majority of development activity occurs. Projects also tend
4826to have release branches where code that has been finished release branches
4827and shipped to production is stored. A release branch won’t
4828change very much, except for bug fixes that need to be made.
4829Finally, significant events in the life cycle of a project are often
4830recorded in tags. A tag might contain the exact code used for tags
4831releasing version 5 of Sesame, for example.
4832M ULTIPLE P ROJECTS 108
4833v w v xyw
4834z
4835{
4836x| v
4837z
4838{
4839}
4840~ €
4841Â
4842‚ ƒ„
4843†
4844‡
4845ˆ
4846Â
4847‰
4848}
4849x
4850Š‹
4851wv
4852z
4853‚ Œ
4854†
4855‡
4856ˆ
4857z
4858Â
4859Â
4860Â
4861Â
4862Â
4863Â
4864Â
4865Â
4866Â
4867Figure 8.1: The Sesame Project Trunk and Branches
4868Chapter 9, Using Tags and Branches, on page 111 has lots of
4869information about tags and branches, but for now you just
4870need to know that both tags and branches are created by
4871copying directories in the Subversion repository. The recom-
4872mended location for tags is a tags/ directory and (surprise!) for
4873branches a branches/ directory.
4874Both of these directories need to be easy to find for your
4875project, so for Sesame we’d end up with /sesame/trunk for the
4876main development area, /sesame/tags for storing tags, and
4877/sesame/branches for storing branches. Figure 8.1 shows this
4878a little more visually.
4879Storing the code for your project in a trunk directory corre-
4880sponds to the SCM “mainline†pattern.
48818.2 Multiple Projects
4882So far we have a repository storing the Sesame project. It’s
4883easy to see how we could store other projects, Aladdin and
4884Rapunzel, as shown in Figure 8.2 on the following page.
4885M ULTIPLE R EPOSITORIES 109
4886ÂŽÂŽ‘Â
4887Â’
4888“
4889”Ž
4890Â’
4891“
4892•
4893–—˜
4894™
4895š
4896š
4897š
4898›
4899•
4900Â
4901—œÂ
4902ÂÂŽ
4903Â’
4904š
4905š
4906š
4907š
4908š
4909š
4910Â
4911ž
4912ŸŸ
4913—
4914Â’
4915“
4916 ” Ž
4917Â’
4918“
4919•
4920–—˜
4921™
4922š
4923š
4924š
4925›
4926•
4927Â
4928— œÂ
4929ÂÂŽ
4930Â’
4931š
4932š
4933š
4934š
4935š
4936š
4937•
4938¡
4939– —¢
4940Â
4941ž
4942Â’
4943“
4944”Ž
4945Â’
4946“
4947•
4948– — ˜
4949™
4950š
4951š
4952š
4953›
4954•
4955Â
4956—œÂ
4957ÂÂŽ
4958Â’
4959š
4960š
4961š
4962š
4963š
4964š
4965•
4966¡£Ž
4967“
4968£
4969•
4970¤
4971Â’
4972Figure 8.2: Aladdin and Rapunzel Projects
4973It’s important to realize that because Subversion uses direc-
4974tory copies for branching and tagging, you don’t have to name
4975your tags directory tags . It might be confusing for your users,
4976however, if you’re using a different name. You also don’t have
4977to put your trunk, tags, and branches directories all together
4978in a single directory. You don’t need to have each project at
4979the root directory of the repository—depending on how your
4980developers and IT department are organized, something like
4981/finance/revenue/ali-baba might work best for you.
4982Subversion’s ability to move directories means that if your
4983repository gets out of control—perhaps you have a few dozen
4984projects at the root level and things are getting unwieldy—
4985you can move projects around easily. Using svn move with two
4986repository URLs, as discussed in Section 6.5, Using Repository
4987URLs, on page 79, will do a server-side rename and instantly
4988move directories. You should coordinate with developers to
4989make sure they have checked in any outstanding changes,
4990perform the move, and then get everyone to run svn update to
4991get the new directory structure.
49928.3 Multiple Repositories
4993Splitting your projects into different directories makes a lot
4994of sense—developers can easily find the project they should
4995M ULTIPLE R EPOSITORIES 110
4996be working on and make changes. It’s also possible to split
4997projects across multiple repositories. Since a repository exists
4998on disk as a set of files in a particular directory, you can create
4999multiple repositories in different directories on a single server
5000or create repositories on entirely separate servers.
5001If you’re accessing a Subversion repository using file://
5002and svn+ssh:// URLs, the first part of the URL specifies the
5003path to the repository directory on the server. You can easily
5004change this to specify a different directory for the repository.
5005When using svnserve , its --root option specifies a virtual root
5006directory for your repositories. If you create directories named
5007(for example) repos1 and repos2 inside the virtual root, with a
5008repository in each, these repository directory names become
5009part of the repository URL. In this case you’d access repos1
5010using svn://myserver/repos1/... .
5011If you’re using Apache to network a Subversion repository,
5012you might define a virtual directory for each repository on
5013the server. Apache configuration is covered in Appendix A
5014on page 151.
5015Of course, separating projects across multiple repositories is
5016extra administration overhead—you’ll have to back up each
5017repository separately. Users might also need more informa-
5018tion on where to find a particular project. The upside to this
5019extra admin overhead is flexibility. If you need to take down
5020a repository for maintenance, 1 you can do so without affect-
5021ing other repositories. If a particular project is outgrowing the
5022server on which it’s hosted, it might make sense to split the
5023repository in two so you can add a second server.
5024You don’t have to make a final decision on day one. Sub-
5025version provides tools to allow you to migrate data between
5026repositories, so you can change your mind when you know
5027more about your requirements. To keep things as simple as
5028possible, we recommend using just a single repository until
5029you’ve got a concrete problem that will be solved by using
5030multiple repositories.
50311 This is somewhat unlikely, since most Subversion maintenance, includ-
5032ing performing backups, can be done without taking down the server.
5033Chapter 9
5034Using Tags and Branches
5035Day-to-day use of Subversion is pretty simple: you update
5036from your repository, edit files, and save the changes back
5037after you’ve tested. However, many developers are put off
5038by tags and branches. Perhaps they’ve worked previously
5039in teams that abused branches and where a diagram of the
5040repository structure would have looked like a bowl of spaghetti
5041rather than a controlled, linear development. Or perhaps
5042they worked in a team where merges between branches were
5043delayed and delayed, so when they did finally occur, it was
5044a nightmare resolving the conflicts. Or perhaps it’s just the
5045incredible flexibility that branches offer; with so much choice,
5046it’s hard to know what to do.
5047In reality, tags and branches can (and should) be simple to
5048use. The trick is to use them in the correct circumstances.
5049In this chapter we present two scenarios where we believe
5050branches should be used by teams: generating releases and
5051giving developers a place to experiment.
5052Beyond these two circumstances, we suggest you think hard
5053before adding branches to a repository. Excessive branching
5054can quickly render any project’s repository unusable.
5055Before we go into the specific recipes, we need to discuss tags
5056and branches in general.
5057T AGS AND B RANCHES 112
5058¥¦ §
5059¨
5060© ª
5061¨
5062«
5063¬
5064©  ©
5065Â¥
5066®
5067¦ª¯
5068«
5069¬
5070©Â©
5071°© ±
5072«
5073¬
5074©Â©
5075²
5076³´
5077µ
5078¶·
5079µ
5080¶ ·
5081²
5082³´
5083²
5084³´
5085²
5086³ ´
5087Figure 9.1: Tags as Slices Through the Repository
50889.1 Tags and Branches
5089Your Subversion repository probably contains a lot of informa-
5090tion. Apart from the sheer number of source files that com-
5091prise a typical project, Subversion also stores every revision of
5092each file. Adding time as a dimension to locating information
5093in your repository means the complexity just explodes—how
5094can we possibly keep track of it all? A tag is a symbolic name
5095for a set of files, each with a particular revision number. You
5096can think of a tag as making a slice through your repository
5097and labeling everything inside, as shown in Figure 9.1 .
5098Tags are really useful for keeping track of important events in
5099the life cycle of your project. Instead of having to remember
5100that you built a release for your customer using revision 16
5101of Calendar.java , revision 23 of Schedule.java , and revision 12
5102of contacts.dat , you can use a tag to remember this for you.
5103Since a Subversion revision number is also a slice through
5104the repository, you might think we could just use revision
5105numbers or maybe the date we checked the code out in order
5106to build a release. This could work, but tags can also be
5107made from a mixed revision working copy—a set of files you’ve
5108checked out that doesn’t correspond to a single repository
5109revision number. This might be needed if you want to pick
5110and choose which versions of project components should be
5111packaged together during a release.
5112To create a tag in Subversion, copy your code (typically from
5113the trunk) in the tags directory for your project. Subversion
5114T AGS AND B RANCHES 113
5115Joe Asks...
5116How Do I Make a Tag Read-Only?
5117Tags are just copies of your repository at a particular
5118revision, so there’s nothing to stop people from check-
5119ing changes into the tags directory. Whilst sometimes
5120it’s useful to be able to change a tag, most of the
5121time it’s best to treat tags as being read-only.
5122You can make your tags directory read-only (or more
5123correctly create-only—new tags should be allowed)
5124by using one of the repository permissions scripts cov-
5125ered in Section A.5, Access Control with Hook Scripts,
5126on page 168. Often, though, this is overkillsince devel-
5127opers will be working on the trunk or a release branch,
5128rather than on a tag.
5129handles this copy process very efficiently, making the copy
5130instantly and requiring very little space to store it. The direc-
5131tory to which you copy the code is the symbolic name for the
5132tag. The copy serves as a reference point, storing the files in
5133your project as they were when the tag was created.
5134Directory copies in Subversion are just that—simple copies.
5135By convention, you’ll never make changes to the code stored
5136underneath tags , but there’s nothing actually stopping you
5137from doing so. If you do check in changes to a tag direc-
5138tory, the tag effectively becomes a branch. Subversion won’t
5139move it to your branches directory or anything clever like that,
5140but the tag will no longer contain a fixed snapshot of your
5141repository. This could be useful in certain cases—for exam-
5142ple, you could set up a latest tag that always contains your
5143most recently built (and tested) code.
5144We first talked about branches in Section 2.7, Branches, on
5145page 19, when we discussed how we can use them to handle
5146releases in a version control system. A branch represents a
5147fork in the history of the repository; the same file may have
5148two or more sets of independent changes made to it, each set
5149existing in a separate branch.
5150T AGS AND B RANCHES 114
5151To create a branch in Subversion, you’ll copy your trunk code
5152to a directory underneath branches for your project. The new
5153directory names the branch, and initially just stores a Subver-
5154sion “cheap copy†of the files as they were when the branch
5155was made. When you check in a change to files on a branch,
5156Subversion remembers the changes in parallel with changes
5157made to the original on the trunk. Subversion also remembers
5158that the two files have a common history.
5159Tags and Branches in Practice
5160Tags and branches have many possible uses. However, exces-
5161sive tagging and branching can end up being remarkably con-
5162fusing. So to keep things simple, we suggest that initially you
5163use them for four different purposes:
5164Release Branches
5165We recommend putting each release of a project onto
5166a separate branch. The directory used inside branches
5167names the branch.
5168Releases
5169The release branch will contain one (and possibly more)
5170releases: points at which the project is shipped. The
5171release tags identify these points.
5172Bug Fixes
5173Bugs in the release are fixed on the release branch. If
5174appropriate the fix is then merged into the trunk and
5175other release branches. In cases where a bug is fixed
5176in one commit, a Subversion revision number is enough
5177to identify what changed and perform any merges. For
5178more complicated bugs a branch is created for the bug
5179fix and merged into the release branch and trunk when
5180the fix is complete. Tags are created to mark the start
5181and end of the bug fix in order to make merging easier.
5182Developer Experiments
5183Sometimes a subteam has to make far-reaching changes
5184to a project’s code base. During the time that these
5185changes are being made, the code is incompatible with
5186the rest of the system and will break the main build. The
5187developers may choose to create a branch labeled as a
5188developer experiment and perform their changes there.
5189C REATING A R ELEASE B RANCH 115
5190Thing to Name Name Style Examples
5191Release branch RB-rel RB-1.0
5192RB-1.0.1a
5193Releases REL-rel REL-1.0
5194REL-1.0.1a
5195Bug fix branches BUG-track BUG-3035
5196BUG-10871
5197Pre–bug fix PRE-track PRE-3035
5198PRE-10871
5199Post–bug fix POST-track POST-3035
5200POST-10871
5201Developer experiments TRY-initials-desc TRY-MGM-cache-pages
5202TRY-MR-neo-persistence
5203Figure 9.2: Tag and Branch Naming Conventions
5204It’s a good idea to agree upon a naming convention for tags
5205and branches with your team. The table in Figure 9.2 shows
5206one simple scheme; this is what we’ll be using in this book.
5207In this table, rel stands for the release number, and track is a
5208bug tracking number.
5209Next we’ll take a look at branches and tags in action, starting
5210with (we hope!) a common event in your project life cycle—
5211creating a release branch so we can ship some code.
52129.2 Creating a Release Branch
5213At intervals throughout the life of your software you’ll want to
5214generate releases. As the date for each release nears, atten-
5215tion will start to focus away from adding new features, instead
5216concentrating on tidying the smaller release-specific details.
5217Although initially the whole team may participate in this pro-
5218cess, there’ll come a time when the law of diminishing returns
5219takes effect, and it becomes more efficient to have a release
5220subteam focus on polishing the code for release. If this sub-
5221C REATING A R ELEASE B RANCH 116
5222¸¹
5223º
5224»¹
5225¼ ½ ¾¿
5226» ¹ À Ã
5227º
5228Â
5229¿ Ã
5230Ä
5231º
5232¾ ¿¼½
5233Figure 9.3: Release Branch Merges to the Trunk
5234team was working in the trunk, the rest of the team would be
5235stalled, waiting for them to finish.
5236Instead, at this point in the process, move the code to be
5237released into its own branch. While the release team works
5238in that branch, the rest of the project can continue in the
5239trunk. When the release itself is made, we tag the state of the
5240release branch with the release number (remember that a tag
5241is simply a copy of the release branch at a particular point
5242in time). Changes made by the release team in the release
5243branch can then be merged back in to the trunk, as shown in
5244Figure 9.3 .
5245Create the release branch by copying your project’s trunk to a
5246new directory underneath branches/ . It’s best to do this using
5247repository URLs, because then the branch creation will hap-
5248pen entirely on the server and be a lot quicker. You should
5249make sure everyone has checked their local working copy in
5250and is ready for the branch to be created. 1
5251In the following example, we create a branch for release 1.0
5252of our project. We also need to create the /sesame/branches
5253directory, because this is the first branch we’ve made:
5254work > svn mkdir -m "Creating branches directory" \
5255svn://olio/sesame/branches
5256Committed revision 32.
52571 Using repository URLs to create a branch, it’s possible to make the
5258branch start from any revision in the repository. If you’re a bit late mak-
5259ing a branch, it’s always possible to talk to other developers, figure out which
5260revision the branch should have started at, and use that instead.
5261W ORKING IN A R ELEASE B RANCH 117
5262work > svn copy -m "Creating release branch for 1.0" \
5263svn://olio/sesame/trunk \
5264svn://olio/sesame/branches/RB-1.0
5265Committed revision 33.
5266Both the branches directory creation and the creation of the
5267actual branch require a commit message since they change
5268the repository.
5269At this point, all we’ve done is to create the release branch.
5270Any working copies checked out by developers will still be
5271pointing at the trunk. To start actually using the release
5272branch, we’ll need to check it out into a new working copy.
52739.3 Working in a Release Branch
5274To access a release branch, you need to check out the project
5275from its branch directory instead of the trunk. You can check
5276out to a separate directory or switch an existing working copy switch
5277to the branch. We recommend the former; it leads to less con-
5278fusion and simplifies working on both branches at the same
5279time. The svn switch command is useful for assembling differ-
5280ent code branches in a working copy, so we’ll discuss both
5281methods.
5282Checking Out a Release Branch
5283If you’re like us, you have plenty of disk space and would
5284rather waste a bit of it than have to remember what branch a
5285particular working copy is looking at. We tend to keep a work-
5286ing copy checked out for each active development branch, just
5287to make things easy.
5288Change back to your work directory, and then check out from
5289the branch directory overriding the default directory name, so
5290the source will be checked out under the directory rb1.0 . When
5291you check out a branch, you are checking out the most recent
5292files in that branch; it’s equivalent to the way that checking
5293out in the trunk returns the latest development copies of the
5294files:
5295work > svn co svn://olio/sesame/branches/RB-1.0 rb1.0
5296A rb1.0/Month.txt
5297A rb1.0/Number.txt
5298A rb1.0/common
5299A rb1.0/common/Log.java
5300A rb1.0/common/Clock.java
5301W ORKING IN A R ELEASE B RANCH 118
5302A rb1.0/Day.txt
5303A rb1.0/contacts
5304A rb1.0/contacts/Contacts.java
5305Checked out revision 33.
5306If we now edit a file in this checked-out release directory and
5307commit the changes, Subversion adds the changes into the
5308branch, not into the trunk. We can now continue to refine the
5309files in preparation for the actual release.
5310Switching a Working Copy to a Release Branch
5311The svn switch command alters all or part of a working copy so
5312that it points to a different branch. Since most branches con-
5313tain only a few differences from the trunk, Subversion can do
5314this operation extremely efficiently, transmitting only changed
5315files to the client. Switching a working copy to point at a dif-
5316ferent branch is much faster than checking out a new working
5317copy for that branch.
5318To switch your working copy of the Sesame trunk to the 1.0
5319release branch, run the following svn switch command:
5320work > cd sesame
5321sesame > svn switch svn://olio/sesame/branches/RB-1.0
5322U common/Clock.java
5323U contacts/Contacts.java
5324Updated to revision 36.
5325Subversion updates the files in the Sesame working copy so
5326that they reflect the latest files in the release branch, in this
5327case updating two Java files to reflect bug fixes made on the
5328branch.
5329The svn switch command also accepts a --revision argument
5330to specify which revision of the branch you’d like to switch to.
5331By default, Subversion switches to the latest revision of the
5332branch (the HEAD revision).
5333You can switch your working copy back to the trunk like this:
5334sesame > svn switch svn://olio/sesame/trunk
5335U common/Clock.java
5336U contacts/Contacts.java
5337Updated to revision 36.
5338Subversion can also switch a subdirectory or even a single file
5339to a different branch. This ability is used in the next section to
5340assemble a working copy with a precise bug fix for a customer.
5341G ENERATING A R ELEASE 119
53429.4 Generating a Release
5343After all the tweaking is over, and the acceptance tests run,
5344the team decides to generate a release. The most important
5345consideration is to ensure that we tag the correct combination
5346of files on the correct branch so that we know precisely what’s
5347in the release.
5348The simplest way to create a release tag is to copy the branch
5349to a new directory under tags . This will tag the latest code in
5350the release branch.
5351Sometimes you might want to tag files or directories that are
5352not all at the same revision. Generally, wanting to tag any-
5353thing other than the latest code on a branch is an indication
5354that something has gone wrong somewhere, so we don’t advise
5355making a habit of it. Subversion can tag the state of any work-
5356ing copy, copying a mixture of revisions into a tag, from which
5357you can potentially create a release.
5358These two methods are a little confusing at first, so let’s start
5359with the simplest. Once you’re happy with the latest code in
5360the release branch, copy it to a new directory under tags :
5361work > svn mkdir -m "Creating tags directory" \
5362svn://olio/sesame/tags
5363Committed revision 34.
5364work > svn copy -m "Tag release 1.0.0" \
5365svn://olio/sesame/branches/RB-1.0 \
5366svn://olio/sesame/tags/REL-1.0.0
5367Committed revision 35.
5368The previous svn copy copied the latest code, revision 34 in
5369this case, from the release branch to the new tag REL-1.0.0 .
5370Sometimes you’ll need to tag something other than the lat-
5371est code in a branch. Suppose release 1.0.0 was a couple of
5372months ago, and the team has successfully shipped a bunch
5373of small fixes, taking them to release 1.0.4. An important
5374client requires a fix to release 1.0.0 but doesn’t want to wait
5375for 1.0.5 to get the fix. The bug is pretty trivial, so we’d like to
5376add the fix for it to the 1.0.0 code and ship that to the client. 2
53772 This is really a pretty nasty kludge, but if your client really doesn’t want
5378to upgrade, it might be the only solution.
5379G ENERATING A R ELEASE 120
5380We’ll check out a working copy with everything as it was in
53811.0.0 and then update a few files for our client. In this exam-
5382ple, Clock.java contained the bug we’re trying to fix:
5383work > svn checkout svn://olio/sesame/tags/REL-1.0.0 \
5384client-fix
5385A client-fix/Month.txt
5386A client-fix/Number.txt
5387A client-fix/common
5388A client-fix/common/Log.java
5389A client-fix/common/Clock.java
5390A client-fix/Day.txt
5391A client-fix/contacts
5392A client-fix/contacts/Contacts.java
5393Checked out revision 37.
5394Next use svn switch to change where the common directory in
5395your working copy is pointing. We’d like to get the bug fixes
5396from the release branch that have been made since the 1.0.0
5397tag was created, so we switch and point at RB-1.0 :
5398work > cd client-fix
5399client-fix > svn switch \
5400svn://olio/sesame/branches/RB-1.0/common \
5401common
5402U common/Clock.java
5403Updated to revision 37.
5404Now your working copy contains what the client wants—the
5405code as it was when 1.0.0 was shipped, with the critical bug
5406fix that was made on the release branch since then.
5407After running tests and verifying the code in our working copy
5408does fix the problem, we can create the new tag. We use svn
5409copy to copy our client-fix working copy into a new tag directory
5410REL-1.0.0-clientfix :
5411client-fix > cd ..
5412work > svn copy -m "Tagging client ' s 1.0.0 fix" client-fix \
5413svn://olio/sesame/tags/REL-1.0.0-clientfix
5414Committed revision 37.
5415Developers can retrieve the code used to build a particular
5416release using svn checkout and the tag’s URL:
5417work > svn co svn://olio/sesame/tags/REL-1.0.0
5418A REL-1.0.0/Month.txt
5419A REL-1.0.0/Number.txt
5420A REL-1.0.0/common
5421A REL-1.0.0/common/Log.java
5422A REL-1.0.0/common/Clock.java
5423A REL-1.0.0/Day.txt
5424A REL-1.0.0/contacts
5425A REL-1.0.0/contacts/Contacts.java
5426Checked out revision 37.
5427F IXING B UGS IN A R ELEASE B RANCH 121
54289.5 Fixing Bugs in a Release Branch
5429Bugs happen. The trick is to handle them in a controlled
5430manner. In a release branch, this means we need to keep
5431track of the changes made to fix the bug and then make sure
5432we apply those fixes to every other branch that might contain
5433the same problem. That last point is particularly important.
5434By their nature, branches contain duplicate code. That means
5435if you find a bug in the source code in one branch, there’s
5436always the possibility the same bug exists in another branch
5437(after all, originally the source code was the same, bugs and
5438all). In the case of a release branch, we need to be able to
5439apply our fix to the trunk. We might also need to apply it to
5440other release branches (if they also contain the buggy code).
5441Without version control, this is a tricky problem. With version
5442control, we can manage the process better. We do this by
5443getting the version control system to keep track of the source
5444code changes made while fixing the bug and then merging
5445those changes into the code in other affected branches.
5446With Subversion, how exactly we track the bug fix depends on
5447how “difficult†the bug is to fix. If it’s a small bug, the fix might
5448be a couple of lines changed in a few files. For a more major
5449defect, the fix might involve changing quite a bit of code, and
5450adding and removing some files, and might be a group effort
5451involving more than one developer.
5452Subversion tracks changes using revision numbers, as we
5453saw in Section 3.6, Updating the Repository, on page 41. If
5454you can fix a bug in a single commit, just remembering the
5455revision number is enough for us to copy the change to other
5456branches. If the bug is more complicated and requires several
5457commits to fix (or includes a number of failed attempts to fix
5458it), you might need to create a branch to track the fix.
5459Simple Bug Fixes
5460Let’s assume we’re trying to fix a reasonably simple problem,
5461where the fix just requires changes to a couple of files. The
5462process is described in the following list.
54631. Check out the code containing the bug into a local work-
5464ing copy.
5465F IXING B UGS IN A R ELEASE B RANCH 122
54662. Generate a test to reveal the bug, fix the code so the new
5467test passes, and verify the build.
54683. Commit your changes into the repository, and remember
5469the new revision number. A good way of remembering
5470this revision number is to add it to your bug tracking
5471system so everyone can find it later.
54724. Use the new revision number to merge the change to all
5473other affected branches (potentially including the trunk).
5474As an example, let’s fix bug 3065 on the release branch. First
5475we go into the release branch working copy, fix the bug, and
5476check in:
5477rb1.0 > # .. edit contacts/Contacts.java and fix the bug .. #
5478rb1.0 > svn commit -m "Fix bug 3065 (address formatting)"
5479Sending contacts/Contacts.java
5480Transmitting file data .
5481Committed revision 38.
5482Subversion tells us our fix was committed as revision 38. To
5483merge the fix to the trunk, we go to the trunk working copy
5484and ask Subversion to merge revision 38. More specifically,
5485we ask for the difference between revisions 37 and 38 to be
5486merged to the trunk working copy:
5487rb1.0 > cd ../sesame
5488sesame > svn update
5489At revision 38.
5490sesame > svn merge -r37:38 svn://olio/sesame/branches/RB-1.0
5491U contacts/Contacts.java
5492sesame > svn commit -m "Merge r38 (fix bug 3065)"
5493Sending contacts/Contacts.java
5494Transmitting file data .
5495Committed revision 39.
5496Complex Bugs
5497If you’re dealing with a difficult bug that might take several
5498developers a few days to fix, plain old Subversion revision
5499numbers might not cut it. Cheap copies to the rescue once
5500again—we’ll create a branch where the bug fixing can be car-
5501ried out and use tags to identify when we start and finish the
5502fix. These tags will help us merge the fix to other branches.
5503The process works like this:
55041. Branch the code containing the bug into a new bug fix
5505branch.
5506F IXING B UGS IN A R ELEASE B RANCH 123
55072. Tag the new branch to mark the start of the bug fix.
55083. Generate a test to reveal the bug, fix the code so the new
5509test passes, and verify the build.
55104. Commit your changes into the repository. If it takes a
5511few tries to fix the bug, don’t worry.
55125. Once you’re happy with the fix, tag the branch again to
5513mark the end of the bug fix.
55146. Use the two tags to merge the fix to all the other affected
5515branches.
5516When creating a branch for the bug fix, we’re using the nam-
5517ing convention BUG-track, where track is a bug tracking num-
5518ber. We use tags named PRE-track and POST-track to mark
5519the start and end of the bug fix:
5520work > svn copy -m "create bugfix branch" \
5521svn://olio/sesame/branches/RB-1.0 \
5522svn://olio/sesame/branches/BUG-10512
5523Committed revision 40.
5524work > svn copy -m "tag bugfix start" \
5525svn://olio/sesame/branches/BUG-10512 \
5526svn://olio/sesame/tags/PRE-10512
5527Committed revision 41.
5528We’ve tagged the start of the bug fix using the tag PRE-10512
5529and can do the actual bug fixing work in branch BUG-10512 .
5530Check out a new working copy of the branch, and fix the bug:
5531work > svn checkout svn://olio/sesame/branches/BUG-10512
5532A BUG-10512/Month.txt
5533A BUG-10512/Number.txt
5534A BUG-10512/common
5535A BUG-10512/common/Log.java
5536A BUG-10512/common/Clock.java
5537A BUG-10512/Day.txt
5538A BUG-10512/contacts
5539A BUG-10512/contacts/Contacts.java
5540Checked out revision 41.
5541work > cd BUG-10512
5542BUG-10512 > # .. Fix bug, possibly adding and removing files .. #
5543BUG-10512 > svn commit -m "Fixing bug 10512"
5544Adding Year.txt
5545Sending common/Log.java
5546Transmitting file data ..
5547Committed revision 42.
5548BUG-10512 > # .. Bug wasn ' t fixed, ask Bob to help out too .. #
5549BUG-10512 > svn commit -m "Still fixing bug 10512"
5550Sending Number.txt
5551Transmitting file data .
5552Committed revision 43.
5553D EVELOPER E XPERIMENTAL B RANCHES 124
5554At this point we’ve fixed the bug. It took us a couple of
5555attempts, and maybe we even asked a colleague to check out
5556branch BUG-10512 and take a look at it for us. Now we should
5557tag the bug fix branch so we can identify the end of the bug
5558fix:
5559BUG-10512 > cd ..
5560work > svn copy -m "tag bugfix finish" \
5561svn://olio/sesame/branches/BUG-10512 \
5562svn://olio/sesame/tags/POST-10512
5563Committed revision 44.
5564Now merge the bug fix to the release branch, which is where
5565we wanted the fix in the first place. After merging, run the
5566test suite to make sure nothing is broken, and then check in:
5567work > cd rb1.0
5568rb1.0 > svn update
5569At revision 44.
5570rb1.0 > svn merge svn://olio/sesame/tags/PRE-10512 \
5571svn://olio/sesame/tags/POST-10512
5572U Number.txt
5573U common/Log.java
5574A Year.txt
5575rb1.0 > # ... run tests ... #
5576rb1.0 > svn commit -m "Merged fix for bug 10512"
5577Sending Number.txt
5578Adding Year.txt
5579Sending common/Log.java
5580Transmitting file data ..
5581Committed revision 45.
5582The same svn merge command can be used to pull the bug
5583fix into other branches and the trunk. Just change into your
5584trunk working copy, make sure it’s up-to-date, and use the
5585same merge command to get the fix.
5586In many cases the simpler method of just tracking the revi-
5587sions committed during a bug fix will work fine, so use it if
5588you can. Some bug tracking software includes a place to track
5589revision numbers explicitly, but if yours doesn’t you can just
5590put revision numbers into the bug’s comments field.
55919.6 Developer Experimental Branches
5592Sometimes developers need to make wide-ranging changes to
5593a project (for example, to change a persistence layer or intro-
5594duce a new security mechanism). These kinds of things take
5595a minimum of several days to code, and (unfortunately) they
5596can’t be introduced incrementally: they just affect too much
5597D EVELOPER E XPERIMENTAL B RANCHES 125
5598code. These changes are typically at a low level in the appli-
5599cation and normally have a far-reaching impact on the rest of
5600the system.
5601If a single developer wants to make a wide-ranging change
5602to the source, they could work in their local workspace. How-
5603ever, this has a couple of potential downsides. First, the devel-
5604oper loses the benefit of version control while they’re working
5605on the change; also, they lose the ability to revert just sec-
5606tions of their work, they lose revision history, and so on. They
5607also don’t have their work in a central repository, so there’s a
5608chance it won’t be backed up.
5609If multiple developers are working on a wide-ranging change,
5610then they have bigger problems; they need to be able to share
5611changes and work on the same (experimental) code base.
5612The answer is to put the experimental code into a branch in
5613the version control system. The developers working on the
5614changes use that branch in their workspace. When they’ve
5615finished their work, they can make the decision about inte-
5616grating their work into the trunk. If they decide that exper-
5617iment is a failure, they can abandon the branch. Otherwise
5618they simply merge the changes made in the branch into the
5619trunk. Whatever their decision, future work continues in the
5620trunk, and the branch becomes history.
5621Creating a developer branch is effectively the same as creating
5622a release branch. We copy the trunk into a new experimental
5623branch directory, stored alongside release branches: 3
5624work > svn copy -m "new hibernate persistence spike" \
5625svn://olio/sesame/trunk \
5626svn://olio/sesame/branches/TRY-MGM-hbn-spike
5627Committed revision 45.
5628To start using the branch, you need to either check it out into
5629a new working copy or switch an existing working copy to the
5630new branch.
56313 You might not want experimental branches cluttering up your release
5632branches directory, and Subversion is perfectly happy to let you put a branch
5633anywhere you like. Just make sure you remember that /branches/cb/fluffy
5634contains that new persistence framework you’re betting the company on....
5635W ORKING WITH E XPERIMENTAL C ODE 126
56369.7 Working with Experimental Code
5637If you have a working copy of your project already checked
5638out, you can switch it to the new experimental branch using
5639svn switch . Here we’ll switch our sesame working copy:
5640work > cd sesame
5641sesame > svn switch svn://olio/sesame/branches/TRY-MGM-hbn-spike
5642At revision 45.
5643To switch the sesame working copy back to the trunk, we use
5644svn switch again:
5645sesame > svn switch svn://olio/sesame/trunk
5646At revision 45.
5647Instead of reusing a working copy, you can check out the
5648branch into a new directory. This is our preferred option,
5649because it’s harder to get confused about what you’re work-
5650ing on:
5651work > svn co svn://olio/sesame/branches/TRY-MGM-hbn-spike hbn-spike
5652A hbn-spike/Month.txt
5653A hbn-spike/Number.txt
5654A hbn-spike/common
5655A hbn-spike/common/Log.java
5656A hbn-spike/common/Clock.java
5657A hbn-spike/Day.txt
5658A hbn-spike/Year.txt
5659A hbn-spike/contacts
5660A hbn-spike/contacts/Contacts.java
5661Checked out revision 45.
56629.8 Merging the Experimental Branch
5663Once you’re happy with the changes you’ve made in an exper-
5664imental branch, you’ll need to merge them back to the trunk.
5665To do this, first make sure all the developers have checked in
5666their changes and that you have an up-to-date working copy
5667of the trunk (this little dance is the reason we suggest check-
5668ing out the experimental branch in a different directory).
5669We need to tell Subversion to merge all the changes in the
5670experimental branch, from when it was created to its latest
5671state, into the trunk. For this, we need to know when the
5672branch was created. Fortunately, svn log has a --stop-on-
5673copy option that will tell us exactly:
5674work > svn log --stop-on-copy \
5675svn://olio/sesame/branches/TRY-MGM-hbn-spike
5676M ERGING THE E XPERIMENTAL B RANCH 127
5677----------------------------------------------------------
5678r47 | mike | 2004-11-12 13:47:13 -0700 (Fri, 12 Nov 2004)
5679Added hibernate utils
5680----------------------------------------------------------
5681r46 | mike | 2004-11-12 13:46:27 -0700 (Fri, 12 Nov 2004)
5682Made Contacts a hibernate mapped class
5683----------------------------------------------------------
5684r45 | mike | 2004-11-12 12:55:21 -0700 (Fri, 12 Nov 2004)
5685new hibernate persistence spike
5686----------------------------------------------------------
5687This tells us the TRY-MGM-hbn-spike branch was created at revi-
5688sion 45 (Subversion also told us this when we created the
5689branch, but we might have forgotten by the time we want to
5690merge). Now we can merge all the changes between revision
569145 and HEAD into our trunk working copy:
5692work > cd sesame
5693sesame > svn update
5694At revision 47.
5695sesame > svn merge -r 45:HEAD \
5696svn://olio/sesame/branches/TRY-MGM-hbn-spike
5697A common/HibernateHelper.java
5698A contacts/Contacts.hbm.xml
5699U contacts/Contacts.java
5700Now we resolve any conflicts produced during the merge, run
5701our unit tests to make sure everything works, and check in:
5702sesame > # .. run unit tests to make sure everything ' s ok .. #
5703sesame > svn commit -m "Merged TRY-MGM-hbn-spike to the trunk"
5704Adding common/HibernateHelper.java
5705Adding contacts/Contacts.hbm.xml
5706Sending contacts/Contacts.java
5707Transmitting file data .
5708Committed revision 48.
5709The techniques in this chapter map directly to a number of
5710SCM Patterns. Using a release branch corresponds to the
5711“release line†and “release-prep codeline†patterns. Experi-
5712mental developer branches correspond to the “task branchâ€
5713pattern. Branches usually have an associated “codeline pol-
5714icy†(even if the policy is fairly informal), helping developers
5715understand how they should handle the code on each branch.
5716Chapter 10
5717Creating a Project
5718The word project is fairly loosely defined. One person working
5719for a week to implement a web form can be a project, as can
5720many hundred laboring for many years. But most projects
5721share a set of common characteristics:
5722• Each project has a name. This may sound trivial, but we
5723tend to give things names when we want to identify them
5724as independent entities. Names don’t have to be external
5725brands, approved by marketing and subject to field tests
5726in major metropolitan areas. Project names are simply
5727internal to your organization.
5728• Each project is cohesive; the components of the project
5729work together to achieve some business aim.
5730• The components within a project tend to be maintained
5731as a unit; you’ll release a version of the project as a
5732whole.
5733• The stuff in a project shares a common set of engineering
5734standards and guidelines and uses a common architec-
5735ture.
5736It is important to consider this list when putting projects into
5737a version control system, as it’s often hard to know where to
5738draw the boundaries between different projects. Getting the
5739project structure wrong is a major source of frustration when
5740using version control and can lead to a lot of wasted effort
5741as time goes on. Subversion does make it straightforward
5742C REATING THE I NITIAL P ROJECT 129
5743to move things around once a project has started, but this
5744requires coordination with everyone using the repository.
5745Subversion organizes everything by directory, so projects will
5746correspond to directory locations inside your repository. Sub-
5747projects might correspond to subdirectories, and so on. This
5748scheme gives you the flexibility to dream up a directory struc-
5749ture that works for your projects, but it can also be a little
5750hard to know where to start.
5751So, before creating projects in your repository, spend some
5752time planning. For example, is your project going to imple-
5753ment a framework that the company will use in future devel-
5754opment efforts? If so, then perhaps that framework should be
5755a separate project in its own right, with your current project
5756and those other future projects sharing in its use. Is your
5757project developing multiple independent components? Per-
5758haps each should be its own project. Or is your project writ-
5759ing an extension for an existing chunk of code? Perhaps then
5760it should be a subproject of that original project.
576110.1 Creating the Initial Project
5762There are basically three ways to create directories (and thus
5763projects) within a Subversion repository:
5764• Import existing source into a directory in the repository.
5765• Manually create directories using svn mkdir until you have
5766the desired project structure.
5767• Convert an existing source code repository. There are
5768Subversion tools to convert CVS, RCS, Visual Source-
5769Safe, and Perforce repositories.
5770Converting from some other version control system is a big
5771topic and is covered in detail in Appendix B on page 174.
5772That leaves us with two options: import and manual directory
5773creation.
5774Importing Into Subversion
5775If you have existing source files (even if it’s just the project’s
5776README file), you can use the svn import command to pull those
5777C REATING THE I NITIAL P ROJECT 130
5778files into your repository. In the examples that follow, we’ll
5779assume you’re working on the Wibble project (the Wickedly
5780Integrated Business-to-Business Lease Exchange).
5781You’ll need a directory tree containing the files you want to
5782import (and only the files you want to import; be sure to clean
5783up all the various backup files and other dross before going
5784any further). Make sure you’re in the top-level directory of
5785this tree (in our case, in the directory wibble ), and then issue
5786an svn import command:
5787wibble > svn import -m "Wibble initial import" \
5788svn://olio/wibble/trunk
5789Adding wibble.build
5790Adding src
5791Adding src/Wibble.cs
5792Adding src/WibbleTest.cs
5793Adding README
5794Committed revision 49.
5795This tells Subversion to import the contents of the current
5796directory, storing it in the repository in /wibble/trunk . Subver-
5797sion automatically creates parent directories as needed dur-
5798ing an import, but you will probably also want the tags and
5799branches directories for your project:
5800wibble > svn mkdir -m "Create tags directory" \
5801svn://olio/wibble/tags
5802Committed revision 50.
5803wibble > svn mkdir -m "Create branches directory" \
5804svn://olio/wibble/branches
5805Committed revision 51.
5806Your project is now checked in. You should check it out using
5807svn checkout , and, if everything is okay, you can delete the
5808original directory tree you used for the import.
5809Manually Creating Directories
5810If you don’t already have files for your project, an easy way to
5811get started is to create a skeletal directory structure and then
5812flesh things out by adding files.
5813We can use the svn mkdir command to create directories in the
5814repository. For a Java project, you might want something like
5815Figure 10.1 on the following page. Helpfully, svn mkdir allows
5816you to create multiple directories with a single command.
5817S TRUCTURE WITHIN THE P ROJECT 131
5818Ã…
5819Æ
5820ÇÇ
5821È
5822É
5823Ê
5824Ë ÃŒ Ã
5825Ê
5826ÃŽ
5827Ã
5828ÃÑ Ã’
5829Ó
5830Ô
5831Ã
5832Ã
5833Ê
5834ÕÉ
5835Ñ
5836ËÌ
5837Ã
5838Ê
5839Figure 10.1: Wibble Project Layout
5840work > svn mkdir -m "Creating initial structure" \
5841svn://olio/wibble \
5842svn://olio/wibble/trunk \
5843svn://olio/wibble/trunk/src \
5844svn://olio/wibble/trunk/doc \
5845svn://olio/wibble/trunk/vendor
5846Committed revision 54.
5847The Wibble project is now ready to check out into a local work-
5848ing copy. You’ll be able to add source code, documentation,
5849and libraries in the same way you’d add files during regular
5850development, using the svn add command.
585110.2 Structure within the Project
5852Your company may well already have standards that dictate
5853how to organize the source code and directories within your
5854projects. If you’re developing with Java, for example, you
5855might be using the Jakarta conventions for laying out directo-
5856ries. 1 If you don’t currently use a standard, what follows are
5857some basic suggestions.
58581 http://jakarta.apache.org/site/dirlayout.html
5859S TRUCTURE WITHIN THE P ROJECT 132
5860Top-Level Files
5861These are the typical files you’ll find at the top-level of each
5862project:
5863README
5864Incredible though it seems, a couple of years from now
5865the latest red-hot project will have faded down to a dull
5866gray, and you’ll have a hard time remembering exactly
5867what the Wibble project was all about. So create a file
5868called README in the top-level project directory. Write
5869a small paragraph describing the project: the business
5870problems it is solving, the basic technologies used, and
5871so on. This isn’t meant to be a full description; it’s just
5872an aide-memoir intended to trigger those long-dormant
5873neurons when you come back after along absence.
5874BUILDING
5875Create another top-level file called BUILDING , containing
5876simple hints to future code archaeologists who have the
5877unenviable task of rebuilding this project from source.
5878Because you’ll be automating the build, this document
5879will be short; Figure 10.2 on the next page shows an
5880example.
5881GLOSSARY
5882Create one more top-level file called GLOSSARY . Make it a
5883habit to document all project-specific jargon in this file.
5884Not only will this make it easier for future developers
5885when they’re trying to work out what a “wibble channelâ€
5886is, but it will also guide the project team when it comes
5887to naming classes, methods, and variables.
5888Top-Level Directories
5889Most projects have at least the following top-level directories:
5890doc/
5891Check all project documentation into doc and its sub-
5892directories. Don’t forget to add memos and e-mails that
5893describe decisions reached. It’s normal to have directo-
5894ries under doc that contain different document types or
5895for different phases of the project.
5896S TRUCTURE WITHIN THE P ROJECT 133
5897Prerequisites:
5898* Oracle 9.6i (perhaps later versions but
5899that configuration ' s not tested)
5900* GCC 2.96
5901Building:
5902./configure [--with-oracle= < dir > ]
5903make
5904make test
5905make install
5906More info:
5907docs/building.html
5908Figure 10.2: Sample BUILDING file
5909If your project needs external documentation (for exam-
5910ple, the description of an algorithm or a third-party file
5911format), consider copying this and storing it under the
5912doc directory tree (copyright permitting, of course). This
5913will make it easier for future maintainers if the external
5914site has since gone away. If you can’t copy this material
5915into your project, create a file in doc called BIBLIOGRAPHY
5916and add links and a brief description in it.
5917data/
5918Many projects carry along data (for example, information
5919needed to populate lookup tables in the database). Keep
5920this data in a single location (if for no other reason that
5921someone, at sometime, will urgently need to find out why
5922we’re charging 127 percent sales tax in Guam).
5923db/
5924If your project uses a database, store all the schema-
5925related stuff here. Work hard not to fall into the habit of
5926modifying schemas online. Have your database admin-
5927istrator create SQL scripts for each update—scripts that
5928both update the schema and migrate the data. By keep-
5929ing these in the repository, you’ll be able to migrate any
5930version of the database to any other version.
5931src/
5932The project’s source code should be stored under this
5933directory. You might want subdirectories to separate
5934different types of source code, for example, src/java and
5935src/eiffel .
5936S TRUCTURE WITHIN THE P ROJECT 134
5937Ö
5938×
5939ØÙ Ú
5940Û
5941ÜÃÞßà Ã
5942áâ
5943ã
5944äß
5945ã
5946åæ
5947æä ç èè Þ Üé
5948Ø
5949Ö
5950ê
5951ë
5952Û
5953ì
5954ì
5955ì
5956Ã
5957×
5958î
5959Û
5960ï
5961Ø
5962ê
5963ë
5964ð
5965ì
5966ñò
5967ë
5968ðó î
5969Û
5970ì
5971ì
5972ì
5973ôõ
5974Ùðó
5975×
5976Û
5977ôõ
5978Ùð ó
5979×
5980Ã
5981×
5982î
5983Û
5984î
5985ë
5986ê
5987õ
5988Ù
5989Ö
5990Û
5991Þ
5992ì
5993ö
5994÷
5995ô
5996÷
5997á
5998ì
5999ö
6000÷
6001ô
6002÷
6003à õ
6004×
6005ôõ
6006×
6007Û
6008é
6009ì
6010ö
6011÷
6012ô
6013÷
6014ø
6015ì
6016ö
6017÷
6018ô
6019÷
6020ë
6021ê
6022ï
6023Û
6024ö
6025ØÙ
6026ê
6027Ö
6028ì
6029ö
6030÷
6031×
6032Ãù
6033×
6034ê
6035Ù ú
6036ì
6037ö
6038÷
6039×
6040ö
6041Ø Ù
6042ê
6043Ö
6044Û
6045ì
6046ì
6047Ã
6048óØ
6049×
6050î
6051õ
6052à ù
6053×
6054ê
6055Ùú
6056Û
6057ì
6058ì
6059Ã
6060ó Ø
6061×
6062î
6063õ
6064û
6065ê
6066ïï
6067ë
6068õ
6069Û
6070Ö
6071÷
6072ú
6073Ã
6074Û
6075ì
6076ì
6077ì
6078ï
6079×
6080÷
6081Ùî ü
6082õÃ
6083Û
6084ì
6085ì
6086ì
6087Figure 10.3: Wibble Project Layout
6088util/
6089A directory to hold various project-specific utility pro-
6090grams, tools, and scripts. Some teams have a directory
6091called tools instead.
6092vendor/
6093If your project uses third-party libraries or header files
6094that you want to archive along with your own code, do it
6095under a top-level vendor directory.
6096vendorsrc/
6097Sometimes a project will import and include code from
6098a third party (for example, if it is using an open-source
6099library and needs to ensure that it will have access to a
6100particular version of the source for the life of the appli-
6101cation). You’ll include the binary libraries (and possibly
6102the header files) in the vendor directory, but you’ll also
6103want to retain the source from which these libraries were
6104built. Store these sources under the vendorsrc directory.
6105We have more to say about vendor source code in Chap-
6106ter 11, Third-Party Code, on page 141.
6107A possible file layout for the Wibble project is shown in Fig-
6108ure 10.3 . In this project we have our own source code (divided
6109into client and server components) along with some imported
6110open-source code (the JUnit and Spring frameworks).
6111S HARING C ODE BETWEEN P ROJECTS 135
6112In addition, many projects will have a standard set of direc-
6113tories that are used during the build or release of the project.
6114These directories do not contain files that should be stored in
6115the repository (as their contents are generated on the fly), but
6116some teams still find it convenient to have these directories
6117appear in every developer’s workspace. To do this, you can
6118add these empty directories to the repository; they’ll appear
6119in the working copy when developers check out.
6120An equally valid alternative is not to store these directories in
6121Subversion. Instead, have your build scripts create them as
6122needed, and then tidy them up when you’re done with them.
6123If you use this scheme, you can add the directory names to
6124the svn:ignore property on your project’s top-level directory to
6125stop Subversion cluttering your screen with question marks.
6126You’ll also want to keep your test code somewhere, but opin-
6127ions vary wildly on where this should be. Some teams like
6128keeping it in parallel directories to their source tree; others
6129put the tests in subdirectories of the source files being tested.
6130To some extent the “correct†answer depends on the language
6131being used. For example, the Java package naming rules
6132mean that if you want to test protected methods you’ll need to
6133construct parallel trees (or put your tests in the same direc-
6134tory as the source being tested). We cover this in more detail
6135in the companion book Pragmatic Unit Testing [HT03], [HT04].
6136There are no hard-and-fast rules for structuring directories
6137in a project. However, being consistent across projects will
6138greatly help people who come along in future and will give you
6139the flexibility to move between projects without experiencing
6140that “I’m totally lost†feeling.
614110.3 Sharing Code between Projects
6142Projects rarely exist in a vacuum, instead being surrounded
6143by other work in an organization. Once a set of projects begins
6144to mature, you’ll often find that there are common areas of
6145functionality that could be reused across projects. In a large
6146enterprise it’s common to have teams specifically working on
6147reusable frameworks and libraries.
6148S HARING C ODE BETWEEN P ROJECTS 136
6149ý
6150þ ÿ ?
6151?
6152?
6153?
6154?
6155ý
6156?
6157? ??
6158?
6159???? ?
6160?
6161?
6162?
6163?
6164þ ?
6165???
6166?
6167?
6168??
6169?
6170?
6171?
6172?
6173???? ?
6174?
6175?
6176?
6177???
6178?
6179?
6180ý
6181?
6182?
6183?
6184?
6185?
6186?
6187?
6188?
6189þ
6190ý
6191þ þ
6192? ??
6193??
6194?
6195?
6196?
6197?
6198??
6199?
6200?
6201?
6202þ
6203?
6204ý
6205þ
6206?
6207!"#$%"
6208?
6209?
6210?
6211?
6212&
6213?
6214? ?
6215'
6216?
6217?
6218?
6219?
6220?
6221??
6222?
6223?
6224?
6225þ
6226ý
6227þ þ
6228? ??
6229??
6230?
6231?
6232þ
6233?
6234ý
6235þ
6236?
6237?
6238&
6239?
6240? ?
6241'
6242?
6243?
6244?
6245?
6246?
6247?
6248?
6249?
6250?
6251?
6252?
6253?
6254?
6255?
6256? ( )
6257?
6258?
6259?
6260?
6261?
6262?????
6263?
6264?
6265?
6266þ
6267ý
6268þ þ
6269? ??
6270??
6271?
6272?
6273þ
6274?
6275ý
6276þ
6277?
6278?
6279&
6280?
6281??
6282'
6283?
6284?
6285?
6286?
6287?
6288?
6289?
6290?
6291?
6292?
6293?
6294Figure 10.4: Repository Layout with an
6295¨
6296Uber-project
6297The Subversion “everything is a directory†approach means
6298that your common code will need to live in a shared directory
6299in the repository. There are two main ways to accomplish this:
6300• Store all your projects in a single “über-project†and use
6301a build script to manage dependencies between projects.
6302• Use svn:externals to pull the dependencies for each project
6303into your working copy before you build.
6304Both approaches can work, but using svn:externals is more flex-
6305ible with respect to project organization and branching.
6306Code Sharing with an
6307¨
6308Uber-project
6309The repository directory structure when using an über-project
6310is shown in Figure 10.4 .
6311Directly beneath the trunk/ directory are directories for each of
6312the shared projects, in this case common and dataaccess . The
6313directories maitai and wibble store the actual project code for
6314the MaiTai and Wibble projects.
6315S HARING C ODE BETWEEN P ROJECTS 137
6316A developer would check out this über-project into a single
6317working copy containing all the projects. What to call this
6318working copy requires creativity and inspiration, neither of
6319which comes cheap, so we’ll go with uber-project :
6320work > svn checkout svn://olio/trunk/ uber-project
6321A uber-project/wibble
6322A uber-project/wibble/doc
6323A uber-project/wibble/doc/UserRequirements.doc
6324A uber-project/wibble/src
6325A uber-project/wibble/src/WibbleTest.java
6326: : :
6327A uber-project/dataaccess/lib/neo-1.3.0.dll
6328A uber-project/dataaccess/src
6329A uber-project/dataaccess/src/DataMapper.cs
6330A uber-project/dataaccess/README
6331Checked out revision 17.
6332When a developer comes to build the MaiTai project, they’d
6333(quite rightly) expect the build script to first build the projects
6334on which MaiTai depends. In this case it might first build the
6335data access project. Once all the dependencies are built—and
6336assuming the data access project produces a library as part
6337of its build—the MaiTai project can use that library and build
6338happily.
6339This strategy has a couple of drawbacks. First, developers
6340have to check out all the code for all the projects in your
6341repository. This might not be desirable if you have a large
6342repository or if some of the source is sensitive and requires
6343stricter access controls. Second, the branching options are
6344limited—you pretty much have to branch all the code at once,
6345rather than on a project-by-project basis.
6346Code Sharing with Externals
6347A special Subversion directory property, svn:externals , lets you
6348include the contents of another repository in your working
6349copy. Subversion properties and how to manipulate them are
6350covered more fully in Section 6.4, Properties, on page 66.
6351The svn:externals property is set on a directory and specifies
6352a list of repository URLs to include when checking out. You
6353can use any Subversion repository you like in an externals
6354definition—the client will do the work of checking out for you.
6355This means that it is possible to include code from Subversion
6356repositories that aren’t under your direct control, for example,
6357open-source projects hosted on the Internet.
6358S HARING C ODE BETWEEN P ROJECTS 138
6359*+
6360,
6361++ - - .//
63620
6363,
63641
63652 34
63665
63676 78
63685
63699
6370+
6371:
6372,
6373+
6374:
63750
6376,
63771
637823 4
63795
63801
6381.;</
6382:
6383,
6384<
63851
6386=
63870
6388>
6389?
63908
63915
6392@
6393A
6394B
63955
63966 78
63975
6398>
6399?
64008
64015
6402CD E
640367
6404?
64055
64066F
6407G
6408FF88
6409D>>
64105
6411HIJ
6412K
6413LM
6414N
6415L
6416O
6417JP
6418Q
6419C DE
642067
6421?
64225
6423678
64245
6425>
6426?
64278
64285
6429@
6430A
6431B
64325
6433C DE
643467
6435?
64365
6437Figure 10.5: Repository Layout Using Externals
6438Figure 10.5 and Figure 10.6 on the next page show views
6439of a repository that uses externals to link shared code into
6440particular projects. There’s a lot going on here, so we’ll cover
6441it piece by piece.
6442Let’s look at the MaiTai project first. It is stored in /maitai/trunk
6443(shown in Figure 10.5 ). This has a dependency on the data
6444access project, in particular on /dataaccess/trunk . The file-
6445names in boxes show where these files are imported to the
6446MaiTai tree using externals. In order to set up the depen-
6447dency, we check out a working copy of the MaiTai project and
6448set the svn:externals property:
6449work > svn checkout svn://olio/maitai/trunk maitai
6450A maitai/lib
6451A maitai/src
6452Checked out revision 19.
6453work > svn propset svn:externals \
6454"dataaccess svn://olio/dataaccess/trunk" \
6455maitai
6456property ' svn:externals ' set on ' maitai '
6457Here we’ve set the svn:externals property to include just a single
6458external. You can use svn propedit to bring up an editor if you
6459have multiple dependencies, which should each be listed on a
6460different line.
6461S HARING C ODE BETWEEN P ROJECTS 139
6462RST T S U
6463V
6464W
6465X
6466Y
6467UZ
6468[
6469\]^
6470[
6471_
6472`
6473a a
6474b
6475c
6476V
6477W
6478X
6479Y
6480UZ
6481[
6482W
6483de f
6484V
6485g
6486h
6487i
6488[
6489X
6490cjS
6491f
6492`
6493W
6494S
6495X
6496k
6497V
6498l
6499m
6500^
6501[
6502W
6503de f
6504[
6505g
6506h
6507i
6508[
6509\]^
6510[
6511l
6512m
6513^
6514[
6515\ ] ^
6516[
6517l
6518m
6519^
6520[
6521n op
6522\ ]
6523m
6524[
6525^ ]q q]
6526p
6527[
6528\]^
6529[
6530l
6531m
6532^
6533[
6534\] ^
6535[
6536l
6537m
6538^
6539[
6540nop
6541\ ]
6542m
6543[
6544^]q q ]
6545p
6546[
6547\]^
6548[
6549l
6550m
6551^
6552[
6553rs t
6554u
6555vw
6556x
6557v
6558y
6559t z
6560{
6561r st
6562u
6563v w
6564x
6565v
6566y
6567tz
6568{
6569Figure 10.6: Repository Layout Using Externals
6570The externals definition has two parts: first we name the
6571directory inside the MaiTai project where Subversion should
6572include /dataaccess/trunk , and then we provide the repository
6573URL we’d like to include. Performing an update on the work-
6574ing copy will cause the Subversion client to pull in the data
6575access project:
6576work > cd maitai
6577maitai > svn update
6578Fetching external item into ' dataaccess '
6579A dataaccess/lib
6580A dataaccess/src
6581Updated external to revision 19.
6582Updated to revision 19.
6583We still need to commit the property change on the maitai
6584directory to let other developers see this new external item.
6585maitai > svn commit -m "Added dataaccess project as an external"
6586Sending .
6587Committed revision 20.
6588S HARING C ODE BETWEEN P ROJECTS 140
6589Externals provide much more flexibility when working with
6590branches. Figure 10.6 on the page before shows that the Wib-
6591ble project depends on common . Furthermore, the trunk of
6592Wibble depends on the trunk of common , but the 1.0 branch
6593of Wibble depends on the 1.0 branch of common . We can
6594do this by changing the svn:externals definition for the Wibble
6595project after we branch it. Externals also allow you to be very
6596precise about the dependencies each project has—developers
6597don’t have to check out every piece of code in the repository
6598in order to start working.
6599An important point to note is that Subversion will not auto-
6600matically commit changes you make to a checked-out external
6601when you commit changes to the project that included it. You
6602need to explicitly commit changes to each external by chang-
6603ing to the directory in which it’s included and running svn
6604commit , or by naming each of the externals directories during
6605a commit.
6606We recommend treating dependencies as “read-only†in each
6607project—if a developer working on MaiTai needs to fix a bug in
6608the data access project, he should check out /dataacess/trunk ,
6609fix the bug, check in, and then do an update in his MaiTai
6610working copy to get the fix.
6611Chapter 11
6612Third-Party Code
6613All projects rely to some extent on external libraries: Java
6614programs use rt.jar , .NET programs use mscorlib.dll , and so on.
6615Should these libraries form part of your working copy when
6616you check out from the repository?
6617To answer that question, ask yourself another. You need to
6618be able to rebuild a working program at some arbitrary time
6619in the future. Will you be able to use the versions of these
6620libraries that will be available then?
662111.1 Binary Libraries
6622If you feel comfortable that the libraries used by your code will
6623be available (and compatible) over the life of your application,
6624then there’s no need to do anything special with them; just
6625use them as installed on your machine.
6626Looking beyond standard language facilities, many projects
6627include other, less stable libraries in their projects. For exam-
6628ple, many .NET developers will use the NUnit 1 framework to
6629test their code. Compared to the standard libraries, these
6630frameworks are fairly volatile (as of May 2006, NUnit is up
6631to version 2.2.8). Although the changes between versions are
6632mostly compatible, changes can affect your application. As
6633a result, we recommend you include these libraries in your
6634project’s repositories.
66351 http://www.nunit.org/
6636B INARY L IBRARIES 142
6637Having made the decision you want to include a third-party
6638library in your workspace and repository, you now have to
6639decide what to include and where to put it.
6640The first decision is what files to include. This is relatively
6641easy. If you use the library in the form distributed by the
6642maker, and you feel confident that the library will continue
6643to work unmodified through the life of the application, then
6644storing the binary form of the library is all that is needed. We
6645suggest putting all these libraries in subdirectories of a top-
6646level vendor/ directory inside your project.
6647If the library is architecture independent (for example, a Java
6648. jar file), then it can simply sit in a subdirectory called lib . If
6649the file as packaged by the vendor has a version number in the
6650name, such as junit-3.8.1.jar , we suggest giving it a more generic
6651name. In this case, you’d add junit.jar to your repository. This
6652makes upgrading easy—just copy over a new version of the
6653library and check in. You won’t need to change your build
6654scripts or include files. In any case, you should state the
6655version number of the library in your commit message so later
6656you can figure out what version you’re using.
6657If instead you have libraries that depend on the target archi-
6658tecture (assuming your application is targeted at more than
6659one architecture), you’ll need to have subdirectories below
6660vendor for each architecture and operating system combina-
6661tion. A common naming scheme for these subdirectories is to
6662use arch - os where arch is the target architecture ( i586 for an
6663Intel Pentium, ppc for a PowerPC, and so on) and os is the
6664operating system ( linux , win2k , osx , and so on).
6665Languages such as C and C++ require that you include source
6666header files in application code that uses a particular library.
6667These header files are supplied with the library and should
6668also be stored in the repository. We suggest storing them in
6669an include subdirectory beneath vendor . Structure the direc-
6670tories beneath vendor/include in such a way that the compilers
6671can find the libraries’ include files naturally. As an example,
6672consider a C library called datetime, which performs date and
6673timecalculations. It comes with a binary library archive, lib-
6674datetime.a , and two header files, datetime.h and extras.h . The
6675datetime.h header library is intended to be installed at the top
6676B INARY L IBRARIES 143
6677|
6678} ~
6679
6680€Â€
6681
6682}
6683‚
6684~
6685ƒ
6686}
6687„
6688€
6689|
6690†
6691‡
6692ˆ
6693‰
6694Š
6695‹ŒÂÂŽ
6696ˆ
6697‡
6698Â
6699Â
6700‘
6701Â’
6702Â
6703‘
6704“”
6705Â
6706• – —
6707Â
6708– ˜
6709™
6710—
6711™
6712‘
6713š—
6714›
6715œ
6716–
6717™
6718Â
6719—Â
6720™
6721ž
6722˜Ÿ
6723›
6724œ
6725Â
6726‘
6727’– ˜
6728™
6729—
6730™
6731‘
6732š—
6733›
6734˜
6735Figure 11.1: Sample Repository with Third-Party Library
6736level of the include hierarchy, extras.h is expected to be in a
6737subdirectory called dt . That is, a program that used both
6738header files would normally start like this:
6739#include < datetime >
6740#include < dt/extras >
6741// . . .
6742In this case, we’d organize our repository (and our working
6743copy) as shown in Figure 11.1 .
6744Integrating with the Build Environment
6745If you include vendor libraries or header files in your repos-
6746itory, you’ll need to make sure your compilers, linkers, and
6747IDEs can get to them. There’s a minor problem: you need
6748to make sure you don’t check anything into the repository
6749that contains absolute path names (as this might not work on
6750some other developer’s machine). Instead, you have a couple
6751of options:
6752• Arrange your build tools so that all path names are rela-
6753tive to (say) the top-level project directory. This is work-
6754able if you’re using an external build tool such as make
6755or ant , but it can get tricky.
6756• Set up some external environment variable to point to
6757the top of the project tree, and make all references in the
6758L IBRARIES WITH S OURCE C ODE 144
6759build relative to this variable. This allows each developer
6760to have different values in the external variable but then
6761to share a common build environment layout.
6762The external variable need not be a true operating sys-
6763tem environment variable. The Eclipse IDE, for example,
6764allows each user to set internal variables and then to
6765have a common shared build structure that references
6766these variables. This means all developers can share a
6767common Eclipse build definition but that developers can
6768still install the source in different locations.
6769We recommend the second approach.
677011.2 Libraries with Source Code
6771Sometimes a library comes with source code (or is distributed
6772only as source code). If you have both source and binary
6773versions of the library available, which should you store in the
6774repository, and how should you set up your working copy?
6775The answer is an exercise in risk management. Having the
6776source available means you are always in the position (tech-
6777nically, at least) to fix bugs and add features, something you
6778can’t do with a binary library. This is clearly a good thing. At
6779the same time, including the source code for all the libraries
6780used by your project can slow down builds and complicate
6781the structure of your project. It also gives future maintainers
6782a headache. If there’s a bug, do they need to consider poten-
6783tial changes to the library source, or can they concentrate on
6784the code written by your organization?
6785Our recommendation is to add vendor source to your reposi-
6786tory, but to treat it specially. To do this you have to do a bit
6787of role playing.
6788Imagine for a minute that you are the writer of this particular
6789library and that every now and then you release an updated
6790version of the code to your user base. Being a high-quality
6791library writer, you naturally put all your source in a version
6792control system and practice all the necessary release control
6793procedures.
6794L IBRARIES WITH S OURCE C ODE 145
6795Now come back from the role play (remember, breathe in,
6796breathe out, breathe in, breathe out). In an ideal world, we
6797should be able to hook straight into our vendor’s repository
6798and extract releases directly from there. But we can’t, so we
6799have to do the work ourselves. Whenever we receive code,
6800bug fixes, and new releases from a vendor, we have to pre-
6801tend that we generated the code and handle it in our version
6802control system as if we were the vendor handling it in theirs.
6803Importing Vendor Source for the First Time
6804When we first receive the source code for a third-party library,
6805we need to import it into our repository. Vendor code is stored
6806on a vendor branch, and each time we receive code and import vendor branch
6807it it’s called a vendor drop. We recommend keeping vendor
6808vendor drop
6809branches separate from the code of your project. If you antici-
6810pate importing code from multiple sources over time, it proba-
6811bly makes sense to keep it all under a common top-level direc-
6812tory; we suggest calling it /vendorsrc .
6813Each library or product you want to track will live in its own
6814vendor branch beneath /vendorsrc , such as /vendorsrc/sun/jdbc .
6815Within the vendor branch directory we’ll have a current direc-
6816tory storing the most recent vendor drop (kind of like the trunk
6817directory for a regular project). Alongside this we’ll have direc-
6818tories containing tags for each vendor drop.
6819To make this more concrete, let’s assume we’ve decided to
6820use version 1.0.0 of the jMock 2 mock objects library (after
6821checking the license terms, of course).
6822Start by downloading the latest release from the jMock web
6823site. Save jmock-1.0.0-src.jar to a temporary directory, and then
6824use WinZip (or plain old jar ) to extract the contents. This
6825should leave you with a folder called jmock-1.0.0 containing all
6826the jMock source code, documentation, and examples.
6827Now we can import the drop into the repository. We’ll store
6828it under /vendorsrc/codehaus/jmock/current . In this case, the
6829vendor is CodeHaus, and the “product†is jMock. Run svn
6830import from the directory above jmock-1.0.0 :
68312 http://jmock.codehaus.org/
6832L IBRARIES WITH S OURCE C ODE 146
6833tmp > svn import --no-auto-props -m "Import jMock 1.0.0" \
6834jmock-1.0.0 \
6835svn://olio/vendorsrc/codehaus/jmock/current
6836Adding jmock-1.0.0/extensions
6837Adding jmock-1.0.0/extensions/cglib
6838Adding jmock-1.0.0/extensions/cglib/acceptance-tests
6839Adding jmock-1.0.0/extensions/cglib/acceptance-tests/atest
6840Adding jmock-1.0.0/extensions/cglib/acceptance-tests/atest/jmock
6841: : : :
6842Adding (bin) jmock-1.0.0/examples/classes/.../Calculator.class
6843Adding (bin) jmock-1.0.0/examples/classes/.../ParseException.class
6844Adding (bin) jmock-1.0.0/examples/classes/.../InfixParser.class
6845Committed revision 3.
6846Next, tag the vendor drop, marking it as version 1.0.0. If
6847CodeHaus releases a new version of jMock, you’ll be able track
6848the two versions effectively:
6849tmp > svn copy -m "Tag 1.0.0 vendor drop" \
6850svn://olio/vendorsrc/codehaus/jmock/current \
6851svn://olio/vendorsrc/codehaus/jmock/1.0.0
6852Committed revision 4.
6853Updating to a New Vendor Release
6854When jMock 1.0.1 comes along, we’d like to be able to incor-
6855porate it into our repository. To do this, think back to our
6856role play—we are pretending to be CodeHaus, maintaining our
6857code in /vendorsrc/codehaus/jmock/current . When we released
68581.0.0, we tagged the code by copying it to jmock/1.0.0 . We con-
6859tinue to develop our code, working on our “trunk.†Once we
6860reach our next release, we make another tag to mark 1.0.1.
6861Outside of the role play, we don’t actually get to see any of
6862the changes that are made to the jMock code. We see only
6863the result, jmock-1.0.1-src.jar . In order to emulate what’s going
6864on in the jMock repository, we need to update the contents of
6865our directory /vendorsrc/codehaus/jmock/current so that it looks
6866like the new release. We update our copy of the jMock code so
6867that it looks like we did all the work to get us to 1.0.1.
6868How do we get our copy to look like the new release? Well,
6869since the last release CodeHaus will have modified some files,
6870added some new files, maybe moved a few files around, and
6871occasionally deleted files. We need to perform all these opera-
6872tions in current .
6873L IBRARIES WITH S OURCE C ODE 147
6874Whilst this synchronization could be done by hand, it’s all
6875pretty labor intensive and prone to mistakes. Fortunately,
6876Subversion has a utility to import new vendor drops automat-
6877ically, performing the adds and deletes for you. The magic is
6878provided by a Perl script called svn load dirs.pl . 3
6879The script requires Perl to be installed on your system, along
6880with a few modules (such as the URI module for manipulating
6881URLs). When run, it requires three arguments:
6882Base URL
6883The base URL of the Subversion repository to work with.
6884It expects to find all the drops for a particular product
6885beneath this directory. In our example so far, this would
6886be svn://olio/vendorsrc/codehaus/jmock .
6887“Current†Directory
6888The directory beneath the base URL in which the latest
6889vendor drop can be found. We’re using current in this
6890example.
6891Directory to Import
6892The directory on the local machine from which to import
6893the new vendor drop.
6894You can also specify a -t tagname option to automatically
6895tag the new vendor drop.
6896Download the new release of jMock, storing it in jmock-1.0.1 in
6897your temporary directory. Now run svn load dirs.pl to load the
6898new release and tag it:
6899tmp > svn load dirs.pl -t 1.0.1 \
6900svn://olio/vendorsrc/codehaus/jmock current jmock-1.0.1
6901Directory jmock-1.0.1 will be tagged as 1.0.1
6902Please examine identified tags. Are they acceptable? (Y/n) y
6903We’re being asked if tagging the new source from jmock-1.0.1
6904as “1.0.1†is okay. That’s what we want to do, so type y and
6905hit Enter. The rest of the process is hands free:
6906Checking that the base URL is a Subversion repository.
6907Running /usr/local/bin/svn log -r HEAD svn://olio/vendorsrc/codehaus/jmock
6908Finding the root URL of the Subversion repository.
6909Running /usr/local/bin/svn log -r HEAD svn://olio
6910Determined that the svn root URL is svn://olio.
69113 http://svn.collab.net/repos/svn/trunk/contrib/client-side
6912L IBRARIES WITH S OURCE C ODE 148
6913Native EOL on this system is \ 012.
6914Finding if any directories need to be created in repository.
6915Running /usr/local/bin/svn log -r HEAD svn://olio/.../jmock/current
6916No directories need to be created to prepare repository.
6917Checking out svn://olio/.../jmock/current into /tmp/...
6918Running /usr/local/bin/svn checkout svn://olio/.../jmock/current my import wc
6919Loading jmock-1.0.1 and will save in tag 1.0.1.
6920U build.properties
6921U VERSION
6922U CHANGELOG
6923U core/src/test/jmock/core/InvocationTest.java
6924U core/src/test/jmock/core/testsupport/MockInvocationMatcher.java
6925U core/src/test/jmock/core/matcher/InvokedRecorderTest.java
6926U core/src/org/jmock/core/matcher/InvokeAtLeastOnceMatcher.java
6927: : :
6928Running /usr/local/bin/svn propget svn:eol-style VERSION
6929Running /usr/local/bin/svn propget svn:eol-style CHANGELOG
6930: : :
6931Running /usr/local/bin/svn commit --file /tmp/svn load ...
6932Running /usr/local/bin/svn update
6933: : :
6934Cleaning up /tmp/svn load dirs ZH6k9TLxFM
6935Examining the Subversion log, we can see that the changes
6936between jMock 1.0.0 and 1.0.1 have been applied to our copy
6937of the code:
6938tmp > svn log -v svn://olio/vendorsrc/codehaus/jmock/current
6939---------------------------------------------------------
6940r5 | mike | 2004-11-18 17:03:06 -0700 (Thu, 18 Nov 2004)
6941Changed paths:
6942M /vendorsrc/codehaus/jmock/current/CHANGELOG
6943M /vendorsrc/codehaus/jmock/current/VERSION
6944M /vendorsrc/codehaus/jmock/current/build.properties
6945: : :
6946Load jmock-1.0.1 into vendorsrc/codehaus/jmock/current.
6947----------------------------------------------------------
6948We can follow the same process to import new releases of
6949jMock, as they become available.
6950Using Vendor Code in a Project
6951All this fancy importing is great so far—you’ve got your own
6952copy of the jMock source code and have tagged it for posterity.
6953Now we need to actually use that source in a project. To do
6954this, copy the vendor branch into your project, storing it in
6955vendor/jmock :
6956work > svn mkdir -m "" svn://olio/maitai/trunk/vendor
6957work > svn copy -m "MaiTai needs jMock" \
6958svn://olio/vendorsrc/codehaus/jmock/1.0.0 \
6959svn://olio/maitai/trunk/vendor/jmock
6960Committed revision 12.
6961When we check out MaiTai, we’ll get a copy of the jMock code:
6962L IBRARIES WITH S OURCE C ODE 149
6963work > svn checkout svn://olio/maitai/trunk maitai
6964A maitai/doc
6965A maitai/src
6966A maitai/vendor
6967A maitai/vendor/jmock
6968A maitai/vendor/jmock/extensions
6969: : : :
6970A maitai/vendor/jmock/build.xml
6971Checked out revision 12.
6972Modifying Vendor Code
6973Now that you have the vendor’s source code, you’re free to
6974make modifications to it, safe in the knowledge that you’ll be
6975able to easily incorporate new releases whilst preserving your
6976custom changes.
6977Let’s say we want to make some tweaks to jMock’s excep-
6978tion handling and expectation framework. Make your changes
6979within the MaiTai working copy, and commit them as normal:
6980maitai > svn status
6981M vendor/jmock/core/src/org/jmock/expectation/ExpectationList.java
6982M vendor/jmock/core/src/org/jmock/util/NotImplementedException.java
6983maitai > svn commit -m "Made some custom changes to jMock"
6984Sending vendor/jmock/core/src/org/jmock/expectation/ExpectationList.java
6985Sending vendor/jmock/core/src/org/jmock/util/NotImplementedException.java
6986Transmitting file data ..
6987Committed revision 13.
6988Subversion tracks the change you’ve made just like regular
6989changes to code you authored yourself.
6990Updating Modified Code
6991Life is good. The MaiTai project is doing well and is a suc-
6992cess for your company. The guys at CodeHaus release a new
6993version of jMock, and you’d like to incorporate that into the
6994MaiTai project. After loading and tagging the new vendor
6995drop, you’re ready to upgrade MaiTai.
6996We need to merge the changes made to jMock between 1.0.0
6997and 1.0.1. To do this, use the svn merge command:
6998maitai > svn merge svn://olio/vendorsrc/codehaus/jmock/1.0.0 \
6999svn://olio/vendorsrc/codehaus/jmock/1.0.1 \
7000vendor/jmock
7001U vendor/jmock/VERSION
7002U vendor/jmock/CHANGELOG
7003: : :
7004U vendor/jmock/build.properties
7005K EYWORD E XPANSION DURING I MPORTS 150
7006Subversion applies the changes to your working copy. If any
7007conflicts arise between your custom modifications and the
70081.0.1 changes, you’ll need to fix them as you would a conflict
7009between two developers. Once any conflicts are resolved, and
7010you’ve run the tests to make sure everything’s still working,
7011commit the changes to the repository:
7012maitai > svn commit -m "Updated MaiTai with jMock 1.0.1"
7013Sending vendor/jmock/CHANGELOG
7014Sending vendor/jmock/VERSION
7015Sending vendor/jmock/build.properties
7016: : :
7017Transmitting file data ......................
7018Committed revision 14.
701911.3 Keyword Expansion during Imports
7020In these examples, we’re importing third-party code (probably
7021from a version control system other than Subversion) into our
7022repository. If we’re importing code from CVS, for example,
7023the authors may have included $ Author $ or $ Id $ keywords.
7024We discussed keywords more fully in Section 6.4, Keyword
7025Expansion, on page 68.
7026The problem is that the keywords are expanded every time
7027the file is checked out. If the vendor has used these tags,
7028then the source you receive will have the vendor’s informa-
7029tion in these fields. However, if you just import these files as
7030they stand and check them back out, Subversion will update
7031the tags, and suddenly your name will appear in the author
7032field. While this may be vaguely satisfying, it will cause prob-
7033lems later when you come to merge in changes with the next
7034vendor release. Subversion will notice that these tag lines
7035have changed, and you’ll get conflicts when merging with the
7036vendor’s code.
7037Fortunately, keyword expansion isn’t switched on for new files
7038by default. However, if you’ve enabled autoprops as described
7039in Section 6.4, Automatic Property Setting, on page 74, and
7040are setting svn:keywords automatically, keyword expansion
7041might occur. Use the --no-auto-props switch when import-
7042ing to disable any potential keyword expansion.
7043The SCM Pattern for handling third party code using branches
7044is, unsuprisingly, named “third party codeline.â€
7045Appendix A
7046Install, Network, Secure, and
7047Administer Subversion
7048Subversion client installation is pretty straightforward, often
7049just requiring the right download for your operating system.
7050Running a server is a little more complicated, and many peo-
7051ple, especially those migrating from CVS, will want to run a
7052Subversion server on a Unix platform. Subversion’s database
7053backend also requires a different backup strategy than a plain
7054file-based version control system. This chapter includes Win-
7055dows and Linux instructions for installing Subversion, getting
7056your repository on the network, and backing it up in case the
7057worst should happen. There’s also a discussion on securing
7058your repository so prying eyes can’t get at your data.
7059A.1 Installing Subversion
7060Subversion comes packaged for a variety of operating sys-
7061tems. 1 If you’re using a Unix-based system, Subversion might
7062be available as an official package, so check first using your
7063package manager.
7064Windows Installation
7065The friendly Windows installer makes short work of installing
7066Subversion, even putting the binaries in your path. If you’re
70671 Go to
7068http://subversion.tigris.org/project_packages.html for
7069the full set of packages.
7070I NSTALLING S UBVERSION 152
7071planning on installing Apache as well, install it before Sub-
7072version. That way, the Subversion installer will automatically
7073copy Subversion’s Apache modules to the right places.
7074Linux Installation
7075Here we’ll cover installation on Fedora Core 5, which happens
7076to include Subversion 1.3 as a standard package. You can
7077either use the Fedora Package Manager to install the packages
7078or download them by hand.
7079To use the GUI package manager, choose Applications > Add/
7080Remove Software. In the “Servers†category, make sure “Web
7081Server†is selected. Under “Development,†check “Develop-
7082ment Tools†then click the Optional Packages button to make
7083sure Subversion is selected. Hit the Update button to apply
7084the changes.
7085To install from the command line, use the yum package man-
7086ager:
7087root > yum install httpd subversion mod dav svn
7088Dependencies Resolved
7089=================================================================
7090Package Arch Version Repository Size
7091=================================================================
7092Installing:
7093httpd i386 2.2.0-5.1.2 core 1.1 M
7094mod dav svn i386 1.3.0-4.2 core 65 k
7095subversion i386 1.3.0-4.2 core 2.1 M
7096Transaction Summary
7097=================================================================
7098Install 3 Package(s)
7099Update 0 Package(s)
7100Remove 0 Package(s)
7101Total download size: 3.3 M
7102Is this ok [y/N]:
7103yum lets you know it’s going to install the requested packages,
7104along with apr and apr-util which are required for Subver-
7105sion to work. After downloading the packages you should see
7106something like this:
7107Running Transaction
7108Installing: httpd ######################### [1/3]
7109Installing: subversion ######################### [2/3]
7110Installing: mod dav svn ######################### [3/3]
7111Installed: httpd.i386 0:2.2.0-5.1.2 mod dav svn.i386
71120:1.3.0-4.2 subversion.i386 0:1.3.0-4.2
7113Complete!
7114Subversion is now installed and ready to go.
7115N ETWORKING WITH SVNSERVE 153
7116A.2 Networking with svnserve
7117svnserve is a simple network server for Subversion. It’s fast
7118and lightweight, and it’s suitable for use on a corporate LAN
7119where traffic is safe from eavesdroppers.
7120svnserve on Windows
7121To start svnserve on Windows, go to your command prompt
7122and type
7123C: \> start svnserve --daemon --root c: \ svn-repos
7124A new window will pop open with the title svnserve.exe . If
7125you’re using Windows XP or have other firewalling software
7126installed, you may be asked whether the server should be
7127allowed to accept network connections, in which case choose
7128to unblock svnserve . We’ve asked svnserve to start in daemon
7129mode with the --daemon option (Windows doesn’t actually run
7130it as a daemon; this option is a quirk needed to get svnserve to
7131start), and we’re allowing access to the repository named with
7132the --root argument.
7133Popping open a new window isn’t great, since you might close
7134it accidentally. You can add a /B just after the start command
7135if you want svnserve to run without its own window, but in this
7136case you’ll need to use Task Manager to kill it off when you’re
7137done.
7138If you’d like svnserve to run whenever your Windows server
7139boots, you’ll need to install it as a service. Magnus Norddahl
7140maintains a simple service wrapper called svnservice , available
7141from http://dark.clansoft.dk/Ëœmbn/svnservice/ .
7142svnserve on Unix
7143Starting svnserve is very similar on Unix:
7144home > svnserve --daemon --root /home/mike/svn-repos
7145Your command prompt returns immediately leaving svnserve
7146running as a daemon. Running ps should show the process
7147still running.
7148Try accessing the repository from a different machine on your
7149network. The example server for this book is called olio , so
7150you’d run
7151N ETWORKING WITH SVN + SSH 154
7152work > svn co svn://olio/sesame/trunk vizier
7153A vizier/Number.txt
7154A vizier/Day.txt
7155Checked out revision 7.
7156If this doesn’t work, you might need to check if there’s a
7157firewall between the two machines. If there is (for example,
7158ZoneAlarm, Windows XP’s built-in firewall, or a Unix firewall),
7159you’ll need to make sure the machine running svnserve can
7160accept connections on TCP port 3690.
7161Once set up, you should secure your repository, because by
7162default svnserve allows read-only anonymous access to every-
7163thing. Refer to Section A.5, svnserve, on page 163 for more
7164details.
7165A.3 Networking with svn+ssh
7166Windows doesn’t usually support incoming SSH connections,
7167so this section covers Unix configuration only. You might be
7168able to get Putty working as a Windows SSH server, but it’s
7169definitely not for the faint of heart!
7170When a user specifies a svn+ssh scheme to access the repos-
7171itory, the Subversion client runs SSH to connect to the server.
7172This means each user needs an account on the server, and the
7173password they’re asked for is their Unix account password.
7174If your users have public/private key pairs or are running
7175an SSH agent, Subversion automatically takes advantage of
7176those features.
7177Subversion tries to run svnserve -t on the server in order to
7178access the repository. If Subversion complains it can’t find
7179svnserve , make sure the default path on the server contains the
7180svnserve binary. Because Subversion starts svnserve using
7181the -t (tunnel) option, you don’t need to have it running as a
7182daemon like you do with plain svn connections.
7183Once the SSH connection is established and svnserve is run-
7184ning in tunnel mode, Subversion will attempt to access the
7185repository’s files. It does this as the same user who authen-
7186ticated via SSH, which means all the users of your repository
7187need read and write access to the repository files. Further-
7188N ETWORKING WITH SVN + SSH 155
7189more, any new files that are created need to be readable and
7190writable for all the other users. 2
7191In order for multiple Unix users to access the repository, they
7192should all be in a single Unix group and have a umask of 002
7193when running svnserve via SSH. You also need to set the group
7194“sticky bit†on the repository directories. Here’s a step-by-step
7195guide to setting this up.
7196First create a Unix group for everyone using Subversion, and
7197add each user to the group. These commands are Linux spe-
7198cific, so you might need to tweak them a bit for your flavor of
7199Unix:
7200root > /usr/sbin/groupadd subversion
7201root > /usr/sbin/usermod -G subversion mike
7202root > /usr/sbin/usermod -G subversion ian
7203Next, change the ownership of your repository directory and
7204files to the new group, and set the group sticky bit for the
7205repository db directory:
7206root > chgrp -R subversion /home/svn-repos
7207root > chmod -R 770 /home/svn-repos
7208root > chmod g+S /home/svn-repos/db # g+t on BSD systems
7209Now try checking out from the repository. Here we’ll specify
7210an exact username for the remote machine, and the password
7211we’re asked for is our Unix password:
7212work > svn checkout \
7213svn+ssh://mike@olio/home/svn-repos/sesame/trunk \
7214sesame
7215mike@olio ' s password:
7216A sesame/Number.txt
7217A sesame/Day.txt
7218Checked out revision 7.
7219This is all a bit complicated, but well worth it if you’d like to
7220take advantage of SSH for securing your connections. More
7221information is available online. 3
72222 Getting this part wrong is the most common cause for “wedged†reposito-
7223ries. During the commit BDB might decide to create new files that are part of
7224the repository. If these aren’t writable by other users their Subversion clients
7225will hang trying to access the repository.
72263 http://svnbook.red-bean.com/en/1.1/ch06s03.html#
7227svn-ch-6-sect-3.4
7228N ETWORKING WITH SVN + SSH 156
7229Troubleshooting an SSH Connection
7230Connecting to a repository using svn+ssh requires quite a few
7231programs to be working and configured correctly. Unfortu-
7232nately, Subversion’s error messages are sometimes less infor-
7233mative than they could be. Here’s a rough guide to things that
7234can go wrong and how to fix them.
7235svn: The system cannot find the file specified. (Windows)
7236Subversion is complaining that it can’t find “the file speci-
7237fied.†In this case it’s looking for ssh in order to make a secure
7238connection (the svn command is being found just fine). The
7239usual fix for this is to edit your Subversion configuration as
7240described back in Section 5.1, svn+ssh, on page 57 and make
7241sure that plink.exe is available in your path.
7242svn: No such file or directory (Unix)
7243Similar to the Windows “cannot find file specified†problem,
7244Subversion is unable to find the ssh command on your system.
7245This might mean ssh isn’t installed on your computer.
7246Subversion just seems to hang (Windows)
7247Bring up Task Manager, and see if plink.exe is running. If it’s
7248running but Subversion isn’t displaying any output, it could
7249be because plink is waiting for user input. This can happen
7250when you connect to an SSH server for the first time and need
7251to accept the server key. Try running plink on its own, saying
7252“yes†when asked to store the key in Putty’s cache:
7253work > plink mike@olio.mynetwork.net echo hello
7254The server ' s host key is not cached in the registry. You
7255have no guarantee that the server is the computer you
7256think it is.
7257The server ' s rsa2 key fingerprint is:
7258ssh-rsa 1024 c3:82:fd:a6:b4:5d:23:f2:1a:f8:8b:04:be:c3
7259If you trust this host, enter "y" to add the key to
7260PuTTY ' s cache and carry on connecting.
7261: : :
7262Store key in cache? (y/n) y
7263mike@olio.mynetwork.net ' s password:
7264hello
7265N ETWORKING WITH A PACHE 157
7266svnserve: command not found
7267svn: Connection closed unexpectedly
7268Either or both of these lines is printed by the Subversion client
7269when it can’t find svnserve on the server. The SSH connection
7270has been established and you’ve authenticated as a Unix user,
7271but svnserve isn’t in the user’s path.
7272Subversion always attempts to run svnserve -t on the remote
7273server, so unfortunately you can’t fix the problem by telling
7274the client where Subversion is installed. You’ll need to change
7275the default path on the server, perhaps by editing /etc/profile .
7276Once you’ve got svnserve in the path, you should be able to
7277test from the client like this:
7278work > ssh mike@olio.mynetwork.net svnserve -t
7279( success ( 1 2 ( ANONYMOUS EXTERNAL ) ( edit-pipeline ) ) )
7280The success message with all the brackets is the start of the
7281svn protocol between the Subversion client and server and
7282means svnserve has been found correctly.
7283svn: No repository found in
7284’svn+ssh://myserver/home/svn-repos’
7285Subversion has successfully connected using SSH and started
7286svnserve . However, svnserve can’t find the repository. Check
7287that you’re using the correct path to the repository and that
7288you have sufficient permissions to read and create files in the
7289repository directory.
7290A.4 Networking with Apache
7291In this section we’ll show how to install Apache and configure
7292it to host a Subversion repository. Unix installation instruc-
7293tions vary a bit depending on the exact flavor of Unix, but
7294good instructions are available online. We’ll again be using
7295Fedora Core 5 as our example Unix platform.
7296The Subversion book from the Subversion developers them-
7297selves is probably the best complete reference and is available
7298at http://svnbook.red-bean.com/ [CSFP].
7299N ETWORKING WITH A PACHE 158
7300The “How-To†section on the Subversionary web site 4 includes
7301networking instructions for a number of operating systems,
7302including RedHat and Windows.
7303Apache on Windows
7304Download and Install Apache
7305Apache is open-source software, and you can download it for
7306free from http://httpd.apache.org/download.cgi .
7307For a Windows installation, you can download either an . exe
7308or an . msi . The MSI is a Windows Installer package and is a
7309smaller download, so that’s probably your best bet. Subver-
7310sion requires at least Apache 2.0.48—in this example we’re
7311using 2.0.50.
7312Run the installer, read the first couple of screens including
7313the license agreement and installation notes, and you should
7314get to a screen similar to that in Figure A.1 on the next page.
7315It’s important to get the info on this screen correct, or users
7316might have trouble connecting to Apache. If you’re not sure of
7317the settings to use, ask a network administrator to help you.
7318We’ll install Apache for the current user only, on port 8080.
7319Windows machines often already have a web server enabled
7320using the normal HTTP port 80, and we don’t want our new
7321Apache server to conflict. If you’re setting up a Subversion
7322repository and want to use port 80, make sure Internet Infor-
7323mation Services (IIS) has its web server switched off.
7324At the next step choose Typical Installation, and stick with
7325the default directory for installing Apache. You’ll see a few
7326command windows pop open as Apache installs, followed by
7327a message informing you that installation was successful.
7328At the moment, Apache isn’t running because we selected the
7329“just for the current user†option when installing. To start
7330Apache, choose Start > All Programs > Apache HTTP Server
73312.0.50 > Control Apache Server > Start Apache in Console. A
7332command prompt window will appear, which means Apache is
73334 http://www.subversionary.org/
7334N ETWORKING WITH A PACHE 159
7335Figure A.1: Apache Server Name Configuration
7336running. 5 Open a web browser to http://localhost:8080
7337and you should see a test page like the one in Figure A.2 on
7338the following page.
7339Install Subversion’s Apache Modules
7340Subversion integrates with Apache using a number of binary
7341modules that need to be installed in the right places for every-
7342thing to work properly.
7343If you’re using Windows, open C:\Program Files\Subversion\httpd
7344and copy mod authz svn.so and mod dav svn.so into the direc-
7345tory C:\Program Files\Apache Group\Apache2\modules . Then go
7346to C:\Program Files\Subversion\bin , and copy the file libdb42.dll
7347into C:\Program Files\Apache Group\Apache2\bin . If you already
73485 We were going to include a screenshot of the Apache console window,
7349but Dave decided it looked like one of those “Bournemouth by Night†joke
7350postcards, so it got the boot. Don’t worry when the Apache window comes up
7351and there’s no output—this is how it’s supposed to look.
7352N ETWORKING WITH A PACHE 160
7353Figure A.2: Apache Test Page
7354have Apache installed, the Subversion installer will do this
7355copying for you when you install Subversion.
7356Configuring Apache
7357Configuring Apache requires editing . conf files inside your
7358Apache install. The files you need to edit vary a little between
7359systems—Windows uses a single httpd.conf , as do many fla-
7360vors of Unix, and Red Hat Linux uses a number of smaller
7361files within a conf.d directory.
7362Choose Start > All Programs > Apache HTTP Server 2.0.50 >
7363Configure Apache Server > Edit the Apache httpd.conf Config-
7364uration file. This will open Notepad, everyone’s favorite editor,
7365with the main Apache configuration file.
7366Scroll down to the section of the file that reads “Dynamic
7367Shared Object (DSO) Support.†You’ll see a large number of
7368LoadModule commands, each of which activates extra func-
7369tionality in Apache. At the bottom of the list, add the following
7370two lines:
7371N ETWORKING WITH A PACHE 161
7372Joe Asks...
7373DAV, WebDAV, DeltaV??
7374As part of its integration with Apache, Subversion uses
7375WebDAV as the protocol between client and server.
7376WebDAV stands for “Web-based Distributed Author-
7377ing and Versioning†and is an extension of the HTTP
7378protocol. Instead of rolling their own network proto-
7379col, the Subversion developers decided to leverage
7380WebDAV.
7381Reuse brings a number of advantages, in both speed
7382of development and compatibility with other clients.
7383For example, both Windows and Mac OS X can con-
7384nect to a WebDAV server and make it available as a
7385network drive.
7386For further information on WebDAV, including client
7387configuration, see http://www.webdav.org/ .
7388LoadModule dav svn module modules/mod dav svn.so
7389LoadModule authz svn module modules/mod authz svn.so
7390Next, scroll up a little, and uncomment the existing line for
7391dav module :
7392LoadModule dav module modules/mod dav.so
7393Finally, scroll down to the bottom of the file, and add the
7394following section:
7395< Location /svn-repos >
7396DAV svn
7397SVNPath c: \ svn-repos
7398< /Location >
7399This tells Apache that URLs starting with /svn-repos should
7400use the Subversion DAV module and that the repository is in
7401c:\svn-repos .
7402If Apache is still running, stop it by closing its command
7403window. Then start Apache by using the Start Apache in
7404Console menu item. Now open your web browser, and hit
7405http://localhost:8080/svn-repos/ . If Subversion and
7406Apache are configured correctly, you’ll see your repository
7407N ETWORKING WITH A PACHE 162
7408Figure A.3: Subversion Repository Browsing
7409and the Sesame project, as in Figure A.3 . Try browsing
7410around the repository—clicking any file will display the lat-
7411est checked-in version of that file, and clicking a directory will
7412navigate you around.
7413Apache on Red Hat Linux
7414Fedora Core 5 usually comes with Apache installed as stan-
7415dard. If you’re following the installation instructions in this
7416chapter, you probably already installed Apache, Subversion,
7417and the Apache integration module mod dav svn . If not, fire
7418up your package manager and get those installed.
7419Configure Apache
7420On Red Hat Linux, Apache uses a number of conf files within
7421/etc/httpd/conf.d . Installing mod dav svn adds a new subver-
7422sion.conf file to that directory, which you’ll need to edit in order
7423to point at your repository. Other flavors of Unix stick with a
7424single httpd.conf file inside /etc/httpd .
7425S ECURING S UBVERSION 163
7426The contents of subversion.conf hint at security settings we’ll be
7427covering in Section A.5, Apache Security, on page 165, but for
7428now just uncomment enough that it points to your repository:
7429< Location /svn-repos >
7430DAV svn
7431SVNPath /home/svn-repos
7432< /Location >
7433Make sure the svn-repos directory is owned by the Apache user,
7434and restart the Apache web server:
7435root > chown -R apache /home/svn-repos
7436root > service httpd restart
7437Stopping httpd: [ OK ]
7438Starting httpd: [ OK ]
7439At this point your repository is unsecured, allowing read and
7440write access to anonymous users. Don’t leave it like this! Sec-
7441tion A.5, Apache Security, on page 165 details how to secure
7442your Apache hosted repository.
7443A.5 Securing Subversion
7444When it comes to accessing a Subversion repository, security
7445lies in two main areas: user authentication and path-based
7446permissions. User authentication is about making sure peo-
7447ple connecting to the repository are authorized to do so; it’s
7448basically password-protecting your data. Anyone supplying a
7449valid username and password is granted access to the reposi-
7450tory. Path-based security goes further, differentiating between
7451users and granting or denying access to individual directories
7452in the repository.
7453svnserve
7454By default, svnserve sets up a read-only repository. To get
7455read/write access, we’ll need to edit svnserve.conf , which lives
7456inside the svn-repos/conf directory. When you create a repos-
7457itory, svnserve.conf looks something like the one in Figure A.4
7458on the following page.
7459If you’re familiar with . conf files, you’ll see that the entire file
7460is commented out (lines starting with # are comments). Whilst
7461Subversion is trying to be helpful and give us some hints for
7462writing a config file, most people just end up confused by
7463S ECURING S UBVERSION 164
7464Figure A.4: Defaultsvnserve.conf
7465the file. Let’s just ignore the defaults and create a simple
7466svnserve.conf :
7467[general]
7468anon-access = read
7469auth-access = write
7470password-db = passwd
7471svnrepos/conf/svnserve.conf
7472This tells svnserve to allow anonymous read-only access to the
7473repository and to allow read/write access for authenticated
7474users. We also tell svnserve to look for usernames and pass-
7475words in a file called passwd . In the same conf directory, create
7476a password file as follows:
7477[users]
7478mike=secret
7479dave=n1nja123
7480ian=b4n4n4
7481svnrepos/conf/passwd
7482We’ve defined three users, each with their own password. In
7483order to commit a change to the repository, a client will have
7484to provide a valid username and password.
7485If you are using Subversion 1.3, svnserve can provide path-
7486based security using the same security configuration file as
7487mod authz svn . If you’re using an earlier version of Subver-
7488S ECURING S UBVERSION 165
7489sion or have not configured path-based security, a user who
7490has read or write access can get to the whole repository.
7491To enable path-based security, add the following line to your
7492svnserve.conf file:
7493authz-db = authz
7494Next, create the authorization database authz as described in
7495Section A.5, Path-Based Security, on page 167.
7496svn+ssh
7497Connecting to a repository using svn+ssh uses Unix security
7498to determine if a user can access the repository. If they can
7499access the repository’s database files they have read/write
7500access to the repository.
7501As with svnserve , it’s possible to use a hook script to achieve
7502path-based security with svn+ssh . It’s also possible to host
7503more than one repository on the same Unix server, with dif-
7504ferent groups of users granted access to each one, using stan-
7505dard Unix permissions.
7506Apache Security
7507If you’ve been following the instructions in this chapter so far,
7508you’ll have a repository online using Apache with only a very
7509basic configuration. When set up like this, your repository will
7510have read/write access for everyone, including anonymous
7511users.
7512We’d better fix that up quickly.
7513Apache provides a wealth of authentication options for users.
7514Here we’ll just set up basic password authentication, but you
7515can do fancier stuff including authenticating against a Win-
7516dows domain. Basic authentication requires a password file
7517with all your usernames and passwords in it, and you need to
7518use the htpasswd utility that comes with Apache to create it.
7519If you’re on Windows, open a command prompt and change to
7520the C:\Program Files\Apache Group\Apache2\bin directory, and
7521then run
7522bin > htpasswd -c -m c: \ svn-repos \ conf \ htpasswd mike
7523New password: ******
7524Re-type new password: ******
7525Adding password for user mike
7526S ECURING S UBVERSION 166
7527On Unix, htpasswd should be in your path already, so run
7528home > htpasswd -c -m /home/svn-repos/conf/htpasswd mike
7529New password: ******
7530Re-type new password: ******
7531Adding password for user mike
7532Once the file is created, you can add new users to it by drop-
7533ping the -c flag:
7534bin > htpasswd -m c: \ svn-repos \ conf \ htpasswd dave
7535New password: ********
7536Re-type new password: ********
7537Adding password for user dave
7538Next we need to tell Apache to authenticate users before they
7539are allowed to access the repository. We can do this by requir-
7540ing a valid user for all operations, or just for those folks who
7541actually modify the repository (and thus leave anonymous
7542browsing enabled). To lock things down completely, modify
7543your Apache Location directive as follows:
7544< Location /svn-repos >
7545DAV svn
7546SVNPath c: \ svn-repos
7547AuthType Basic
7548AuthName "Subversion Repository"
7549AuthUserFile c: \ svn-repos \ conf \ htpasswd
7550Require valid-user
7551< /Location >
7552If instead you’d like anonymous read-only access, configure
7553Apache like this:
7554< Location /svn-repos >
7555DAV svn
7556SVNPath c: \ svn-repos
7557AuthType Basic
7558AuthName "Subversion Repository"
7559AuthUserFile c: \ svn-repos \ conf \ htpasswd
7560< LimitExcept GET PROPFIND OPTIONS REPORT >
7561Require valid-user
7562< /LimitExcept >
7563< /Location >
7564Your configuration changes will take effect once you restart
7565Apache.
7566If you have an SSL certificate for your Apache server, you can
7567require a secure connection when accessing the repository.
7568This will encrypt all traffic between the Subversion client and
7569the repository, including passwords and file contents, and is
7570S ECURING S UBVERSION 167
7571generally a good idea if you’re making your repository avail-
7572able over the Internet. Edit your Apache configuration once
7573more, and add SSLRequireSSL :
7574< Location /svn-repos >
7575DAV svn
7576SVNPath c: \ svn-repos
7577AuthType Basic
7578AuthName "Subversion Repository"
7579AuthUserFile c: \ svn-repos \ conf \ htpasswd
7580Require valid-user
7581SSLRequireSSL
7582< /Location >
7583Path-Based Security
7584Both svnserve and Apache can be configured to use path-based
7585security, which can restrict access to directories within the
7586repository. This is accomplished using mod authz svn (for
7587Apache) or the authz-db configuration setting (for svnserve ).
7588Both use a common file format for defining the authorization
7589database.
7590To enable the authorization database in Apache, edit your sub-
7591version.conf file and add the following section to your repository
7592definition:
7593AuthzSVNAccessFile c: \ svn-repos \ conf \ authz
7594The authorization database file contains group definitions and
7595path security definitions. The [groups] config section names
7596groups and the users within them. Path security definitions
7597associate repository paths with access permissions for users
7598or groups of users. The access granted can be read-only, read-
7599write, or no access, using “râ€, “rw†or “â€, respectively.
7600As an example, suppose we have developers Fred and Wilma
7601who should be able to read and write the Sesame project tree,
7602with everyone else just able to read the tree. The authz file
7603would look like this:
7604[groups]
7605developers = fred, wilma
7606[/projects/sesame]
7607@developers = rw
7608* = r
7609svnrepos/conf/authz
7610The new, top-secret “Project Blue†can only be accessed by
7611Barney, our smartest and most trustworthy developer. We’ll
7612need the following security definition:
7613S ECURING S UBVERSION 168
7614[/projects/blue]
7615barney = rw
7616* =
7617Security permissions are inherited from parent directories to
7618their children. You can tighten (or loosen) permissions by
7619including a more specific security definition. To provide the
7620test team write access to Sesame’s testing directory, the au-
7621thorization file should look like this:
7622[/projects/sesame]
7623@developers = rw
7624* = r
7625[/projects/sesame/testing]
7626@testers = rw
7627If you’re using the SVNParentPath directive to network mul-
7628tiple repositories, you can use [repository:path] syntax to
7629refer to a specific repository. If the administrators group
7630should get read-write access to documents stored under the
7631admin repository, use the following security definition:
7632[admin:/docs]
7633@administrators = rw
7634In the previous example the only people able to access the
7635docs directory will be the administrators. In fact, the only
7636path within the admin repository that anyone can access will
7637be docs because Subversion disables access to all directo-
7638ries unless explicitly instructed otherwise. It’s often useful to
7639specify read-only access everywhere in every repository, which
7640looks like this:
7641[/]
7642* = r
7643Access Control with Hook Scripts
7644Subversion can be configured with a number of hook scripts hook scripts
7645that are run on the server at certain times during a commit.
7646The pre-commit hook runs before a commit is allowed to pro-
7647ceed, and if it returns a nonzero exit status, Subversion dis-
7648allows the commit.
7649Pre-commit hooks have access to information about which
7650files are being changed, as well as the user attempting to
7651change them. We can use this information to set up path-
7652based security—if a user attempts to change a file or directory
7653S ECURING S UBVERSION 169
7654to which they have not been granted access, our hook script
7655exits with a one and Subversion stops the commit.
7656Subversion comes with commit-access-control.pl , which should
7657get installed somewhere on your machine when you install
7658Subversion. For Fedora Core 5, for example, it’s bundled with
7659the Subversion documentation in /usr/share/doc .
7660Copy commit-access-control.pl to the hooks directory in your
7661repository. Also copy commit-access-control.cfg.example , which
7662you should rename to ditch the . example extension.
7663Inside your hooks directory, rename pre-commit.tmpl and make
7664it executable:
7665hooks > mv pre-commit.tmpl pre-commit
7666hooks > chmod +x pre-commit
7667The pre-commit template does two things – it checks that the
7668log message being used contains some text (which you may or
7669may not be worried about) and then calls the access control
7670script to check the user’s permissions.
7671Configure the permissions in commit-access-control.cfg , and
7672you should be ready to go. Python fans might be interested
7673in svnperms.py , included in the Subversion distribution, which
7674works in a similar fashion.
7675Hook scripts that do more than simple read-only file access
7676may require you configure security settings on your system.
7677If you are using Apache to host your Subversion repository
7678the hook scripts will run as the Apache user, usually httpd or
7679nobody, rather than a regular user. This may mean that your
7680scripts cannot perform operations such as modifying files or
7681sending emails, depending on your exact configuration. Many
7682Linux distributions now include SELinux security enhance-
7683ments that make it impossible for particular programs—such
7684as the Apache web server—to access files outside of their
7685usual configuration and web site directories. In this case you
7686may need to relax the restrictions to get your hook scripts to
7687work properly. You can usually check the security log in order
7688to see whether your scripts are being blocked by SELinux or
7689other security settings.
7690B ACKING U P Y OUR R EPOSITORY 170
7691A.6 Backing Up Your Repository
7692Backing up your source code makes a lot of sense—after all,
7693your developers are assuming the repository is a safe place to
7694store all their hard work. Subversion uses either Berkeley DB
7695or the “fsfs†filesystem as the backend for your repository, and
7696these can’t be backed up like a regular file. If someone makes
7697a change to the repository during a backup, the repository
7698files may be in an inconsistent state, causing the backup to
7699be invalid. 6
7700Subversion provides the svnadmin dump command to extract
7701the contents of a repository into a portable dumpfile. A dump- dumpfile
7702file contains information about each revision in the repository
7703and can be backed up like a regular file. The svnadmin load
7704command takes the contents of a dumpfile and loads it into a
7705repository. This can be used to restore from a backup or to
7706copy a repository to another location.
7707Full Backups
7708Depending on how large your repository is, and how often you
7709want to make a backup, you might be able to get away with
7710just doing complete dumps of your repository. The following
7711command creates a complete dump of the repository:
7712mike > svnadmin dump
7713˜ /svn-repos
7714> dumpfile.041113
7715* Dumped revision 0.
7716* Dumped revision 1.
7717: : :
7718* Dumped revision 48.
7719Subversion dumps every revision in the repository to the con-
7720sole, which we then save in dumpfile.041113 . The resulting file
7721contains everything the repository contains. A typical dump
7722is highly compressible and ready to back up.
7723Creating a dumpfile using svnadmin will always produce a con-
7724sistent snapshot of your repository, even if changes are being
7725committed whilst the dump is created. This means you don’t
77266 Using an “fsfs†repository
7727you’re more likely to get a consistent
7728backup, especially if you back up the files in a particular order.
7729See http://svn.collab.net/repos/svn/trunk/notes/fsfs for more
7730details.
7731B ACKING U P Y OUR R EPOSITORY 171
7732need to shut down access to the repository whilst svnadmin
7733dump is running.
7734To restore from the dumpfile into a new repository, use svnad-
7735min load . First we create a new repository (the old one might
7736not be totally corrupt, so don’t delete it), and then load the
7737dumpfile:
7738mike > svnadmin create svn-repos2
7739mike > svnadmin load svn-repos2 < dumpfile.041113
7740<<< Started new transaction, based on original revision 1
7741* adding path : sesame ... done.
7742* adding path : sesame/trunk ... done.
7743* adding path : sesame/trunk/Day.txt ... done.
7744* adding path : sesame/trunk/Number.txt ... done.
7745------- Committed revision 1 >>>
7746: : :
7747<<< Started new transaction, based on original revision 48
7748* adding path : sesame/trunk/common/HibernateHelper.java COPIED... done.
7749* adding path : sesame/trunk/contacts/Contacts.hbm.xml COPIED... done.
7750* editing path : sesame/trunk/contacts/Contacts.java ... done.
7751------- Committed revision 48 >>>
7752Subversion replays each revision from the dumpfile and com-
7753mits to the repository. Once the load is complete, the reposi-
7754tory is ready to go and looks exactly as it did when the dump
7755was created.
7756Incremental Backups
7757Doing full backups every day is going to eat disk space pretty
7758fast. Fortunately, svnadmin dump takes an --incremental option,
7759along with --revision specifying a revision range, to produce
7760smaller dump files.
7761Let’s say you already have a dump file containing revisions
77621 to 100, but the repository is up to revision 104. You can
7763create an incremental dump file by running
7764work > svnadmin dump --incremental --revision 100:104 \
7765/home/svn-repos
7766Combining weekly backups with daily incrementals should
7767give you peace of mind without requiring crazy amounts of
7768disk space. With a bit of scripting, we can create a weekly
7769and daily backup routine that remembers the revision num-
7770bers for each backup.
7771The program that follows is the weekly backup script. As pre-
7772sented it’s a very basic Perl script, but it does demonstrate
7773B ACKING U P Y OUR R EPOSITORY 172
7774how to use svnlook youngest to find out what revision your
7775repository is currently on.
7776#!/usr/bin/perl -w
7777#
7778# Perform a weekly backup of a Subversion repository,
7779# logging the most-recently-backed-up revision so an
7780# incremental script can be run other days.
7781$ svn repos = "/home/mike/svn-repos" ;
7782$ backups dir = "/home/mike/svn-backup" ;
7783$ next backup file = "weekly-full-backup." . ‘date +%Y%m%d‘ ;
7784$ youngest = ‘svnlook youngest $ svn repos‘ ;
7785chomp $ youngest;
7786print "Backing up to revision $ youngest \ n" ;
7787$ svnadmin cmd = "svnadmin dump --revision 0: $ youngest " .
7788" $ svn repos > $ backups dir/ $ next backup file" ;
7789‘ $ svnadmin cmd‘ ;
7790print "Compressing dump file... \ n" ;
7791print ‘gzip -9 $ backups dir/ $ next backup file‘ ;
7792open(LOG, " >$ backups dir/last backed up" );
7793print LOG $ youngest;
7794close LOG;
7795svn-backup/weekly-backup.pl
7796Running this script dumps your repository into a file called
7797weekly-full-backup.yyyymmdd and compresses it using gzip . It
7798also saves the most recent revision to be backed up into a file
7799called last backed up :
7800svn-backup > ./weekly-backup.pl
7801Backing up to revision 638
7802* Dumped revision 0.
7803* Dumped revision 1.
7804* Dumped revision 2.
7805: : :
7806* Dumped revision 638.
7807Compressing dump file...
7808The daily backup script uses the revision number saved by the
7809weekly script to dump just what has changed, rather than the
7810whole repository:
7811#!/usr/bin/perl -w
7812#
7813# Perform a daily backup of a Subversion repository,
7814# using the previous most-recently-backed-up revision
7815# to create just an incremental dump.
7816$ svn repos = "/home/mike/svn-repos" ;
7817$ backups dir = "/home/mike/svn-backup" ;
7818$ next backup file = "daily-incremental-backup." . ‘date +%Y%m%d‘ ;
7819open(IN, " $ backups dir/last backed up" );
7820$ previous youngest = < IN > ;
7821chomp $ previous youngest;
7822close IN;
7823$ youngest = ‘svnlook youngest $ svn repos‘ ;
7824B ACKING U P Y OUR R EPOSITORY 173
7825chomp $ youngest;
7826if( $ youngest eq $ previous youngest) {
7827print "No new revisions to back up. \ n" ;
7828exit 0;
7829}
7830# We need to backup from the last backed up revision
7831# to the latest (youngest) revision in the repository
7832$ first rev = $ previous youngest + 1;
7833$ last rev = $ youngest;
7834print "Backing up revisions $ first rev to $ last rev... \ n" ;
7835$ svnadmin cmd = "svnadmin dump --incremental " .
7836"--revision $ first rev: $ last rev " .
7837" $ svn repos > $ backups dir/ $ next backup file" ;
7838‘ $ svnadmin cmd‘ ;
7839print "Compressing dump file... \ n" ;
7840print ‘gzip -9 $ backups dir/ $ next backup file‘ ;
7841open(LOG, " >$ backups dir/last backed up" );
7842print LOG $ last rev;
7843close LOG;
7844svn-backup/daily-backup.pl
7845Running this script after some changes have been made will
7846dump just the new revisions:
7847svn-backup > ./daily-backup.pl
7848Backing up revisions 639:641
7849* Dumped revision 639.
7850* Dumped revision 640.
7851* Dumped revision 641.
7852Compressing dump file...
7853The daily incremental backups are much smaller than a full
7854backup but don’t contain enough information to restore your
7855repository if disaster strikes. To do a restore, you need to
7856first load your most recent full backup, followed by each daily
7857backup:
7858svn-backup > mkdir newrepos
7859svn-backup > svnadmin create newrepos
7860svn-backup > zcat weekly-full-backup.20041129.gz | \
7861svnadmin load newrepos
7862<<< Started new transaction, based on original revision 1
7863* adding path : branches ... done.
7864* adding path : tags ... done.
7865* adding path : trunk ... done.
7866: : : :
7867svn-backup > zcat daily-incremental-backup.20041130.gz | \
7868svnadmin load newrepos
7869<<< Started new transaction, based on original revision 639
7870* editing path : trunk/ccnet/lib/NetReflector.dll ... done.
7871------- Committed new rev 639 (loaded from original rev 639) >>>
7872: : : :
7873Appendix B
7874Migrating to Subversion
7875So you’re sold on the benefits of using Subversion. You like
7876its support for atomic commits, its changesets, its speedy net-
7877work protocols, and its real branching and merging. You’ve
7878even convinced your boss that Subversion is right for your
7879team. The only minor problem standing between you and
7880a glorious subversive victory is the half-dozen projects and
7881years of history you have in your existing version control tool.
7882Fortunately, the Subversion developers thought people might
7883like to keep their old history around and have provided tools
7884to convert an existing CVS 1 repository to Subversion. You can
7885also find third-party tools to convert from ClearCase, Perforce,
7886and Visual SourceSafe.
7887Before jumping headfirst into the rest of this chapter, it’s
7888worth noting that not converting your old repository is also
7889a reasonable migration strategy. If you’re not too bothered
7890about being able to see historical information past the point
7891you started using Subversion, just export your source code
7892from the old version control tool, import it into Subversion,
7893and make the old repository read-only. If you really do need
7894that historical information it’s still there, albeit not in the new
7895Subversion repository.
7896In the rest of this chapter we’ll assume you want to convert all
7897your history and that we’re performing a migration from CVS
7898to Subversion.
78991 cvs2svn
7900will also convert an RCS repository to Subversion, since RCS is
7901the underlying format used by CVS.
7902G ETTING CVS 2 SVN 175
7903B.1 Getting cvs2svn
7904The cvs2svn project, along with the main Subversion project, is
7905hosted at Tigris. 2 Download the package corresponding to the
7906version of Subversion you’re using. As of this writing, cvs2svn
7907is only available for Subversion 1.2 or 1.3, the older versions
7908are no longer maintained.
7909cvs2svn is a Python script designed to run on Unix. Whilst you
7910might be able to get it to work on Windows, possibly using the
7911Cygwin 3 Linux emulation tools, we recommend using a real
7912Unix box. You’ll also need rcs installed because cvs2svn uses
7913it to access the contents of your CVS repository (you can get
7914away with having just CVS installed, but using “real†RCS is
7915a safer bet).
7916You can install cvs2svn on your system so everyone can see it
7917or just run it as a normal user. Both will work, but installing
7918system-wide is less work if you’re not Python savvy. Log in as
7919root, and run the following commands:
7920tmp > tar -xzf cvs2svn-1.2.1.tar.gz
7921tmp > cd cvs2svn-1.2.1
7922cvs2svn-1.2.1 > make install
7923./setup.py install
7924running install
7925: : :
7926copying build/lib/cvs2svn rcsparse/compat.py - > ...
7927copying build/lib/cvs2svn rcsparse/debug.py - > ...
7928: : :
7929byte-compiling /usr/lib/python2.3/.../default.py to default.pyc
7930byte-compiling /usr/lib/python2.3/.../texttools.py to texttools.pyc
7931running install scripts
7932copying build/scripts-2.3/cvs2svn - > /usr/bin
7933changing mode of /usr/bin/cvs2svn to 775
7934B.2 Choosing How Much to Convert
7935cvs2svn will do a thorough job of converting your existing CVS
7936repository, including all your branches and tags. It will also
7937analyze the history, looking for files that were all changed at
7938about the same time with the same log message and con-
7939verting from CVS’s per-file revision history to Subversion’s
7940changeset style. All of this is quite a bit of work and will
7941take a while depending on the size of your CVS repository.
79422 http://cvs2svn.tigris.org/
79433 http://www.cygwin.com/
7944C ONVERTING Y OUR R EPOSITORY 176
7945If you don’t want to convert all of the history, you don’t have to
7946do so. Specifying which branches you’re interested in will save
7947both conversion time and space in the new Subversion repos-
7948itory. cvs2svn takes a whole bunch of command-line argu-
7949ments, but probably the most useful is --exclude , which
7950sets a regular expression for matching tags and branches
7951you’d like to skip during conversion.
7952It’s important to note that cvs2svn is designed for one-time
7953conversions from CVS to Subversion; it can’t be used to incre-
7954mentally sync changes between the two systems.
7955B.3 Converting Your Repository
7956Let’s assume you’d like a complete conversion of everything
7957in your CVS repository. The first step is to make sure every-
7958one has their changes checked into CVS and is aware you’re
7959about to do the conversion. Next take your CVS repository
7960offline so no more changes are committed to it. The final
7961preparation step, and the most important, is to make a copy
7962of your CVS repository. You need to copy the whole of your
7963CVSROOT because that’s what cvs2svn runs against. We’ll say
7964that again: make a copy of your CVS repository and use the
7965copy when converting.
7966cvs2svn works by creating a Subversion dumpfile, just like
7967those created with svnadmin dump . The dumpfile can then be
7968loaded into a Subversion repository with svnadmin load . You
7969can shortcut this process using cvs2svn ’s -s option, specifying
7970a directory in which you’d like to create the new Subversion
7971repository.
7972Here we’ll do a conversion of the Testsweet project, which is
7973hosted on SourceForge. The great thing about SourceForge
7974projects is the daily CVS snapshot where you can download a
7975compressed copy of the project’s repository, precisely the files
7976cvs2svn needs for conversion. 4 If you’d like to play with cvs2svn
7977but don’t want to use your own CVS repository to do so, this
7978might be just what you need.
79794 Testsweet’s daily CVS snapshot is at
7980http://cvs.sourceforge.net/
7981cvstarballs/testsweet-cvsroot.tar.bz2 .
7982C ONVERTING Y OUR R EPOSITORY 177
7983Copy your CVS repository to a scratch directory. In this exam-
7984ple we’ve put the Testsweet CVS repository into a local direc-
7985tory called testsweet , and we’re converting it to a Subversion
7986repository in testsweet-repos . cvs2svn will create the repository
7987directory and initialize it for us during the conversion:
7988tmp > cvs2svn -v -s testsweet-repos testsweet
7989----- pass 1 -----
7990Examining all CVS ' ,v ' files...
7991testsweet/CVSROOT/checkoutlist,v
7992testsweet/CVSROOT/commitinfo,v
7993testsweet/CVSROOT/config,v
7994: : :
7995We asked for verboseness (the -v option), so cvs2svn produced
7996a whole bunch of output during the conversion. Testsweet is
7997a pretty small project so takes only a few seconds to convert.
7998When it’s done, cvs2svn prints a few statistics for us:
7999cvs2svn Statistics:
8000------------------
8001Total CVS Files: 161
8002Total CVS Revisions: 218
8003Total Unique Tags: 1
8004Total Unique Branches: 0
8005CVS Repos Size in KB: 2716
8006Total SVN Commits: 10
8007First Revision Date: Fri Nov 21 18:12:21 2003
8008Last Revision Date: Thu Jun 24 12:35:29 2004
8009We can now use svn ls to browse the new repository, observing
8010how we have the usual trunk , tags , and branches directories:
8011tmp > svn ls file:///tmp/testsweet-repos
8012branches/
8013tags/
8014trunk/
8015tmp > svn ls file:///tmp/testsweet-repos/trunk
8016CVSROOT/
8017testsweet/
8018We now have the Testsweet project at the root level of the
8019repository, which might not be quite what you want. cvs2svn
8020allows us to specify the trunk , tags , and branches directories:
8021tmp > cvs2svn --trunk=testsweet/trunk \
8022--branches=testsweet/branches \
8023--tags=testsweet/tags \
8024-s testsweet-repos testsweet
8025Your newly converted repository is ready for use immediately.
8026Just fire up networking using svnserve or Apache, check out a
8027working copy, and carry on coding!
8028Appendix C
8029Third-Party Subversion Tools
8030Subversion comes as a set of command-line applications— svn ,
8031svnadmin , svnserve , etc. Whilst the command line is fairly easy
8032to use, most people like to use something a little more friendly.
8033Fortunately, Subversion provides a rich set of APIs to third-
8034party developers, so they can make add-on clients and tools.
8035C.1 TortoiseSVN
8036Tortoise is a front end for Subversion that integrates directly
8037with Windows Explorer. Once installed, you can see the state
8038of your files and directories just by browsing around your
8039computer. Tortoise puts little green ticks next to files that are
8040up-to-date and little red exclamation points next to files you’ve
8041modified. Tortoise also provides handy automation for tasks
8042such as resolving conflicts and managing tags and branches.
8043In this section we’ll use Tortoise to carry out some everyday
8044tasks that we’ve previously seen using the command line.
8045Downloading and Installing
8046Download TortoiseSVN, 1 and run the appropriate installer for
8047your version of Windows, which should pop up a welcome
8048screen. Pick a location to install to (or accept the default
8049directory C:\Program Files\TortoiseSVN ), and choose whether Tor-
8050toise should be available to every user on the computer or just
80511 TortoiseSVN can be found at
8052http://tortoisesvn.tigris.org/ .
8053T ORTOISE SVN 179
8054Figure C.1: The Tortoise Context Menu
8055yourself. That’s all you need to decide on; the installer will
8056take care of everything else.
8057The Tortoise installer will ask you to restart your computer.
8058Unlike most installers Tortoise is actually serious about this;
8059because it integrates with the Windows Explorer, it needs a
8060reboot to properly register itself.
8061Checking Out
8062Bring up an Explorer window, and change to a directory in
8063which you’d like to check out a working copy. Here we’ll be
8064using C:\work . Right-clicking in the directory will bring up a
8065menu including Tortoise’s Subversion integration, as shown
8066in Figure C.1 .
8067Choose Checkout... from the context menu, which will bring
8068up a dialog box asking what you’d like to check out. Use the
8069sandbox repository file:///C:/svn-repos/sesame/trunk , and check
8070T ORTOISE SVN 180
8071Figure C.2: The Freshly Checked-Out Sesame Project
8072out to C:\work\princess ( sesame is already a working copy, so
8073we’ll be starting fresh as Princess).
8074Tortoise will flash a progress box as it checks out the Sesame
8075project, leaving you with a new princess directory. Looking in
8076the directory, you’ll see Day.txt , Number.txt , and the rest of the
8077Sesame project. Since all the files are up-to-date, Tortoise
8078flags them with a little green check mark, as shown in Fig-
8079ure C.2 .
8080Making Changes
8081Make some changes to Number.txt , maybe capitalizing three.
8082After you save the file, Tortoise will flag it with a red exclama-
8083tion point. 2 The parent directory princess will also be flagged
8084red. Right-click Number.txt , and choose TortoiseSVN > Diff.
80852 You might need to hit F5 to get Windows to refresh the screen and display
8086the new icon.
8087T ORTOISE SVN 181
8088Figure C.3: Examining Your Changes
8089This will display a TortoiseMerge window showing the changes
8090you’ve made, similar to Figure C.3 .
8091Adding a new file is equally straightforward. Create a new file
8092called Year.txt , and save it in your working copy. Subversion
8093doesn’t know anything about this file yet, so Tortoise leaves
8094it undecorated. Right-click the new file, and choose Tortoise-
8095SVN > Add. Tortoise will pop up a window asking you to con-
8096firm the addition, which is more useful when you’re adding
8097a bunch of files at once. Click the OK button, and Tortoise
8098will add the file. Since Subversion now knows about Year.txt ,
8099it displays it with a blue “plus†icon.
8100Checking In
8101Right-click on the princess directory, and choose Commit....
8102Tortoise will show you all the files you’ve changed and prompt
8103you for a commit message, as shown in Figure C.4 on the next
8104page. At this point, you can decide not to commit a particular
8105file by unchecking its tickbox. If you’re not sure what you’ve
8106changed, double-clicking a file will pop up a diff window so
8107you can review your changes.
8108T ORTOISE SVN 182
8109Figure C.4: The TortoiseSVN Commit Window
8110Enter a commit message describing your changes (and more
8111important why you made those changes) and hit OK. Tortoise
8112will flash a window as it commits your changes to the reposi-
8113tory.
8114Resolving Conflicts
8115As part of our lightning-fast tour through Tortoise, let’s see
8116how it helps us when a conflict arises. Check out another
8117copy of the Sesame project, this time to C:\work\aladdin . We’ll
8118use this directory to simulate the actions of Aladdin, another
8119developer on our team. Edit Number.txt , changing five to cinco,
8120and then commit the changes.
8121T ORTOISE SVN 183
8122Figure C.5: Number.txt in Conflict
8123Now go back to the princess working copy, and edit the same
8124file, changing five to cinq, this time to keep our French cus-
8125tomers happy. Right-click the princess directory, choose Com-
8126mit, enter a log message, and hit OK. Tortoise will tell you that
8127Number.txt is out-of-date and the commit has failed. Tortoise
8128will also suggest you update your working copy in order to
8129commit.
8130Follow Tortoise’s suggestion, and run an update on princess by
8131right-clicking and choosing Update. The Tortoise update win-
8132dow will pop up whilst Tortoise gets the latest revision from
8133the repository, and depending on how fast your machine is
8134you might notice a line in red as it gets to Number.txt , denoting
8135a conflict. Tortoise will leave both Number.txt and princess dec-
8136orated with a warning triangle, as shown in Figure C.5 , to let
8137you know there’s a conflict.
8138Tortoise also saves some extra copies of Number.txt to help
8139resolve the conflict. You’ll notice . mine , . r9 , and . r10 in our
8140T ORTOISE SVN 184
8141Figure C.6: The Tortoise Merge Window
8142example so far. The first, . mine , is your version of the file,
8143including your modifications. The second, . r9 , contains the
8144base revision on which your changes are based—this is the
8145revision of the file before Princess started editing it. Finally,
8146. r10 contains the revision that conflicts with your changes.
8147These are the changes that Aladdin committed.
8148Fortunately, Tortoise comes with a three-way 3 merge tool that
8149makes it easy to resolve the conflicts. Right-click on the file
8150Number.txt , and choose TortoiseSVN > Edit Conflicts. Tortoise
8151will pop up a merge window like that in Figure C.6 .
8152TortoiseMerge displays the two sets of changes side by side,
8153along with a merge result in the bottom half of the window.
8154In this particular case we’re sure that cinq is correct, so we’re
8155going to pick our changes (the Princess’s changes rather than
8156Aladdin’s). Right-click the word cinq, and choose Use this text
8157block. Tortoise will update the merge result in the bottom
8158half of the window to show the result. If you have more than
81593 Three-way merging is so called because it merges an original version of
8160a file with two people’s changes.
8161IDE I NTEGRATION 185
8162one conflict, you can pick and choose between the two sets
8163of changes until you’re happy. Now just close the merge win-
8164dow. Tortoise will ask you if you’d like to save your changes;
8165say “yes†since you’re happy with the merge, and Tortoise will
8166close the merge window.
8167You’ll notice Tortoise is still decorating the file with a little
8168warning triangle. Now that we’ve resolved the conflict, we
8169need to tell Tortoise everything is okay. Right-click Number.txt ,
8170and choose TortoiseSVN > Resolved. Tortoise will clean up the
8171. mine , . r9 , and . r10 files and mark Number.txt with an exclama-
8172tion point showing you’ve modified it. Now finish checking in
8173as normal.
8174TortoiseSVN provides shortcuts for branching, tagging, and
8175merging, and whilst we don’t have space here to detail every-
8176thing, we do suggest you try it. We do just about have room
8177to plug the excellent repository browser, which you can get
8178to by choosing TortoiseSVN > Repo-Browser. This nifty little
8179tool enables you to nose around a repository without needing
8180a working copy. This comes in handy if you’re trying to figure
8181out where all the branches are for a project or where exactly
8182they’ve imported vendor source code. Figure C.7 on the fol-
8183lowing page shows us perusing the Subversion repository at
8184http://svn.collab.net .
8185C.2 IDE Integration
8186Subversion’s IDE integration has greatly matured since Sub-
8187version 1.0, and many popular IDEs now include official sup-
8188port. It’s possible to use just the command line or Tortoise,
8189but many users are used to tight integration between their
8190editor and version control, so do investigate Subversion sup-
8191port if you can.
8192Eclipse, the popular open-source Java IDE, has a plug-in
8193called Subclipse that integrates with Subversion, available
8194from http://subclipse.tigris.org/ .
8195IntelliJ IDEA, another popular Java IDE, has full support for
8196Subversion as of release 5.0. IDEA is available from http://www.jetbrains.com/ .
8197Ankhsvn provides integration with Visual Studio and is avail-
8198able from http://ankhsvn.tigris.org/ . Note that if you’re
8199O THER T OOLS 186
8200Figure C.7: Tortoise Repo-Browser in action
8201using Visual Studio web projects, they may be incompatible
8202with Subversion’s .svn administrative directories. TortoiseSVN
8203has a special “directory hack†option that will use svn as a
8204directory name instead. Bear in mind that a working copy cre-
8205ated like this will be incompatible with a normal working copy,
8206so you might need to re-checkout after enabling the hack.
8207C.3 Other Tools
8208SVN::Notify sends colored HTML e-mails when a developer
8209checks changes into your repository. This can be a great com-
8210munication tool for your team. SVN::Notify is available from
8211CPAN: http://search.cpan.org/dist/SVN-Notify/ .
8212If you’re using XCode on the Mac, you might need a key man-
8213ager to get SSH connections to work. SSHKeychain provides
8214“painless key management for Mac OS X†and is available
8215from http://www.sshkeychain.org/ .
8216The Putty suite of SSH client tools for Windows 4 also works
82174 http://www.chiark.greenend.org.uk/Ëœsgtatham/putty/
8218O THER T OOLS 187
8219great for getting an svn+ssh connection working and includes
8220Pageant, a key management agent. Chapters 8 and 9 of the
8221Putty Manual 5 are worth reading if you’d like to avoid typing
8222passwords everytime you access an svn+ssh repository.
82235 http://the.earth.li/Ëœsgtatham/putty/0.56/htmldoc/Chapter9.html
8224Appendix D
8225Advanced Topics
8226D.1 Programmatic Access to Subversion
8227Subversion features a number of language bindings, allowing
8228you to access the Subversion API through your favorite pro-
8229gramming language. The language bindings use Swig, the
8230Simplified Wrapper and Interface Generator, and essentially
8231expose the original C APIs to other languages. Swig bindings
8232exist for C, C++, C#, Java, Perl, Python and Ruby. Of these
8233the Python bindings are probably the most popular and def-
8234initely the most mature, but expect bindings to improve over
8235time.
8236Installing language bindings will be different depending on
8237your operating system, but tends to be best supported on
8238Unix. For Fedora Core 5, installing the Perl bindings is as
8239simple as yum install subversion-perl .
8240As an alternative to wrapping the C API, a group of program-
8241mers decided to implement a Subversion client in pure Java.
8242When they started the advice from the Subversion developers
8243was “don’t bother, just use the Swig bindings,†but they per-
8244severed and have produced an excellent implementation. The
8245JavaSVN library is used by JetBrains as the basis of their IDE
8246integration with Subversion, which is as good a recommenda-
8247tion as they could ever wish for.
8248The TMate JavaSVN library is available from http://tmate.org/svn/
8249and we’ll be using it for examples in the next section.
8250P ROGRAMMATIC A CCESS TO S UBVERSION 189
8251A Simple Subversion Client
8252Download the standalone version of JavaSVN from the TMate
8253website and unzip it to your hard drive. You’ll find . jar files
8254used for development and a doc subdirectory containing full
8255JavaDoc documentation for the library. To use JavaSVN in a
8256project simply include javasvn.jar in your classpath.
8257The JavaSVN library contains a rich assortment of functions
8258for talking to a Subversion repository and manipulating a
8259local working copy. As a first example we’ll connect to the
8260Subversion repository at CollabNet and print out a directory
8261listing.
8262Remote operations are conducted through instances of SVN-
8263Repository . Since we’re using the http scheme to access the
8264repository we must initialize the DAV repository factory before
8265we use it:
8266String reposUrl = "http: //svn.collab.net/repos/svn";
8267SVNURL url = SVNURL.parseURIEncoded(reposUrl);
8268DAVRepositoryFactory.setup();
8269SVNRepository repository = SVNRepositoryFactory.create(url);
8270Now that we have a repository instance we can perform func-
8271tions against the remote repository. For instance, to retrieve
8272a directory listing we can use the getDir () method:
8273Map < String, String > dirProps = new HashMap < String, String > ();
8274List < SVNDirEntry > dirEntries = new ArrayList < SVNDirEntry > ();
8275repository.getDir("/trunk/subversion", -1, dirProps, dirEntries);
8276We provide a path within the repository, /trunk/subversion , and
8277a revision number, in this case -1 to indicate we’re inter-
8278ested in the HEAD revision. We also provide an empty map
8279into which JavaSVN will place the properties for the directory
8280being listed, and an empty list into which the actual directory
8281entries will be fetched.
8282Each SVNDirEntry represents a file or directory within the direc-
8283tory being listed. Entries have a wealth of properties such as
8284name, size, revision, creation date, last-changed-by, and so
8285on. Here’s an example program listing files within the Collab-
8286Net Subversion repository:
8287import org.tmatesoft.svn.core.*;
8288import org.tmatesoft.svn.core.io.*;
8289import org.tmatesoft.svn.core.internal.io.dav.*;
8290import java.util.*;
8291P ROGRAMMATIC A CCESS TO S UBVERSION 190
8292public class ListDirectory
8293{
8294public static void main(String[] args)
8295throws SVNException
8296{
8297String reposUrl = "http: //svn.collab.net/repos/svn";
8298SVNURL url = SVNURL.parseURIEncoded(reposUrl);
8299DAVRepositoryFactory.setup();
8300SVNRepository repository = SVNRepositoryFactory.create(url);
8301Map < String, String > dirProps = new HashMap < String, String > ();
8302List < SVNDirEntry > dirEntries = new ArrayList < SVNDirEntry > ();
8303repository.getDir("/trunk/subversion", -1, dirProps, dirEntries);
8304for (SVNDirEntry dirEntry : dirEntries) {
8305printEntry(dirEntry);
8306}
8307}
8308private static void printEntry(SVNDirEntry entry) {
8309if(entry.getKind() == SVNNodeKind.DIR) {
8310System.out.println("Directory: " + entry.getName());
8311} else {
8312System.out.println("File: " + entry.getName()
8313+ ", size " + entry.getSize()
8314+ ", last modified by " + entry.getAuthor());
8315}
8316}
8317}
8318java/ListDirectory.java
8319Watching a Repository for Changes
8320Subversion’s hook scripts allow you to intercept interesting
8321events (such as changes being committed), but you might not
8322always want to use a hook script. In some cases you may
8323be unable to use hooks due to security or access restrictions
8324on your repository. Many Continuous Integration tools use
8325a “polling†strategy to check whether anything has changed
8326within a repository, and if it has, to automatically do some-
8327thing useful like building the latest code and running tests.
8328The JavaSVN library can be used to poll a repository and look
8329for changes using the getLatestRevision () method.
8330The following example program watches a given repository
8331and prints out the log message when someone commits a
8332change. It only checks once per minute, so it creates a very
8333light load on a Subversion server.
8334import org.tmatesoft.svn.core.*;
8335import org.tmatesoft.svn.core.io.*;
8336import org.tmatesoft.svn.core.internal.io.dav.*;
8337import java.util.*;
8338P ROGRAMMATIC A CCESS TO S UBVERSION 191
8339public class DetectChanges
8340{
8341public static void main(String[] args)
8342throws SVNException
8343{
8344String reposUrl = "http: //svn.collab.net/repos/svn";
8345SVNURL url = SVNURL.parseURIEncoded(reposUrl);
8346DAVRepositoryFactory.setup();
8347SVNRepository repository = SVNRepositoryFactory.create(url);
8348long lastSeenRevision = repository.getLatestRevision();
8349while(true) {
8350long latestRevision = repository.getLatestRevision();
8351if(latestRevision != lastSeenRevision) {
8352displayChanges(lastSeenRevision + 1,
8353latestRevision, repository);
8354lastSeenRevision = latestRevision;
8355}
8356pause(60);
8357}
8358}
8359private static void displayChanges(long startRev, long endRev,
8360SVNRepository repository)
8361throws SVNException {
8362String[] targetPaths = { "/" } ;
8363List < SVNLogEntry > entries = new ArrayList < SVNLogEntry > ();
8364repository.log(targetPaths, entries, startRev,
8365endRev, false, false);
8366for (SVNLogEntry entry : entries) {
8367System.out.println("New revision " + entry.getRevision()
8368+ " by " + entry.getAuthor());
8369System.out.println("Log message: " + entry.getMessage());
8370}
8371}
8372private static void pause(int seconds) {
8373try {
8374Thread.sleep(seconds * 1000);
8375} catch (InterruptedException e) {
8376// Do nothing
8377}
8378}
8379}
8380java/DetectChanges.java
8381Instead of simply printing the log message, you could modify
8382the program to send emails, run build scripts, or whatever
8383else is useful.
8384Managing a Working Copy
8385JavaSVN lets you access a working copy in the same way
8386as the svn command-line tool. In particular, the SVNWCClient
8387class provides doXYZ () methods that mirror the command line
8388P ROGRAMMATIC A CCESS TO S UBVERSION 192
8389client. For example, we can use the doInfo () method to mimic
8390the svn info command:
8391import org.tmatesoft.svn.core.*;
8392import org.tmatesoft.svn.core.wc.*;
8393import java.io.File;
8394public class WorkingCopyInfo
8395{
8396public static void main(String[] args)
8397throws SVNException
8398{
8399File workingCopyRoot = new File("c: \\ work \\ subversion");
8400SVNWCClient wcClient = new SVNWCClient(null, null);
8401SVNInfo info = wcClient.doInfo(workingCopyRoot,
8402SVNRevision.WORKING);
8403System.out.println("Working Copy Info for " +
8404workingCopyRoot);
8405System.out.println("URL: " +
8406info.getURL());
8407System.out.println("Repository root: " +
8408info.getRepositoryRootURL());
8409System.out.println("Last Changed Author: " +
8410info.getAuthor());
8411System.out.println("Last Changed Rev: " +
8412info.getCommittedRevision());
8413System.out.println("Last Changed Date: " +
8414info.getCommittedDate());
8415System.out.println("URL: " +
8416info.getURL());
8417}
8418}
8419java/WorkingCopyInfo.java
8420Running this example will produce output similar to the reg-
8421ular svn info :
8422Working Copy Info for c: \ work \ subversion
8423URL: http://svn.collab.net/repos/svn/trunk/subversion
8424Repository root: http://svn.collab.net/repos/svn
8425Last Changed Author: mbk
8426Last Changed Rev: 19040
8427Last Changed Date: Sun Mar 26 08:26:13 MST 2006
8428URL: http://svn.collab.net/repos/svn/trunk/subversion
8429SVNWCClient will let you perform operations including add,
8430delete, lock and unlock, but you need to use the SVNCom-
8431mitClient class to commit changes from a working copy to the
8432repository.
8433Hopefully this tour of some of JavaSVN’s functionality will give
8434you ideas for embedding Subversion support into your own
8435applications. If you’re not coding in Java, remember there are
8436plenty of other language options too.
8437A DVANCED R EPOSITORY M ANAGEMENT 193
8438D.2 Advanced Repository Management
8439When setting up Subversion within an organization, a com-
8440mon question is “How many repositories should I create?â€
8441Our advice is to create only one repository until you have a
8442concrete need for more. We take this approach because it’s
8443easy to split an existing repository into two should the need
8444arise. The more repositories you have, the more administra-
8445tion will be required backing them up, managing users, and
8446so on. Remember that it’s not the end of the world if you cre-
8447ate multiple repositories and eventually need to merge them,
8448because Subversion has good support for splitting, merging,
8449and reorganizing repositories. This section covers exactly how
8450to perform these advanced repository operations.
8451Splitting a Repository
8452First, make sure you tell everyone you’re going to split the
8453repository. The ideal situation is one in which everyone can
8454check in, go home for the night, leave you to organize stuff,
8455and then come in the next day and start on something fresh.
8456If people can’t commit all their changes you may need to help
8457them relocate 1 their working copy once you’ve finished the
8458split. Once everyone’s committed their changes, close down
8459network access to your repository to be sure no one can com-
8460mit further changes. This might be overkill depending on your
8461situation, but it’s nice to be safe.
8462Next, back up your repository using svnadmin dump to create a
8463dump file, as described in Section A.6, Backing Up Your Repos-
8464itory, on page 170. Make sure you perform a complete dump,
8465not an incremental. A dump file is a portable representation
8466of the Subversion repository which we can use to recreate the
8467repository elsewhere.
8468home > svnadmin dump /home/svnroot/log4rss > log4rss.dump
8469* Dumped revision 0.
8470* Dumped revision 1.
8471: : :
8472* Dumped revision 37.
8473* Dumped revision 38.
84741 The
8475svn switch command includes the --relocate option that can match up
8476an old working copy with a new server location.
8477A DVANCED R EPOSITORY M ANAGEMENT 194
8478We’re going to load the dump file into a new repository, which
8479you should create and initialize:
8480home > mkdir tools-repos
8481home > svnadmin create tools-repos
8482The dump file contains complete history of all files within your
8483repository. For the new tools repository we’re only interested
8484in a particular path within the repository, log4rss/trunk/tools .
8485Use the svndumpfilter command to select just the directories
8486you wish to move to the new repository, then pipe its output
8487into the svnadmin load command.
8488home > cat log4rss.dump \
8489| svndumpfilter include log4rss/trunk/tools \
8490| svnadmin load tools-repos
8491Including prefixes:
8492' /log4rss/trunk/tools '
8493Revision 0 committed as 0.
8494Revision 1 committed as 1.
8495Revision 2 committed as 2.
8496: : :
8497<<< Started new transaction, based on original revision 38
8498------- Committed revision 38 >>>
8499svndumpfilter will be quite verbose, listing information about
8500the items included in the filter and the items which were
8501dropped. Now the new tools-repos repository contains just
8502the tools directory.
8503At this point you can make the new repository available and
8504tell developers where to find it. It’s probably also wise to
8505delete the log4rss/trunk/tools directory from the original reposi-
8506tory, just so people can’t accidentally use the old stuff. Sub-
8507version doesn’t have an “obliterate†command so the tools
8508directory is still using space in the old repository—if this is
8509an issue you’ll need to consider loading your dump file into
8510a new repository using an “exclude†command to weed out
8511the directory you no longer want. In most cases this isn’t an
8512issue, but if your repository contains lots of large files it might
8513pay to do a little housekeeping.
8514Merging Two Repositories
8515In some cases you might wish to merge two existing reposito-
8516ries. An example of this could be two separate project teams
8517merging into one, or a new project team taking over an exist-
8518A DVANCED R EPOSITORY M ANAGEMENT 195
8519ing codebase and wanting to use their own repository to man-
8520age the code.
8521Merging one repository into another is as simple as creating
8522a dump of the “donor†repository and using svnadmin load to
8523load the dump into the target repository. The load process
8524will replay each action that took place in the old repository
8525and although revision numbers won’t match your history will
8526be preserved.
8527This kind of merging will only work when the two reposito-
8528ries have different directory structures—if any directories are
8529shared by the two repositories the load will fail. To get around
8530this, use the --parent-dir option to load into a different location.
8531For example, we can load a dump of the Log4RSS repository
8532into itself in a new merged directory:
8533svnroot > svn mkdir file:///home/svnroot/log4rss/merge \
8534-m "Create merge directory"
8535Committed revision 36.
8536svnroot > svnadmin load --parent-dir merge log4rss < log4rss.dump
8537<<< Started new transaction, based on original revision 1
8538* adding path : merge/trunk ... done.
8539------- Committed new rev 37 (loaded from original rev 1) >>>
8540: : :
8541<<< Started new transaction, based on original revision 25
8542* editing path : merge/trunk/build.xml ... done.
8543------- Committed new rev 61 (loaded from original rev 25) >>>
8544In the above session snippet, you can see that the load com-
8545mand created revision 61 from an original revision 25, and
8546that instead of editing trunk/build.xml , merge/trunk/build.xml was
8547used instead, thus avoiding a conflict with the files already in
8548the repository.
8549Organizing a Repository
8550After merging two repositories you’ll probably want to reor-
8551ganize, especially if you used the --parent-dir option to avoid
8552conflicts. You might also want to rearrange a repository for
8553other reasons—maybe the repository has been around for a
8554while and isn’t really structured as you’d like. Fortunately
8555Subversion is great at moving things around.
8556Before moving directories in Subversion, make sure all your
8557users have checked in their changes. After a significant repos-
8558itory reorganization it’s often easier to check out a fresh work-
8559A DVANCED R EPOSITORY M ANAGEMENT 196
8560ing copy than try to update to the latest version. For this rea-
8561son you might want to reorganize at the weekend or after work
8562one evening.
8563Using repository URLs rather than working copy paths as
8564arguments to svn mv means the moves occur instantly on the
8565server. This is often important if you’re juggling large directo-
8566ries full of files.
8567We recommend using a graphical client such as TortoiseSVN
8568for large repository reorganizations, simply because it’s much
8569easier to keep track of the directory structure. The Tortoise
8570repository browser allows you to drag and drop files and direc-
8571tories to move them—very convenient indeed!
8572Appendix E
8573Command Summary and
8574Recipes
8575E.1 Subversion Command Summary
8576Most Subversion commands have common options, which we
8577list first in order to avoid repeating them for each command.
8578If you’re unsure which options a particular command accepts,
8579just run svn help command for a quick summary.
8580Common options:
8581--targets list Read in list and interpret it as a list of argu-
8582ments on which to operate.
8583--non-recursive, -N Operate on a single directory only; don’t try to
8584process subdirectories.
8585--verbose, -v Print additional information.
8586--quiet, -q Print as little as possible.
8587--username name Specify the name to be used when connecting
8588and authorizing.
8589--password pswd Specify the password to be used.
8590--no-auth-cache Do not cache authentication tokens.
8591--non-interactive Do not prompt for extra information.
8592--config-dir dir Read user configuration from dir.
8593--editor-cmd cmd Use cmd as log message editor.
8594S UBVERSION C OMMAND S UMMARY 198
8595svn add
8596Add names of files and directories to version control. They will be
8597added to the repository in the next commit.
8598svn add path...
8599Options:
8600--auto-props Automatically set properties on files when adding them.
8601--no-auto-props Disable automatic property setting.
8602svn blame (also known as ann, annotate, praise)
8603Show revision and author information for each line of a file
8604svn blame target...
8605Options:
8606--revision, -r rev If specified as a single revision rev, shows blame informa-
8607tion for the targets at revision rev. If specified as a revi-
8608sion range rev1:rev2, shows blame information for the
8609targets at revision rev2, but examines revisions only as
8610far back as rev1 (for this to be useful, rev1 should be less
8611than rev2).
8612svn cat
8613Output the contents of specified files or URLs.
8614svn cat target...
8615Options:
8616--revision, –r rev Output the contents of target at revision rev.
8617svn checkout (also known as co)
8618Check out a working copy from a repository.
8619svn checkout url... path
8620Checks out the given URLs. With no path argument, checks out into
8621local directories named using the base names of the URLs. If path is
8622given with one URL argument, checks out into path. If path is given
8623with multiple URL arguments, checks out into subdirectories of path
8624named for the base names in the urls.
8625Options:
8626--revision, -r rev The revision to check out.
8627S UBVERSION C OMMAND S UMMARY 199
8628svn cleanup
8629Clean up the working copy, removing locks, resuming unfinished
8630operations, etc.
8631svn cleanup path...
8632svn commit (also known as ci)
8633Send changes from your working copy to the repository.
8634svn commit path...
8635Options:
8636--message, –m msg Use msg as the commit log message.
8637--file, –F file Use the contents of file as the commit log message.
8638--no-unlock Do not release locks during the commit.
8639svn copy (also known as cp)
8640Duplicate something in working copy or repository, remembering
8641history.
8642svn copy src dest
8643src and dest can each be either a working copy (WC) path or a URL.
8644src dest Effect...
8645WC WC Copy and schedule for addition (with history).
8646WC URL Immediately commit a copy of WC to URL.
8647URL WC Check out URL into WC, schedule for addition.
8648URL URL Complete server-side copy; used to branch and tag.
8649Options:
8650--revision, -r rev The revision of src to copy. Only makes sense if src is a
8651repository URL.
8652svn delete (also known as del, remove, rm)
8653Remove files and directories from version control.
8654svn delete target...
8655Deletes files and directories from the repository. If target is a work-
8656ing copy file or directory, it is removed from the working copy and
8657scheduled for deletion at the next commit. If target is a repository
8658URL, it is deleted from the repository via an immediate commit.
8659Options:
8660--message, –m msg Use msg as the commit log message.
8661--file, –F file Use the contents of file as the commit log message.
8662S UBVERSION C OMMAND S UMMARY 200
8663svn diff (also known as di)
8664Display the differences between two paths.
8665svn diff -r rev1 : rev2 target...
8666svn diff oldurl newurl
8667In the first form, display changes made to target between revisions
8668rev1 and rev2. Targets may be working copy paths or URLs.
8669In the second form, display the differences between the HEAD revi-
8670sions of oldurl and newurl.
8671Options:
8672--old arg Use arg as the older target.
8673--new arg Use arg as the newer target.
8674svn export
8675Create an unversioned copy of a tree.
8676svn export -r rev URL path
8677Exports a clean directory tree from the repository specified by URL,
8678at revision rev if it is given, otherwise at HEAD, into path. If path is
8679omitted the last component of the URL is used as the local directory
8680name.
8681Options:
8682--revision, -r rev Export from the repository at revision rev.
8683--native-eol style Use a different end-of-line marker than the standard
8684system marker for files with a native svn:eol-style prop-
8685erty. style must be one of LF , CR , or CRLF .
8686svn import
8687Commit an unversioned file or tree into the repository.
8688svn import path URL
8689Recursively commit a copy of path to URL. If path is omitted, the
8690current directory is assumed. Parent directories are created as nec-
8691essary in the repository.
8692Options:
8693--auto-props Automatically set properties on files when importing
8694them.
8695--no-auto-props Disable automatic property setting on imported files.
8696S UBVERSION C OMMAND S UMMARY 201
8697svn info
8698Display information about a file or directory.
8699svn info path...
8700Print information about each path.
8701Options:
8702--recursive, -r Descend recursively.
8703svn list (also known as ls)
8704List directory entries in the repository.
8705svn list target...
8706List each target file and the contents of each target directory as they
8707exist in the repository. If target is a working copy path, the corre-
8708sponding repository URL will be used.
8709Options:
8710--verbose, -v Show extra information about each directory entry.
8711svn lock
8712Lock files so that other users cannot commit changes.
8713svn lock target
8714Communicates with the repository server to obtain a lock on one or
8715more working copy files. Once locked, other users cannot commit
8716changes to the files unless the lock is released or broken.
8717Options:
8718--message, –m msg Use msg as the lock information message.
8719--force Force the lock to succeed by stealing the lock from
8720another user or working copy.
8721svn log
8722Show the log messages for a set of revisions and/or files.
8723svn log target
8724Print the log messages for a local path or repository URL. For a local
8725path the default revision range is BASE:1, and for a URL the default
8726revision range is HEAD:1.
8727S UBVERSION C OMMAND S UMMARY 202
8728Options:
8729--revision, -r rev If rev is a single revision, show the log entry only for
8730that revision. If rev is a revision range, show only the
8731log entries for those revisions.
8732--verbose, -v Print all affected paths with each log message.
8733--stop-on-copy Do not cross copies while traversing history (useful
8734for determining the start point of a branch).
8735svn merge
8736Apply the differences between two sources to a working copy path.
8737svn merge sourceURL1 @rev1 sourceURL2 @rev2 wcpath
8738svn merge sourceWCPATH1@ rev1 sourceWCPATH2@ rev1 wcpath
8739svn merge -r rev1 : rev2 SOURCE wcpath
8740In the first form, the source URLs are specified at revisions rev1
8741and rev2. These are the two sources to be compared. The revisions
8742default to HEAD if omitted.
8743In the second form, the URLs corresponding to the source working
8744copy paths define the sources to be compared. The revisions must
8745be specified.
8746In the third form, SOURCE can be a URL or working copy item, in
8747which case the corresponding URL is used. This URL is compared as
8748it existed between revisions rev1 and rev2.
8749wcpath is the working copy path that will receive the changes. If
8750wcpath is omitted, a the current directory is assumed, unless the
8751sources have identical basenames that match a file within the cur-
8752rent directory, in which case the differences will be applied to that
8753file.
8754Options:
8755--diff3-cmd cmd Use cmd as merge command.
8756--ignore-ancestry Ignore ancestry when calculating merges.
8757svn mkdir
8758Create a new directory under version control.
8759svn mkdir target...
8760Each directory specified by a working copy path is created locally and
8761scheduled for addition upon the next commit. Each directory speci-
8762fied by a URL is created in the repository via an immediate commit.
8763In both cases, all the intermediate directories must already exist.
8764S UBVERSION C OMMAND S UMMARY 203
8765svn move (also known as mv, rename, ren)
8766Move and/or rename something in working copy or repository.
8767svn move src dest
8768src and dest must both be either working copy paths or repository
8769URLs. In the working copy, the move is performed and the new
8770location scheduled for addition. For repository URLs, a complete
8771server-side rename is performed immediately.
8772Options:
8773--revision, -r rev Use revision rev of the source when performing the move.
8774svn propdel (also known as pdel, pd)
8775Remove property from files or directories.
8776svn propdel propname path...
8777Delete property propname from path in the local working copy.
8778svn propedit (also known as pedit, pe)
8779Edit property from files or directories.
8780svn propedit propname path...
8781Start an external editor, and edit propname on path in the local work-
8782ing copy.
8783svn propget (also known as pget, pg)
8784Print property values from files or directories.
8785svn propget propname path...
8786Print the contents of propname from each path. By default, Subver-
8787sion will add an extra newline to the end of the property values so
8788that the output looks pretty. Also, whenever there are multiple paths
8789involved, each property value is prefixed with the path with which it
8790is associated.
8791Options:
8792--strict Disable extra newlines and other beautifications (useful when
8793redirecting binary property values to a file).
8794S UBVERSION C OMMAND S UMMARY 204
8795svn proplist (also known as plist, pl)
8796List all properties on files or directories.
8797svn proplist path...
8798List properties on path.
8799Options:
8800--verbose, -v Print extra information.
8801--recursive, -R Descend recursively.
8802--revision, -r rev List properties defined in revision rev of path.
8803svn propset (also known as pset, ps)
8804Set a propery on files or directories.
8805svn propset propname propval path...
8806Set property propname to value propval on path. If propval is not
8807specified, you must use the -F option to specify a file whose contents
8808should be used as the property value.
8809Options:
8810--file, -F file Read the contents of file and use it as the property
8811value.
8812--recursive, -R Descend recursively.
8813--encoding enc Treat value as being in character set encoding enc.
8814svn resolved
8815Remove conflicted state on working copy files or directories.
8816svn resolved path...
8817Mark a file that previously contained conflicts as “resolved.†Note
8818that this command does not semantically resolve conflicts or remove
8819conflict markers; it merely removes the conflict-related artifact files
8820and allows path to be committed.
8821Options:
8822--recursive, -R Descend recursively.
8823S UBVERSION C OMMAND S UMMARY 205
8824svn revert
8825Restore pristine working copy file (undo most local edits).
8826svn revert path...
8827This command does not require network access and undoes any
8828changes you have made to path. It does not restore removed direc-
8829tories.
8830Options:
8831--recursive, -R Descend recursively.
8832svn status (also known as stat, st)
8833Print the status of working copy files and directories.
8834svn status path...
8835With no args, print only locally modified items (no network access).
8836With -u , add working revision and server out-of-date information.
8837With -v , print full revision information on every item.
8838The first six columns in the output are each one character wide.
8839First column: Says if item was added, deleted, or otherwise changed.
8840“ †No modifications.
8841A Added.
8842C Conflicted.
8843D Deleted.
8844G Merged.
8845I Ignored.
8846M Modified.
8847R Replaced.
8848X Item is unversioned, but is used by an externals definition.
8849? Item is not under version control.
8850! Item is missing (removed by non- svn command) or incomplete.
8851˜
8852Versioned item obstructed by some item of a different kind.
8853Second column: Modifications of a file’s or directory’s properties.
8854“ †No modifications.
8855C Conflicted.
8856M Modified.
8857Third column: Whether the working copy directory is locked.
8858“ †Not locked.
8859L Locked.
8860S UBVERSION C OMMAND S UMMARY 206
8861Fourth column: Scheduled commit will contain addition with his-
8862tory.
8863“ †No history scheduled with commit.
8864+ History scheduled with commit.
8865Fifth column: Whether the item is switched relative to its parent.
8866“ †Normal.
8867S Switched.
8868Sixth column: Lock token information (to show repository informa-
8869tion, use -u ).
8870“ †No lock token present, not locked in the repository.
8871K Lock token present, item locked in the repository.
8872O Item locked in the repository, lock token present in some other
8873working copy.
8874T Item locked in the repository, lock token present in working copy
8875but stolen by some other working copy.
8876B Item not locked in the repository, but broken lock token present
8877in working copy.
8878The out-of-date information appears in the eighth column (with -u ).
8879* A newer revision exists on the server.
8880“ †The working copy is up-to-date.
8881The remaining fields are variable width and delimited by spaces: the
8882working revision (with -u or -v ), the last-committed revision, and last-
8883committed author (with -v ). The working copy path is always the final
8884field, so it can include spaces.
8885Options:
8886--show-updates, -u Contact the server to display update information.
8887--verbose, -v Print extra information.
8888--non-recursive, -N Operate on single directory only.
8889--no-ignore Disregard default and svn:ignore property ignores.
8890S UBVERSION C OMMAND S UMMARY 207
8891svn switch (also known as sw)
8892Update the working copy to a different URL.
8893svn switch URL path
8894Update the working copy to mirror a new URL within the repository.
8895This behavior is similar to svn update and is the way to move a work-
8896ing copy to a branch or tag within the same repository.
8897Options:
8898--revision, -r rev Switch to revision rev.
8899--non-recursive, -N Operate on single directory only.
8900--diff3-cmd cmd Use cmd as merge command.
8901svn unlock
8902Unlock working copy files or repository URLs.
8903svn unlock target...
8904Release locks currently held on target so other users can commit
8905changes.
8906Options:
8907--force Break an existing lock on target, even if it is not owned by the
8908current working copy.
8909svn update (also known as up)
8910Bring changes from the repository into the working copy.
8911svn update path...
8912If no revision given, bring working copy up-to-date with HEAD revi-
8913sion. Otherwise synchronize working copy to revision given by -r .
8914For each updated item a line will start with a character reporting the
8915action taken. These characters have the following meaning:
8916A Added.
8917D Deleted.
8918U Updated.
8919C Conflict.
8920M Merged.
8921A character in the first column signifies an update to the actual file,
8922and updates to the file’s properties are shown in the second column.
8923R ECIPES 208
8924Options:
8925--revision, -r rev Update to revision rev.
8926--non-recursive, -N Operate on single directory only.
8927--diff3-cmd cmd Use cmd as merge command.
8928E.2 Recipes
8929Checking out............................................... Page 63
8930svn checkout URL path
8931Checking out a specific revision ........................ Page 63
8932svn checkout -r rev URL
8933Checking out a specific date............................. Page 63
8934svn checkout -r " { date } " URL
8935Finding out where a working copy came from......... Page 63
8936svn info path
8937Updating a working copy................................. Page 64
8938svn update
8939Updating specific items in a working copy............. Page 64
8940svn update path...
8941Adding files to the repository............................ Page 66
8942svn add path...
8943Setting a property on a file or directory ............... Page 67
8944svn propset propname propvalue path...
8945Editing a property on a file or directory ............... Page 67
8946svn propedit propname path...
8947Listing the properties on a file or directory ........... Page 67
8948svn proplist path...
8949Printing the contents of a property..................... Page 67
8950svn propget propname path...
8951Deleting a property ....................................... Page 68
8952svn propdel propname path...
8953Enabling keyword expansion for a file.................. Page 69
8954svn propset svn:keywords " keywords " file...
8955Ignoring certain files in a directory..................... Page 71
8956svn propedit svn:ignore path...
8957R ECIPES 209
8958Setting end-of-line style for a file....................... Page 72
8959svn propset svn:eol-style style path...
8960Setting the mime-type of file............................ Page 73
8961svn propset svn:mime-type mime-type path...
8962Marking a file executable................................. Page 74
8963svn propset svn:executable true path...
8964Copying a file or directory ............................... Page 76
8965svn copy source destination
8966Renaming a file or directory............................. Page 77
8967svn rename oldname newname
8968Moving a file or directory ................................ Page 77
8969svn move source destination
8970Showing changes to a file or directory ................. Page 80
8971svn diff path...
8972Comparing two revisions of a file ....................... Page 81
8973svn diff -r rev1 : rev2 file
8974Showing changes between a file and the latest revision in
8975the repository.............................................. Page 83
8976svn diff -r HEAD file...
8977Showing the most recent change to a file.............. Page 84
8978svn diff -r PREV:BASE file...
8979Creating a patch file ...................................... Page 85
8980svn diff > patchfile
8981Applying a patch file...................................... Page 85
8982patch -p0 -i patchfile
8983Discarding your changes in the face of a conflict..... Page 88
8984svn revert file...
8985svn update file...
8986Discarding someone else’s changes in the face of a con-
8987flict ......................................................... Page 90
8988cp file .mine file
8989svn resolved file
8990Marking a conflict resolved.............................. Page 90
8991svn resolved file...
8992R ECIPES 210
8993Checking in changes...................................... Page 91
8994svn commit -m " message "
8995Showing history for a file ................................ Page 91
8996svn log file
8997Showing recent activity in a directory ................. Page 93
8998svn log path | more
8999Showing detailed history for a file ...................... Page 93
9000svn log -v file...
9001Annotating files with author information.............. Page 94
9002svn blame file...
9003Reverting an already committed change............... Page 96
9004svn merge -r rev : rev-1 path...
9005Checking the working copy status...................... Page 98
9006svn status
9007Showing updates pending from the repository ........ Page 98
9008svn status --show-updates
9009Enabling locking on a file ............................... Page 101
9010svn propset svn:needs-lock true file...
9011svn commit -m "Enabled locking" file...
9012Obtaining a lock on a file................................ Page 102
9013svn lock file... -m " lock comment "
9014Examining lock information for a file ................. Page 103
9015svn info file... | grep Lock
9016Breaking another user’s lock on a file ................. Page 104
9017svn unlock --force URL
9018Stealing another user’s lock on a file.................. Page 105
9019svn lock --force file... -m " lock message "
9020Creating a release branch ............................... Page 116
9021svn copy \
9022svn://myserver/ project /trunk \
9023svn://myserver/ project /branches/ RB-x.y
9024R ECIPES 211
9025Checking out a release branch.......................... Page 117
9026cd work
9027svn checkout \
9028svn://myserver/ project /branches/ RB-x.y
9029Switching a working copy to a release branch........ Page 118
9030cd myproj
9031svn switch \
9032svn://myserver/ project /branches/RB- x.y
9033Switching a working copy back to the trunk ......... Page 118
9034cd myproj
9035svn switch svn://myserver/ project /trunk
9036Creating a release tag.................................... Page 119
9037svn copy \
9038svn://myserver/ project /branches/RB- x.y \
9039svn://myserver/ project /tags/REL- x.y
9040Checking out a release................................... Page 120
9041svn checkout \
9042svn://myserver/ project /tags/REL- x.y
9043Merging a simple bug fix from a release branch to the
9044trunk....................................................... Page 122
9045cd project
9046svn update
9047svn merge -r rev-1 : rev \
9048svn://myserver/ project /branches/RB- x.y
9049Creating a branch for a complex bug fix............... Page 123
9050svn copy \
9051svn://myserver/ project /branches/RB- x.y \
9052svn://myserver/ project /branches/BUG- track
9053svn copy \
9054svn://myserver/ project /branches/BUG- track \
9055svn://myserver/ project /tags/PRE- track
9056Checking out a bug fix branch.......................... Page 123
9057svn checkout \
9058svn://myserver/ project /branches/BUG- track
9059Tagging the end of a bug fix............................. Page 124
9060svn copy \
9061svn://myserver/ project /branches/BUG- track \
9062svn://myserver/ project /tags/POST- track
9063R ECIPES 212
9064Merging a complex bug fix to a release branch ....... Page 124
9065cd RB x.y
9066svn merge \
9067svn://myserver/ project /tags/PRE- track \
9068svn://myserver/ project /tags/POST- track
9069Creating experimental branches........................ Page 125
9070svn copy \
9071svn://.../trunk \
9072svn://.../branches/TRY- initials - mnemonic
9073Using an experimental branch.......................... Page 125
9074svn switch \
9075svn://.../branches/TRY- initials - mnemonic
9076Returning to the trunk .................................. Page 125
9077svn switch svn://.../trunk
9078Finding out when a branch was created............... Page 126
9079svn log --stop-on-copy \
9080svn://.../branches/ branch
9081Merging an experimental branch....................... Page 127
9082svn log --stop-on-copy \
9083svn://.../branches/TRY- initials - mnemonic
9084cd trunk-working-copy
9085svn merge \
9086-r branch-start-revision :HEAD \
9087svn://.../branches/TRY- initials - mnemonic
9088svn commit
9089Importing a project into the repository ............... Page 130
9090cd project
9091svn import svn://myserver/ project /trunk
9092Manually creating directories for a project ........... Page 130
9093svn mkdir svn://myserver/ project /
9094svn mkdir svn://myserver/ project /trunk
9095svn mkdir svn://myserver/ project /tags
9096svn mkdir svn://myserver/ project /branches
9097Importing third-party code.............................. Page 145
9098svn import vendor-tree \
9099svn://.../vendorsrc/ vendor / product /current
9100R ECIPES 213
9101Tagging a vendor drop ................................... Page 146
9102svn copy \
9103svn://.../vendorsrc/ vendor / product /current \
9104svn://.../vendorsrc/ vendor / product / version
9105Loading a new vendor drop.............................. Page 147
9106svn load dirs.pl \
9107svn://.../vendorsrc/ vendor / product \
9108current vendor-tree
9109Using vendor code in a project ......................... Page 148
9110svn copy \
9111svn://.../vendorsrc/ vendor / product / ver \
9112svn://.../ project /trunk/vendor/ product
9113Upgrading vendor code in a project.................... Page 149
9114svn merge \
9115svn://.../vendorsrc/ vendor / product / oldver \
9116svn://.../vendorsrc/ vendor / product / newver \
9117vendor/ product
9118Starting svnserve on Windows.......................... Page 153
9119start svnserve --daemon --root repos-dir
9120Starting svnserve on Unix............................... Page 153
9121svnserve --daemon --root repos-dir
9122Creating a full backup of your repository ............. Page 170
9123svnadmin dump repos > dumpfile
9124Creating an incremental backup of your repository . Page 171
9125svnadmin dump --incremental \
9126--revision rev1 : rev2 repos
9127Appendix F
9128Other Resources
9129There are a wealth of Subversion and version control related
9130resources available out there—here are just a few to get you
9131started.
9132F.1 Online Resources
9133Subversion Home Page .... http://subversion.tigris.org/
9134The official Subversion web site is an excellent resource for anyone
9135getting started with Subversion. The site contains all sorts of doc-
9136umentation, including the excellent Subversion FAQ that contains
9137common questions and answers. The project links page is a great
9138place to find Subversion-related software, plug-ins, articles, and doc-
9139umentation.
9140You can also join the Subversion users’ mailing list; just send an
9141e-mail to users-subscribe@subversion.tigris.org . The list is
9142the place to ask questions and is populated by some very friendly
9143people, including Subversion’s core developers.
9144Pragmatic Programmers. ..
9145... http://www.pragmaticprogrammer.com/titles/svn/
9146The companion web site for this book where you’ll find code samples,
9147errata, and links to other pragmatic things.
9148Subversion Book............. http://svnbook.red-bean.com/
9149The official Subversion book is available online and in print form
9150and contains in-depth discussion of even Subversion’s most esoteric
9151features.
9152Better SCM.................. http://better-scm.berlios.de/
9153The Better SCM project aims to promote alternatives to CVS and
9154includes a comparison between various version control systems.
9155B IBLIOGRAPHY 215
9156CM Crossroads............... http://www.cmcrossroads.com/
9157Configuration Management is a larger topic than version control but
9158usually requires decent version control to achieve its aims. Through-
9159out the book we’ve mentioned the various “SCM Patterns†by name,
9160so if you’d like to find out about the patterns in more detail or are
9161interested in how source code, builds, projects, and releases are
9162organized, this site contains articles and discussion groups that may
9163interest you.
9164F.2 Bibliography
9165[BA03] Stephen P. Berczuk and Brad Appleton. Soft-
9166ware Configuration Management Patterns: Effec-
9167tive Teamwork, Practical Integration. Addison-Wes-
9168ley, 2003.
9169[Cla04] Mike Clark. Pragmatic Project Automation. How to
9170Build, Deploy, and Monitor Java Applications. The
9171Pragmatic Programmers, LLC, Raleigh, NC, and
9172Dallas, TX, 2004.
9173[CSFP] Ben Collins-Sussman, Brian W. Fitzpatrick, and
9174C. Michael Pilato. Version Control with Subversion.
9175[HT03] Andrew Hunt and David Thomas. Pragmatic Unit
9176Testing In Java with JUnit. The Pragmatic Pro-
9177grammers, LLC, Raleigh, NC, and Dallas, TX,
91782003.
9179[HT04] Andrew Hunt and David Thomas. Pragmatic Unit
9180Testing In C# with NUnit. The Pragmatic Program-
9181mers, LLC, Raleigh, NC, and Dallas, TX, 2004.
9182Index
9183Symbols
9184<<<< conflict marker, 88
9185A
9186Access rights, 57, 59, 155
9187securing Subversion, 163
9188svnserve command, 163
9189svn add command, 66, 198
9190--non-recursive option, 66
9191Alias module, 16
9192svn ann command, 94
9193svn annotate command, 94
9194Ant script, 11
9195Apache web server
9196install on Linux, 162
9197mod authz svn , 159
9198mod dav svn , 59, 159, 162
9199security, 165–168
9200virtual directories, 110
9201on Windows, 151, 158
9202Appleton, Brad, vi, 26
9203Artifact (store or not), 13
9204Atomic commit, 7
9205Audit functionality, 1
9206$ Author $ keyword, 69
9207Autoprops, 74, 150
9208B
9209Backing up (repository), 170–173
9210BASE revision, 81
9211Berczuk, Stephen, 26
9212Binary vs. text files, 73
9213Binary files (locking), 99–106
9214Binary libraries, 141
9215svn blame command, 94, 198
9216-r option, 95
9217Branch, 19–22
9218to avoid code freeze, 19
9219as a copy, 76
9220creating, 113
9221creating retrospectively, 116n
9222experimental, 114, 124
9223and externals, 140
9224merge, 22, 122, 124
9225naming, 115f
9226release, 107, 114, 115
9227trunk, 19, 37, 107
9228Bug fix
9229identifying revision containing,
9230121, 122
9231merging, 22, 122, 124
9232in release branch, 121
9233tagging, 114
9234Build
9235and environment variables,
9236144
9237organizing paths for, 143
9238build.xml , 11
9239BUILDING file, 132
9240sample, 133f
9241C
9242Carriage return (EOL style), 72
9243svn cat command, 198
9244Check out, 12
9245svn checkout command, 39, 45,
924662, 198
9247-r option, 63
9248ˇ
9249Cibej, Branko, vi
9250svn cleanup command, 199
9251Client/server access to
9252repository, 10
9253Code freeze, avoiding, 19
9254CodeHaus, 85, 145, 145n
9255Command line, 29, 30
9256Commit, 14
9257atomic nature of, 7
9258e-mail notification on, 186
9259SVN COMMIT COMMAND 217 F ILE
9260sequence of commands to
9261follow, 91
9262svn commit command, 41, 66,
926376, 91, 199
9264-m option, 41, 91
9265COMMITTED revsion, 81
9266Compiler, finding header files,
9267143
9268Configuration file, 58, 75
9269Configuration Management, 26
9270Conflict
9271during merge, 24, 48
9272graphical front end, 183
9273markers, 88
9274resolution, 23, 87
9275Conventions, typographic, viii
9276svn copy command, 75, 199
9277to create release branch, 119
9278svnadmin create command, 34
9279Creating a project, 34, 128–140
9280Creating a repository, 33
9281CVS
9282.cvsignore equivalent in
9283Subversion, 71
9284keywords ( $Log$ etc), 68, 70
9285migrating to Subversion,
9286174–177
9287modules are Subversion
9288directories, 16
9289vs. Subversion, 6
9290version numbering, 17
9291cvs2svn command, 175
9292D
9293data/ directory, 133
9294$ Date $ keyword, 68
9295Date, accessing revision by, 81
9296DAV, 161
9297db/ directory, 133
9298svn delete command, 199
9299DeltaV, 161
9300Developers
9301experimenting in branches,
9302114, 124
9303misunderstandings, 49
9304sharing code, 1, 24
9305svn diff command, 40, 80, 85,
9306200
9307binary file, 73
9308--diff-cmd option, 41
9309-r option, 46, 82
9310--diff-cmd option
9311to svn diff , 41
9312Difference
9313conflict resolution, 23
9314determining, 80
9315and file type, 73
9316merging, 22, 122, 124
9317and patch, 85
9318stored in repository, 16
9319unified format, 40
9320between versions, 82
9321between working copy and
9322repository, 83
9323Directory
9324for branches and tags, 108
9325Jakarta conventions for laying
9326out, 131
9327linking with svn:externals , 137
9328in repository, 16
9329structure in project, 131, 134f
9330top-level in project, 132
9331versioning, 7
9332doc/ directory, 132
9333Download Subversion, 33
9334dumpfile, 170
9335E
9336Eclipse IDE, 144, 185
9337Editing, 23, 39
9338EDITOR environment variable, 43
9339Editor, choosing, 43
9340E-mail notification of commit,
9341186
9342End-of-line style, 72
9343Environment variable
9344in build, 144
9345EDITOR , 43
9346SVN EDITOR , 43
9347VISUAL , 43
9348Executable file, 74
9349svn export command, 200
9350External repositories, 109, 137
9351F
9352File
9353adding to repository, 66
9354changing contents, 39
9355checked out read-only, 23
9356commiting changes, 91
9357copy, 75
9358difference with repository, 83
9359F ILE - SPECIFIC VERSION NUMBERING 218 L OCKING
9360editing, 23, 39
9361entity in repository, 15
9362executable, 74
9363generated, 13
9364header (include), 142
9365ignoring, 71
9366locking, 99–106
9367mime type of, 73
9368move (rename), 77
9369top-level in project, 132
9370unmergeable, 99
9371versioning, 7
9372File-specific version numbering,
937316
9374Firewall, 153, 154
9375using HTTP to minimize holes,
937661
9377Framework as separate project,
9378129
9379Fred and Wilma, 2, 22
9380G
9381Gemkow, Steffen, vi
9382Generated file (store or not), 13
9383GLOSSARY file, 132
9384GUI front end, 178
9385H
9386HEAD revision, 81
9387Header (include) files, 142
9388$ HeadURL $ keyword, 69
9389Hook scripts, 168
9390http protocol, 59, 157
9391I
9392$ Id $ keyword, 69
9393IDE
9394configuration variables, 144
9395Eclipse, 144, 185
9396IntelliJ IDEA, 185
9397method-level check in, 15n
9398organizing libraries for, 143
9399Subversion integration, 185
9400Visual Studio, 185
9401Ignoring files, 71
9402svn import command, 36, 129,
9403200
9404-m option, 36
9405--no-auto-props option, 150
9406Import into repository, 36
9407existing source, 129
9408manual directory creation, 130
9409third-party source, 145
9410svn info command, 63, 103,
9411201
9412Install Subversion, 28, 151–173
9413firewall issues, 153, 154
9414HTTP protocol, 157
9415on Linux, 152
9416svn+ssh protocol, 154
9417svnserve , 153
9418on Windows, 151
9419as Windows service, 153
9420IntelliJ IDEA IDE, 185
9421Internet, access repository over,
942261
9423J
9424Java (Jakarta) conventions, 131
9425jMock library, 145, 149
9426K
9427Keyword
9428$ Author $, 69
9429$ Date $, 68
9430$ HeadURL $, 69
9431$ Id $, 69
9432$ LastChangedBy $, 69
9433$ LastChangedDate $, 68
9434$ LastChangedRevision $, 68
9435$ Rev $, 68
9436$ Revision $, 68
9437$ URL $, 69
9438Keyword expansion, 68
9439in third-party source, 150
9440L
9441$ LastChangedBy $ keyword, 69
9442$ LastChangedDate $ keyword, 68
9443$ LastChangedRevision $
9444keyword, 68
9445lib/ directory, 142
9446Line feed (EOL style), 72
9447Linker, finding libraries, 143
9448Linux installation, 152
9449and Apache, 157, 162
9450setting groups and sticky bits,
9451155
9452svn list command, 201
9453svn lock command, 100, 201
9454Locked-out of repository, 155
9455Locking, 22, 99–106
9456L OG 219 P ROJECT
9457breaking, 104
9458enabling, 101–102
9459hook scripts, 105
9460importance of, 100–101
9461optimistic, 23
9462strict, 23, 86
9463token, 103, 104, 206
9464unmergeable files, 106
9465when to use, 106
9466Log
9467of changes, 1, 91
9468making messages meaningful,
946992
9470svn log command, 41, 91, 101,
9471201
9472-r option, 93
9473--stop-on-copy option, 126
9474-v option, 94
9475--verbose option, 42
9476$Log$ keyword (not supported), 70
9477svn ls command, 177
9478M
9479-m option
9480to svn commit , 41, 91
9481to svn import , 36
9482Merge, 22, 64
9483automatic on update, 23
9484bug fix, 122, 124
9485changes, 44, 47
9486conflict, 24, 48, 87
9487graphical, 184
9488svn merge command, 97, 124,
9489202
9490to revert changes, 96
9491Metadata
9492project, stored, 11
9493Method
9494IDE versioning of, 15n
9495Migrating CVS or RCS to
9496Subversion, 174–177
9497Mime type, 73
9498svn mkdir command, 130, 202
9499mod authz svn , 159
9500mod dav svn , 59, 159, 162
9501svn move command, 77, 203
9502refactor repository, 109
9503Multiple projects, 108, 128, 135
9504using externals, 137
9505über project technique, 136
9506Multiple repositories, 109
9507N
9508Naming projects, 128
9509Naming tags and branches, 115f,
9510123
9511Network, 55–61
9512choosing right type, 60
9513firewall, 153, 154
9514offline access, 11
9515to access repository, 10
9516repository URLs, 79
9517scheme, 55
9518with syn+ssh , 154–157
9519with synserve, 153–154
9520VPN, 10
9521NFS (Network File System), 35
9522--no-auto-props option
9523to svn import , 150
9524--non-recursive option
9525to svn add , 66
9526Norddahl, Magnus, 153
9527Notepad editor, 43
9528NUnit (example of library), 141
9529O
9530Offline access, 11
9531Open-source
9532free repositories for, 85
9533Optimistic locking, 23
9534P
9535Password, 164
9536patch command, 85
9537Path names, relative in build, 143
9538philosophy, 53
9539plink.exe , 58
9540Pragmatic Starter Kit, vi, 53
9541svn praise command, 94
9542PREV revsion, 81
9543Project, 15
9544characteristics, 128
9545code freeze (avoiding), 19
9546communication, 49
9547creating, 34, 128–140
9548directory structure, 131, 132,
9549134f
9550importing, 36
9551incorporate third-party code,
9552148
9553multiple ˜ s, 108
9554release, 115, 119
9555P ROMPT 220 SSH
9556sharing code, 24
9557subprojects, 129
9558tagging latest build, 113
9559Prompt, 29, 31
9560svn propdel command, 68, 203
9561svn propedit command, 67,
9562203
9563Properties, 66–75
9564naming, 67
9565setting automatically, 74, 150
9566svn:eol-style , 72
9567svn:executable , 74
9568svn:externals , 137
9569svn:ignore , 71, 135
9570svn:keywords , 68, 69, 150
9571svn:mime-type , 66, 73
9572versioning, 7
9573svn propget command, 68, 203
9574svn proplist command, 68,
9575204
9576svn propset command, 67, 204
9577Putty (SSH on Windows), 58, 154,
9578186
9579R
9580-r option
9581to svn blame , 95
9582to svn checkout , 63
9583to svn diff , 46, 82
9584to svn log , 93
9585r1:r2, 81
9586Rasmussen, Robert, vi
9587RCS, migrating to Subversion,
9588174–177
9589README file, 132
9590Recipes, 208
9591Refactoring, 75, 77
9592Release
9593fixing bugs in, 121
9594generating, 119
9595Remote file system, 35
9596Removing a change, 95
9597svn rename command, 77
9598Repositories
9599directories in, 129
9600Repository
9601access rights, 57, 59
9602add file to, 66
9603backing up, 170–173
9604creating, 33
9605defined, 9
9606directories in, 16
9607external, 137
9608files stored in, 15
9609free for open-source, 85
9610importing into, 36, 145
9611over Internet, 61
9612locking, 22
9613migrating from CVS or RCS,
9614174–177
9615multiple ˜ ies, 109
9616˜ -wide numbering, 16, 41
9617projects in, 15, 108, 128
9618stores differences, 16
9619tag, 18
9620updating, 41
9621URL, 36, 37, 55, 79
9622wedged, 155
9623what to store in, 11–12
9624Reserved checkout (Subversion
96251.2), 86
9626svn resolved command, 90,
9627204
9628$ Rev $ keyword, 68
9629svn revert command, 88, 95,
9630205
9631Revision
9632BASE, 81
9633COMMITTED, 81
9634by date, 81
9635HEAD, 81
9636identifiers, 80
9637mixed, 42, 112
9638PREV, 81
9639range, 81
9640$ Revision $ keyword, 68
9641--revision option
9642to svn switch , 118
9643Roberts, Mike, vi
9644Rupp, David, vi
9645S
9646Secure Socket Layer (SSL), 61
9647Security, 163–169
9648Shell, 29
9649--show-updates option
9650to svn status , 46, 98
9651Source code, 11
9652importing third party, 144
9653src/ directory, 133
9654SSH, 57
9655SSL (S ECURE S OCKET L AYER ) 221 T AG
9656key manager (SSHKeychain),
9657186
9658troubleshooting, 155
9659SSL (Secure Socket Layer), 61
9660Starter Kit, vi, 53
9661svn status command, 40, 45,
966298, 205
9663--show-updates option, 46,
966498
9665-u option, 46, 98
9666Sticky bit (Unix groups), 155
9667--stop-on-copy option
9668to svn log , 126
9669Strict locking, 23
9670Subversion
9671benefits, 6
9672command summary, 197–207
9673compared to CVS, 7
9674config file, 58, 75
9675download URL, 33
9676file locking, 99–106
9677free repositories, 85
9678hook scripts, 105
9679installation, 151–153
9680migrating from CVS or RCS,
9681174–177
9682offline access to, 11
9683philosophy of using, 53
9684recipes, 208
9685security, 163
9686third-party clients, 178
9687troubleshooting, 156, 157
9688user name, 57
9689versions, 34
9690svn command
9691--version option, 32
9692svn commands
9693add , 66, 198
9694ann , 94
9695annotate , 94
9696blame , 94, 198
9697cat , 198
9698checkout , 39, 45, 62, 198
9699cleanup , 199
9700commit , 41, 66, 76, 91, 199
9701copy , 75, 119, 199
9702delete , 199
9703diff , 40, 73, 80, 85, 200
9704export , 200
9705import , 36, 129, 200
9706info , 63, 103, 201
9707list , 201
9708lock , 100, 201
9709log , 41, 91, 101, 201
9710ls , 177
9711merge , 96, 97, 124, 202
9712mkdir , 130, 202
9713move , 77, 109, 203
9714praise , 94
9715propdel , 68, 203
9716propedit , 67, 203
9717propget , 68, 203
9718proplist , 68, 204
9719propset , 67, 204
9720rename , 77
9721resolved , 90, 204
9722revert , 88, 95, 205
9723status , 40, 45, 98, 205
9724switch , 117, 118, 120, 207
9725unlock , 104, 207
9726update , 44, 49, 64, 87, 207
9727svn protocol, 56
9728svn+ssh protocol, 57, 154
9729svn:eol-style property, 72
9730svn:executable property, 74
9731svn:externals property, 137
9732svn:ignore property, 71, 135
9733svn:keywords property, 68, 69,
9734150
9735svn:mime-type property, 66, 73
9736SVN EDITOR environment
9737variable, 43
9738svnadmin command
9739--version option, 32
9740svn load dirs.pl script, 147
9741SVN:Notify, 186
9742svnserve command, 56, 153, 163
9743--daemon option, 153
9744invoked by svn+ssh , 154
9745--root option, 110, 153
9746svn switch command, 117, 118,
9747120, 207
9748--revision option, 118
9749T
9750Tag, 18, 107, 112–113
9751bug fix, 114
9752as a copy, 76
9753making read-only, 113
9754naming, 115f
9755release, 114, 119
9756T EST CODE 222 W ORKING COPY
9757as slice through repository,
9758112
9759third-party source, 146
9760Test code, 135
9761Testsweet project, 176
9762Text vs. binary files, 73
9763Third-party, 141–150
9764binary libraries, 141
9765header (include) files, 142
9766import ˜ source, 145
9767including code in project, 148
9768modifying, 149
9769source code, 134, 144
9770tagging their release, 146
9771updating source, 146
9772version numbers, 142
9773what to include, 142
9774Time machine, 2
9775Tortoise
9776graphical merge, 184
9777TortoisePlink SSH client, 58
9778TortoiseSVN client, 178
9779Transactional commit, 7
9780Troubleshooting, 156, 157
9781Tunnel, 61
9782configuration, 58, 75
9783Tunnel over SSH, 57
9784Typographic conventions, viii
9785U
9786-u option
9787to svn status , 46, 98
9788¨
9789Uber project technique, 136
9790umask, 155
9791UNDO button, 1, 18
9792Undoing a change, 95
9793svn unlock command, 104, 207
9794Update, 14, 41
9795svn update command, 44, 64,
9796207
9797conflict and, 87
9798status flags, 49, 64
9799URL, 55
9800file://... , 37
9801http:// ..., 59
9802repository, 36, 37, 79
9803scheme, 55
9804svn:// ..., 56
9805svn+ssh:// ..., 57
9806$ URL $ keyword, 69
9807User name, 57, 164
9808connecting via SSH, 154
9809util/ directory, 134
9810V
9811-v option
9812to svn log , 94
9813vendor/ directory, 134, 142
9814vendorsrc/ directory, 134, 145
9815--verbose option
9816to svn log , 42
9817Version, 16
9818numbering, 16, 41
9819what gets ˜ ed, 7
9820--version option
9821to svn , 32
9822to svnadmin , 32
9823Version control
9824advantages, 1
9825philosophy, 53
9826Virtual Private Network (VPN), 10,
982761
9828VISUAL environment variable, 43
9829Visual Studio IDE, 185
9830W
9831WebDAV, 161
9832Wedged repository, 155
9833Wilma and Fred, 2, 22
9834Windows
9835installation, 151
9836Putty (SSH), 58, 154, 186
9837shell, 29
9838svnserve , 153
9839Visual Studio IDE, 185
9840Windows Explorer
9841adding Subversion to, 178
9842Working copy
9843checkout into, 62
9844definition, 12
9845difference with repository, 83
9846ignoring files, 71
9847location, 38
9848seeing what’s changed, 80
9849status of, 97