# PaCkAgE DaTaStReAm LNFsubversion-docs 1 11756 # end of header 07070100027250000081a4000017820000044e000000014b1d4576000004290000022d0000016a00000000000000000000001b00000000LNFsubversion-docs/pkginfo PKG=LNFsubversion-docs ARCH=i386 VERSION=1.6.6 MAXINST=1000 SERIALNUM=001 NAME=Subversion - documentation CATEGORY=development,utils,application EMAIL=developers@linofee.org VENDOR=LINOFEE, http://www.linofee.org BASEDIR=/usr/doc DESC=This package contains additional documentation for subversion like a html formatted Subversion book, best practice infos, HOWTOs and tools examples. Subversion is a concurrent version control system which enables one or more users to collaborate in developing and maintaining a hierarchy of files and directories while keeping a history of all changes. Subversion only stores the differences between versions, instead of every complete file. Subversion also keeps a log of who, when, and why changes occurred. As such it basically does the same thing CVS does (Concurrent Versioning System) but has major enhancements compared to CVS and fixes a lot of the annoyances that CVS users face. LICINFO=Subversion LICURL=http://subversion.tigris.org/project_license.html LICFILE=subversion.txt PSTAMP=idev20091207191206 CLASSES=none 0707010002724f000081a4000017820000044e000000014b1d457a00009bb00000022d0000016a00000000000000000000001a00000000LNFsubversion-docs/pkgmap : 1 11756 1 i pkginfo 1065 30565 1260209526 1 d none subversion 0755 bin bin 1 f none subversion/BUGS 0644 bin bin 107 9904 1127249608 1 f none subversion/CHANGES 0644 bin bin 161545 4728 1255623308 1 f none subversion/COMMITTERS 0644 bin bin 10964 3588 1232110285 1 f none subversion/HACKING 0644 bin bin 113 10488 1121977084 1 f none subversion/INSTALL 0644 bin bin 67415 40467 1244483735 1 f none subversion/README 0644 bin bin 2244 45546 1196408919 1 f none subversion/WritingChangeLogs.txt 0644 bin bin 9158 9663 1151009799 1 f none subversion/cvs-crossover-guide.html 0644 bin bin 26602 37963 1260209521 1 f none subversion/lj_article.txt 0644 bin bin 13988 543 1169554058 1 d none subversion/notes 0755 bin bin 1 f none subversion/notes/EuroOSCON-2005-vc-bof.txt 0644 bin bin 12611 48091 1212910340 1 f none subversion/notes/alternate-bdb-version 0644 bin bin 4147 35765 1140370184 1 f none subversion/notes/anchors_and_targets.txt 0644 bin bin 6911 10672 1064532772 1 f none subversion/notes/asp-dot-net-hack.txt 0644 bin bin 1473 179 1129756132 1 f none subversion/notes/assurance.txt 0644 bin bin 3975 20877 1067709195 1 f none subversion/notes/authz_policy.txt 0644 bin bin 7307 14366 1147674776 1 f none subversion/notes/autoversion-compatibility.txt 0644 bin bin 4835 56169 1043340094 1 f none subversion/notes/autoversioning-strategy.txt 0644 bin bin 13946 64668 1099674504 1 f none subversion/notes/changelist-design.txt 0644 bin bin 20247 58858 1200951093 1 f none subversion/notes/changeset-signing.txt 0644 bin bin 3156 19695 1125234027 1 f none subversion/notes/cli-repo-root-relative-support.txt 0644 bin bin 1505 56294 1212910340 1 d none subversion/notes/commit-access-templates 0755 bin bin 1 f none subversion/notes/commit-access-templates/contrib-committer.tmpl 0644 bin bin 2503 28553 1212910340 1 f none subversion/notes/commit-access-templates/full-committer.tmpl 0644 bin bin 1695 23420 1212910340 1 f none subversion/notes/commit-access-templates/partial-committer.tmpl 0644 bin bin 1720 25537 1212910340 1 f none subversion/notes/compatibility.txt 0644 bin bin 2506 16873 1221000077 1 f none subversion/notes/copies-during-updates.txt 0644 bin bin 2173 56109 1189025345 1 f none subversion/notes/diff-encodings.txt 0644 bin bin 5646 50284 1133270626 1 f none subversion/notes/dump-load-format.txt 0644 bin bin 8396 59959 1227531121 1 f none subversion/notes/entries-caching 0644 bin bin 7539 14665 1099426521 1 f none subversion/notes/fs-improvements.txt 0644 bin bin 22987 39807 1221099732 1 f none subversion/notes/fs_dumprestore.txt 0644 bin bin 161 14798 1184549121 1 f none subversion/notes/fsfs 0644 bin bin 10993 10326 1212757098 1 f none subversion/notes/http-protocol-v2.txt 0644 bin bin 9978 30320 1233696840 1 f none subversion/notes/interactive-conflict-resolution.txt 0644 bin bin 3017 972 1212910340 1 f none subversion/notes/l10n-problems 0644 bin bin 9760 29147 1224677261 1 f none subversion/notes/line-endings-and-keywords.txt 0644 bin bin 12000 54363 1093814085 1 d none subversion/notes/locking 0755 bin bin 1 f none subversion/notes/locking/TODO.txt 0644 bin bin 828 64231 1124654813 1 f none subversion/notes/locking/locking-functional-spec.txt 0644 bin bin 8453 27971 1106065781 1 f none subversion/notes/locking/locking-implementation.txt 0644 bin bin 9072 49317 1124654813 1 f none subversion/notes/locking/locking-ui.txt 0644 bin bin 16838 13752 1160078426 1 f none subversion/notes/locking/ra_dav_strategy.txt 0644 bin bin 2739 23687 1124654813 1 f none subversion/notes/locking/svn-needs-lock-impl.txt 0644 bin bin 1913 34686 1107898105 1 d none subversion/notes/logo 0755 bin bin 1 d none subversion/notes/logo/16-colour 0755 bin bin 1 f none subversion/notes/logo/16-colour/subversion_logo_notxt-16m.png 0644 bin bin 237 19245 1031081549 1 f none subversion/notes/logo/16-colour/subversion_logo_notxt-32m.png 0644 bin bin 292 27924 1031081549 1 f none subversion/notes/logo/16-colour/subversion_logo_notxt-48m.png 0644 bin bin 348 34710 1031081549 1 d none subversion/notes/logo/256-colour 0755 bin bin 1 f none subversion/notes/logo/256-colour/subversion_logo-200x173.png 0644 bin bin 5150 28038 1031730945 1 f none subversion/notes/logo/256-colour/subversion_logo-384x332.png 0644 bin bin 10063 41000 1031171168 1 f none subversion/notes/logo/256-colour/subversion_logo.pal 0644 bin bin 2538 43266 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_hor-237x32.png 0644 bin bin 2426 35229 1031732581 1 f none subversion/notes/logo/256-colour/subversion_logo_hor-468x64.png 0644 bin bin 4094 39948 1031141795 1 f none subversion/notes/logo/256-colour/subversion_logo_notxt-16.png 0644 bin bin 1038 60119 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_notxt-32.png 0644 bin bin 1214 14381 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_notxt-48.png 0644 bin bin 1390 37150 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_txt.pal 0644 bin bin 3048 4731 1031141795 1 d none subversion/notes/logo/grayscale 0755 bin bin 1 f none subversion/notes/logo/grayscale/subversion_logo_notxt-16g.png 0644 bin bin 274 28499 1031081549 1 f none subversion/notes/logo/grayscale/subversion_logo_notxt-32g.png 0644 bin bin 457 50018 1031081549 1 f none subversion/notes/logo/grayscale/subversion_logo_notxt-48g.png 0644 bin bin 632 8700 1031081549 1 f none subversion/notes/logo/subversion_logo.eps.gz 0644 bin bin 105590 47434 1031081549 1 f none subversion/notes/logo/subversion_logo.icns 0644 bin bin 29722 56195 1031732581 1 f none subversion/notes/logo/subversion_logo.ico 0644 bin bin 10134 1892 1098244297 1 f none subversion/notes/logo/subversion_logo.png 0644 bin bin 36976 34089 1031081549 1 f none subversion/notes/logo/subversion_logo_notxt.png 0644 bin bin 24955 3610 1031081549 1 f none subversion/notes/object-model.txt 0644 bin bin 6347 38502 1206378634 1 d none subversion/notes/obliterate 0755 bin bin 1 f none subversion/notes/obliterate/obliterate-functional-spec.txt 0644 bin bin 26893 50382 1212528268 1 f none subversion/notes/propmerging_sanity.txt 0644 bin bin 5132 11494 1119994314 1 f none subversion/notes/repos_upgrade_HOWTO 0644 bin bin 4585 53749 1165858085 1 f none subversion/notes/sasl.txt 0644 bin bin 9581 21488 1250534092 1 f none subversion/notes/schema-tradeoffs.txt 0644 bin bin 4661 12783 1124654813 1 f none subversion/notes/skip-deltas 0644 bin bin 6852 43706 1212910340 1 f none subversion/notes/sparse-directories.txt 0644 bin bin 19548 45801 1207347367 1 f none subversion/notes/sql-backend 0644 bin bin 1551 10681 1212910340 1 f none subversion/notes/ssh-tricks 0644 bin bin 4061 23417 1212910340 1 f none subversion/notes/svndiff 0644 bin bin 4377 53454 1175902320 1 f none subversion/notes/svnsync.txt 0644 bin bin 7849 33213 1220478936 1 f none subversion/notes/test-writing 0644 bin bin 6291 15272 1212910340 1 d none subversion/notes/tree-conflicts 0755 bin bin 1 f none subversion/notes/tree-conflicts/all-tests.sh 0644 bin bin 447 37261 1225732931 1 f none subversion/notes/tree-conflicts/design-overview.txt 0644 bin bin 8592 11897 1227137892 1 f none subversion/notes/tree-conflicts/detection.txt 0644 bin bin 14234 49828 1223302969 1 f none subversion/notes/tree-conflicts/requirements.txt 0644 bin bin 7807 35517 1227137892 1 f none subversion/notes/tree-conflicts/resolution.txt 0644 bin bin 19905 26254 1234285351 1 f none subversion/notes/tree-conflicts/scratch-pad.txt 0644 bin bin 7420 47333 1207115210 1 f none subversion/notes/tree-conflicts/use-cases-resolution.txt 0644 bin bin 11053 37044 1227205581 1 f none subversion/notes/tree-conflicts/use-cases.txt 0644 bin bin 15169 60940 1200320840 1 f none subversion/notes/txdelta_sanity 0644 bin bin 1936 36548 1042497793 1 f none subversion/notes/unicode-composition-for-filenames 0644 bin bin 10178 41408 1206900758 1 f none subversion/notes/wc-improvements 0644 bin bin 9830 37155 1212910340 1 f none subversion/notes/wc-ng-design 0644 bin bin 40095 27258 1231534971 1 f none subversion/notes/webdav-acl-notes 0644 bin bin 12522 5810 1151513780 1 f none subversion/notes/webdav-general-summary 0644 bin bin 17159 54976 1169554058 1 f none subversion/notes/webdav-protocol 0644 bin bin 12030 14193 1221514555 1 f none subversion/notes/webdav-proxy 0644 bin bin 3438 43454 1230494626 1 f none subversion/notes/windows-service.txt 0644 bin bin 8836 56062 1142198486 1 s none subversion/styles.css=svnbook/styles.css 1 f none subversion/svn-best-practices.html 0644 bin bin 10800 8379 1260209521 1 f none subversion/svn-doc.el 0644 bin bin 670 56367 1042497793 1 f none subversion/svn-misc-docs.html 0644 bin bin 38845 52584 1260209479 1 d none subversion/svnbook 0755 bin bin 1 d none subversion/svnbook/images 0755 bin bin 1 f none subversion/svnbook/images/ch01dia1.png 0644 bin bin 55406 46785 1260169409 1 f none subversion/svnbook/images/ch02dia1.png 0644 bin bin 2544 56813 1260169409 1 f none subversion/svnbook/images/ch02dia2.png 0644 bin bin 11754 41703 1260169409 1 f none subversion/svnbook/images/ch02dia3.png 0644 bin bin 14307 46783 1260169409 1 f none subversion/svnbook/images/ch02dia4.png 0644 bin bin 11705 59086 1260169409 1 f none subversion/svnbook/images/ch02dia5.png 0644 bin bin 12176 58829 1260169409 1 f none subversion/svnbook/images/ch02dia6.png 0644 bin bin 4023 20011 1260169409 1 f none subversion/svnbook/images/ch02dia7.png 0644 bin bin 5495 59920 1260169409 1 f none subversion/svnbook/images/ch04dia1.png 0644 bin bin 2713 12573 1260169409 1 f none subversion/svnbook/images/ch04dia2.png 0644 bin bin 4127 54100 1260169409 1 f none subversion/svnbook/images/ch04dia3.png 0644 bin bin 6537 38498 1260169409 1 f none subversion/svnbook/images/ch04dia4.png 0644 bin bin 3849 31231 1260169409 1 f none subversion/svnbook/images/ch08dia1.png 0644 bin bin 2644 1706 1260169409 1 f none subversion/svnbook/images/ch08dia2.png 0644 bin bin 3910 40439 1260169409 1 f none subversion/svnbook/images/note.png 0644 bin bin 2015 55452 1260169409 1 f none subversion/svnbook/images/tip.png 0644 bin bin 2685 1692 1260169409 1 f none subversion/svnbook/images/warning.png 0644 bin bin 1690 8095 1260169409 1 f none subversion/svnbook/index.html 0644 bin bin 107207 60790 1260169409 1 f none subversion/svnbook/styles.css 0644 bin bin 5332 50752 1260169409 1 f none subversion/svnbook/svn.advanced.changelists.html 0644 bin bin 18731 31474 1260169409 1 f none subversion/svnbook/svn.advanced.confarea.html 0644 bin bin 47261 45662 1260169409 1 f none subversion/svnbook/svn.advanced.externaldifftools.html 0644 bin bin 17044 41625 1260169409 1 f none subversion/svnbook/svn.advanced.externaleditors.html 0644 bin bin 7499 24189 1260169409 1 f none subversion/svnbook/svn.advanced.externals.html 0644 bin bin 23934 27799 1260169409 1 f none subversion/svnbook/svn.advanced.html 0644 bin bin 10898 12108 1260169409 1 f none subversion/svnbook/svn.advanced.l10n.html 0644 bin bin 11605 33482 1260169409 1 f none subversion/svnbook/svn.advanced.locking.html 0644 bin bin 38337 30524 1260169409 1 f none subversion/svnbook/svn.advanced.pegrevs.html 0644 bin bin 21708 35939 1260169409 1 f none subversion/svnbook/svn.advanced.props.file-portability.html 0644 bin bin 21113 58926 1260169409 1 f none subversion/svnbook/svn.advanced.props.html 0644 bin bin 37348 24571 1260169409 1 f none subversion/svnbook/svn.advanced.props.special.ignore.html 0644 bin bin 20280 32255 1260169409 1 f none subversion/svnbook/svn.advanced.props.special.keywords.html 0644 bin bin 19496 16928 1260169409 1 f none subversion/svnbook/svn.advanced.sparsedirs.html 0644 bin bin 16097 27084 1260169409 1 f none subversion/svnbook/svn.advanced.summary.html 0644 bin bin 4018 57026 1260169409 1 f none subversion/svnbook/svn.advanced.vendorbr.html 0644 bin bin 22882 5841 1260169409 1 f none subversion/svnbook/svn.basic.html 0644 bin bin 7080 54834 1260169409 1 f none subversion/svnbook/svn.basic.in-action.html 0644 bin bin 37194 21761 1260169409 1 f none subversion/svnbook/svn.basic.repository.html 0644 bin bin 5457 52933 1260169409 1 f none subversion/svnbook/svn.basic.summary.html 0644 bin bin 4044 56131 1260169409 1 f none subversion/svnbook/svn.basic.vsn-models.html 0644 bin bin 16205 61767 1260169409 1 f none subversion/svnbook/svn.branchmerge.advanced.html 0644 bin bin 51392 26134 1260169409 1 f none subversion/svnbook/svn.branchmerge.basicmerging.html 0644 bin bin 43452 58255 1260169409 1 f none subversion/svnbook/svn.branchmerge.commonpatterns.html 0644 bin bin 12750 47146 1260169409 1 f none subversion/svnbook/svn.branchmerge.html 0644 bin bin 12175 13375 1260169409 1 f none subversion/svnbook/svn.branchmerge.maint.html 0644 bin bin 10330 64022 1260169409 1 f none subversion/svnbook/svn.branchmerge.summary.html 0644 bin bin 9877 43868 1260169409 1 f none subversion/svnbook/svn.branchmerge.switchwc.html 0644 bin bin 11391 15441 1260169409 1 f none subversion/svnbook/svn.branchmerge.tags.html 0644 bin bin 11090 60520 1260169409 1 f none subversion/svnbook/svn.branchmerge.using.html 0644 bin bin 21606 30954 1260169409 1 f none subversion/svnbook/svn.branchmerge.whatis.html 0644 bin bin 5362 43175 1260169409 1 f none subversion/svnbook/svn.copyright.html 0644 bin bin 17399 13517 1260169409 1 f none subversion/svnbook/svn.customization.html 0644 bin bin 6805 43811 1260169409 1 f none subversion/svnbook/svn.customization.summary.html 0644 bin bin 3953 60084 1260169409 1 f none subversion/svnbook/svn.developer.html 0644 bin bin 7046 7382 1260169409 1 f none subversion/svnbook/svn.developer.insidewc.html 0644 bin bin 9474 56565 1260169409 1 f none subversion/svnbook/svn.developer.layerlib.html 0644 bin bin 34042 29432 1260169409 1 f none subversion/svnbook/svn.developer.summary.html 0644 bin bin 3852 49230 1260169409 1 f none subversion/svnbook/svn.developer.usingapi.html 0644 bin bin 36307 21392 1260169409 1 f none subversion/svnbook/svn.forcvs.auth.html 0644 bin bin 4504 40847 1260169409 1 f none subversion/svnbook/svn.forcvs.binary-and-trans.html 0644 bin bin 5841 27690 1260169409 1 f none subversion/svnbook/svn.forcvs.branches-and-tags.html 0644 bin bin 5034 4648 1260169409 1 f none subversion/svnbook/svn.forcvs.conflicts.html 0644 bin bin 4355 28220 1260169409 1 f none subversion/svnbook/svn.forcvs.convert.html 0644 bin bin 4578 48484 1260169409 1 f none subversion/svnbook/svn.forcvs.directories.html 0644 bin bin 6976 51676 1260169409 1 f none subversion/svnbook/svn.forcvs.disconnected.html 0644 bin bin 5667 58155 1260169409 1 f none subversion/svnbook/svn.forcvs.html 0644 bin bin 6059 62066 1260169409 1 f none subversion/svnbook/svn.forcvs.modules.html 0644 bin bin 3572 24898 1260169409 1 f none subversion/svnbook/svn.forcvs.properties.html 0644 bin bin 3759 41324 1260169409 1 f none subversion/svnbook/svn.forcvs.revnums.html 0644 bin bin 5557 63967 1260169409 1 f none subversion/svnbook/svn.forcvs.status-vs-update.html 0644 bin bin 9511 38303 1260169409 1 f none subversion/svnbook/svn.foreword.html 0644 bin bin 9224 55678 1260169409 1 f none subversion/svnbook/svn.index.html 0644 bin bin 15811 19104 1260169409 1 f none subversion/svnbook/svn.intro.html 0644 bin bin 4521 24978 1260169409 1 f none subversion/svnbook/svn.intro.install.html 0644 bin bin 7884 63158 1260169409 1 f none subversion/svnbook/svn.intro.quickstart.html 0644 bin bin 11481 34510 1260169409 1 f none subversion/svnbook/svn.intro.whatis.html 0644 bin bin 21584 1754 1260169409 1 f none subversion/svnbook/svn.preface.acks.html 0644 bin bin 12303 35921 1260169409 1 f none subversion/svnbook/svn.preface.audience.html 0644 bin bin 5035 17161 1260169409 1 f none subversion/svnbook/svn.preface.conventions.html 0644 bin bin 5888 45162 1260169409 1 f none subversion/svnbook/svn.preface.free.html 0644 bin bin 4855 62642 1260169409 1 f none subversion/svnbook/svn.preface.howread.html 0644 bin bin 8524 41697 1260169409 1 f none subversion/svnbook/svn.preface.html 0644 bin bin 8468 44817 1260169409 1 f none subversion/svnbook/svn.preface.organization.html 0644 bin bin 9738 21868 1260169409 1 f none subversion/svnbook/svn.ref.html 0644 bin bin 31410 54283 1260169409 1 f none subversion/svnbook/svn.ref.mod_authz_svn.conf.html 0644 bin bin 6916 7182 1260169409 1 f none subversion/svnbook/svn.ref.mod_authz_svn.html 0644 bin bin 3056 46552 1260169409 1 f none subversion/svnbook/svn.ref.mod_dav_svn.conf.html 0644 bin bin 18595 30936 1260169409 1 f none subversion/svnbook/svn.ref.mod_dav_svn.html 0644 bin bin 2975 38318 1260169409 1 f none subversion/svnbook/svn.ref.properties.html 0644 bin bin 11615 21658 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.html 0644 bin bin 3050 45099 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-commit.html 0644 bin bin 4702 41009 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-lock.html 0644 bin bin 4571 27331 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-revprop-change.html 0644 bin bin 5527 37750 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-unlock.html 0644 bin bin 4613 32390 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-commit.html 0644 bin bin 4575 30042 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-lock.html 0644 bin bin 4722 39708 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-revprop-change.html 0644 bin bin 5341 23012 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-unlock.html 0644 bin bin 4749 40732 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.start-commit.html 0644 bin bin 4789 43588 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.add.html 0644 bin bin 5716 44716 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.blame.html 0644 bin bin 6026 7998 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.cat.html 0644 bin bin 5621 32571 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.changelist.html 0644 bin bin 5353 14962 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.checkout.html 0644 bin bin 6796 7230 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.cleanup.html 0644 bin bin 5314 18933 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.commit.html 0644 bin bin 7954 28998 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.copy.html 0644 bin bin 10441 53250 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.delete.html 0644 bin bin 6227 25010 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.diff.html 0644 bin bin 15967 21752 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.export.html 0644 bin bin 6476 42555 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.help.html 0644 bin bin 4234 62260 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.import.html 0644 bin bin 6199 21757 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.info.html 0644 bin bin 9762 1094 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.list.html 0644 bin bin 7774 5835 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.lock.html 0644 bin bin 5372 20423 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.log.html 0644 bin bin 15240 34609 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.merge.html 0644 bin bin 8477 6427 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.mergeinfo.html 0644 bin bin 5821 59348 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.mkdir.html 0644 bin bin 5267 12256 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.move.html 0644 bin bin 7306 16543 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propdel.html 0644 bin bin 5067 65340 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propedit.html 0644 bin bin 5401 29925 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propget.html 0644 bin bin 5525 37728 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.proplist.html 0644 bin bin 5785 57858 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propset.html 0644 bin bin 8585 9813 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.resolve.html 0644 bin bin 7454 40098 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.resolved.html 0644 bin bin 6750 64897 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.revert.html 0644 bin bin 6525 41864 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.status.html 0644 bin bin 19826 21074 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.switch.html 0644 bin bin 11812 58 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.unlock.html 0644 bin bin 5214 10302 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.update.html 0644 bin bin 9083 15874 1260169409 1 f none subversion/svnbook/svn.ref.svn.html 0644 bin bin 34950 24069 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.crashtest.html 0644 bin bin 4085 55462 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.create.html 0644 bin bin 5758 53642 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.deltify.html 0644 bin bin 4158 494 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.dump.html 0644 bin bin 7446 8675 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.help.html 0644 bin bin 3708 27581 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.hotcopy.html 0644 bin bin 5260 18630 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.list-dblogs.html 0644 bin bin 4138 1916 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.list-unused-dblogs.html 0644 bin bin 4539 32721 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.load.html 0644 bin bin 4815 51145 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.lslocks.html 0644 bin bin 4439 17521 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.lstxns.html 0644 bin bin 4007 54941 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.pack.html 0644 bin bin 3749 33081 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.recover.html 0644 bin bin 5556 54822 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.rmlocks.html 0644 bin bin 4136 61077 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.rmtxns.html 0644 bin bin 4439 24443 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.setlog.html 0644 bin bin 5329 19126 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.setrevprop.html 0644 bin bin 4755 47610 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.setuuid.html 0644 bin bin 4760 46077 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.upgrade.html 0644 bin bin 5405 25740 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.verify.html 0644 bin bin 4487 25143 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.html 0644 bin bin 10767 63822 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.commands.c.exclude.html 0644 bin bin 4683 45798 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.commands.c.help.html 0644 bin bin 3858 42588 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.commands.c.include.html 0644 bin bin 4735 50006 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.html 0644 bin bin 6664 49123 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.author.html 0644 bin bin 3853 36486 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.cat.html 0644 bin bin 4224 61409 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.changed.html 0644 bin bin 6662 45236 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.date.html 0644 bin bin 3898 38150 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.diff.html 0644 bin bin 5002 58044 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.dirs-changed.html 0644 bin bin 4019 51157 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.help.html 0644 bin bin 4043 53849 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.history.html 0644 bin bin 4713 31258 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.info.html 0644 bin bin 4032 50023 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.lock.html 0644 bin bin 4247 479 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.log.html 0644 bin bin 3861 37000 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.propget.html 0644 bin bin 4395 16035 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.proplist.html 0644 bin bin 4755 44783 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.tree.html 0644 bin bin 4375 9656 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.uuid.html 0644 bin bin 4139 60014 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.youngest.html 0644 bin bin 3763 30633 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.html 0644 bin bin 7817 4061 1260169409 1 f none subversion/svnbook/svn.ref.svnserve.html 0644 bin bin 12072 11255 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.copy-revprops.html 0644 bin bin 5144 14512 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.help.html 0644 bin bin 3949 44955 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.info.html 0644 bin bin 4451 20340 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.init.html 0644 bin bin 5384 35513 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.sync.html 0644 bin bin 5409 36647 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.html 0644 bin bin 9737 22720 1260169409 1 f none subversion/svnbook/svn.ref.svnversion.html 0644 bin bin 2973 38456 1260169409 1 f none subversion/svnbook/svn.ref.svnversion.re.html 0644 bin bin 7636 944 1260169409 1 f none subversion/svnbook/svn.reposadmin.basics.html 0644 bin bin 7085 41486 1260169409 1 f none subversion/svnbook/svn.reposadmin.create.html 0644 bin bin 20163 3556 1260169409 1 f none subversion/svnbook/svn.reposadmin.html 0644 bin bin 12514 44116 1260169409 1 f none subversion/svnbook/svn.reposadmin.maint.html 0644 bin bin 127526 61226 1260169409 1 f none subversion/svnbook/svn.reposadmin.maint.moving-and-removing.html 0644 bin bin 5337 51132 1260169409 1 f none subversion/svnbook/svn.reposadmin.planning.html 0644 bin bin 38161 51064 1260169409 1 f none subversion/svnbook/svn.reposadmin.summary.html 0644 bin bin 3587 27454 1260169409 1 f none subversion/svnbook/svn.serverconfig.choosing.html 0644 bin bin 16017 62326 1260169409 1 f none subversion/svnbook/svn.serverconfig.html 0644 bin bin 13350 21447 1260169409 1 f none subversion/svnbook/svn.serverconfig.httpd.html 0644 bin bin 82508 29837 1260169409 1 f none subversion/svnbook/svn.serverconfig.multimethod.html 0644 bin bin 10094 38681 1260169409 1 f none subversion/svnbook/svn.serverconfig.netmodel.html 0644 bin bin 18503 61765 1260169409 1 f none subversion/svnbook/svn.serverconfig.overview.html 0644 bin bin 10131 5414 1260169409 1 f none subversion/svnbook/svn.serverconfig.pathbasedauthz.html 0644 bin bin 18621 50850 1260169409 1 f none subversion/svnbook/svn.serverconfig.svnserve.html 0644 bin bin 54349 26593 1260169409 1 f none subversion/svnbook/svn.tour.cleanup.html 0644 bin bin 7103 52266 1260169409 1 f none subversion/svnbook/svn.tour.cycle.html 0644 bin bin 66678 36616 1260169409 1 f none subversion/svnbook/svn.tour.help.html 0644 bin bin 5326 33749 1260169409 1 f none subversion/svnbook/svn.tour.history.html 0644 bin bin 24053 15757 1260169409 1 f none subversion/svnbook/svn.tour.html 0644 bin bin 12688 31192 1260169409 1 f none subversion/svnbook/svn.tour.importing.html 0644 bin bin 6620 15853 1260169409 1 f none subversion/svnbook/svn.tour.initial.html 0644 bin bin 14437 18251 1260169409 1 f none subversion/svnbook/svn.tour.revs.specifiers.html 0644 bin bin 13832 26151 1260169409 1 f none subversion/svnbook/svn.tour.summary.html 0644 bin bin 3690 35163 1260169409 1 f none subversion/svnbook/svn.tour.treeconflicts.html 0644 bin bin 16529 43183 1260169409 1 f none subversion/svnbook/svn.webdav.autoversioning.html 0644 bin bin 8556 59756 1260169409 1 f none subversion/svnbook/svn.webdav.basic.html 0644 bin bin 7833 64390 1260169409 1 f none subversion/svnbook/svn.webdav.clients.html 0644 bin bin 25741 2759 1260169409 1 f none subversion/svnbook/svn.webdav.html 0644 bin bin 6812 35580 1260169409 1 d none subversion/tools 0755 bin bin 1 d none subversion/tools/bdb 0755 bin bin 1 f none subversion/tools/bdb/erase-all-text-data.py 0755 bin bin 2211 41563 1230083891 1 f none subversion/tools/bdb/skel.py 0644 bin bin 6379 25645 1224435754 1 f none subversion/tools/bdb/svn-bdb-view.py 0755 bin bin 7726 45315 1233348466 1 f none subversion/tools/bdb/svnfs.py 0644 bin bin 2295 50390 1188090288 1 f none subversion/tools/bdb/whatis-rep.py 0755 bin bin 1674 63417 1230083891 1 d none subversion/tools/cgi 0755 bin bin 1 f none subversion/tools/cgi/mirror_dir_through_svn.README 0644 bin bin 3082 13610 1062093803 1 f none subversion/tools/cgi/mirror_dir_through_svn.cgi 0755 bin bin 6645 64371 1206456152 1 f none subversion/tools/cgi/tweak-log.cgi 0644 bin bin 10422 30545 1192032640 1 d none subversion/tools/client-side 0755 bin bin 1 f none subversion/tools/client-side/asvn 0755 bin bin 11406 446 1201479865 1 f none subversion/tools/client-side/diff-wrap.sh 0755 bin bin 1465 54160 1205172428 1 f none subversion/tools/client-side/diff3wrap.bat 0644 bin bin 870 7708 1120723506 1 f none subversion/tools/client-side/diffwrap.bat 0644 bin bin 503 41357 1213103562 1 d none subversion/tools/client-side/emacs 0755 bin bin 1 f none subversion/tools/client-side/emacs/dsvn.el 0644 bin bin 76185 29274 1243350930 1 f none subversion/tools/client-side/emacs/psvn.el 0644 bin bin 297077 63375 1234388114 1 f none subversion/tools/client-side/emacs/vc-svn.el 0644 bin bin 18514 35473 1174028619 1 f none subversion/tools/client-side/incremental-update.py 0755 bin bin 6038 12754 1188090288 1 f none subversion/tools/client-side/search-svnlog.pl 0755 bin bin 3227 55404 1206456152 1 f none subversion/tools/client-side/svn-clean 0755 bin bin 6564 47482 1201381347 1 f none subversion/tools/client-side/svn-hgmerge.py 0755 bin bin 1963 37155 1213716052 1 f none subversion/tools/client-side/svn-log.pl 0644 bin bin 736 57837 1188090288 1 f none subversion/tools/client-side/svn-merge-vendor.py 0755 bin bin 18252 43981 1192781826 1 d none subversion/tools/client-side/svn-push 0755 bin bin 1 f none subversion/tools/client-side/svn-push/svn-push.c 0644 bin bin 6126 35042 1232851210 1 f none subversion/tools/client-side/svn-resolve 0755 bin bin 3284 56393 1149730698 1 f none subversion/tools/client-side/svn-viewdiff 0755 bin bin 4796 22362 1143668223 1 d none subversion/tools/client-side/svn2cl 0755 bin bin 1 f none subversion/tools/client-side/svn2cl/NEWS 0644 bin bin 3232 15258 1229874436 1 f none subversion/tools/client-side/svn2cl/README 0644 bin bin 4226 24672 1207491166 1 f none subversion/tools/client-side/svn2cl/TODO 0644 bin bin 457 42374 1207491166 1 f none subversion/tools/client-side/svn2cl/authors.xml 0644 bin bin 374 32262 1161209035 1 f none subversion/tools/client-side/svn2cl/svn2cl.1 0644 bin bin 8399 59978 1229874436 1 f none subversion/tools/client-side/svn2cl/svn2cl.sh 0755 bin bin 11155 34097 1229874436 1 f none subversion/tools/client-side/svn2cl/svn2cl.xsl 0644 bin bin 17216 7108 1229874436 1 f none subversion/tools/client-side/svn2cl/svn2html.css 0644 bin bin 1218 34123 1144705185 1 f none subversion/tools/client-side/svn2cl/svn2html.xsl 0644 bin bin 7360 62250 1229874436 1 f none subversion/tools/client-side/svn_all_diffs.pl 0755 bin bin 3927 45696 1206456152 1 f none subversion/tools/client-side/svn_apply_autoprops.py 0755 bin bin 4764 763 1153366888 1 f none subversion/tools/client-side/svn_export_empty_files.py 0755 bin bin 14560 12242 1197931724 1 d none subversion/tools/client-side/svn_load_dirs 0755 bin bin 1 f none subversion/tools/client-side/svn_load_dirs/LICENSE_AFL3.txt 0644 bin bin 10962 53979 1255352236 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs.README 0644 bin bin 9577 37287 1174028619 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs.pl 0755 bin bin 67158 20860 1260208980 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs.pl.in 0755 bin bin 67162 21017 1255352236 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs_property_table.example 0644 bin bin 1334 51041 1174028619 1 f none subversion/tools/client-side/svn_update.pl 0755 bin bin 9999 57147 1191617780 1 d none subversion/tools/client-side/svncopy 0755 bin bin 1 f none subversion/tools/client-side/svncopy/svncopy.README 0644 bin bin 9772 62860 1174028619 1 f none subversion/tools/client-side/svncopy/svncopy.pl 0755 bin bin 31528 17695 1260208980 1 f none subversion/tools/client-side/svncopy/svncopy.pl.in 0644 bin bin 31532 17852 1174028619 1 f none subversion/tools/client-side/svncopy/testsvncopy.pl 0755 bin bin 31911 55974 1260208980 1 f none subversion/tools/client-side/svncopy/testsvncopy.pl.in 0644 bin bin 31915 56131 1174028619 1 d none subversion/tools/client-side/svnmerge 0755 bin bin 1 f none subversion/tools/client-side/svnmerge/svnmerge-migrate-history-remotely.py 0755 bin bin 18703 28884 1232490354 1 f none subversion/tools/client-side/svnmerge/svnmerge-migrate-history.py 0755 bin bin 16115 10755 1234816525 1 f none subversion/tools/client-side/svnmerge/svnmerge-migrate-test.sh 0755 bin bin 2925 23971 1210699417 1 f none subversion/tools/client-side/svnmerge/svnmerge.README 0644 bin bin 1011 23837 1174028619 1 f none subversion/tools/client-side/svnmerge/svnmerge.py 0755 bin bin 83614 10837 1238432827 1 f none subversion/tools/client-side/svnmerge/svnmerge.sh 0755 bin bin 24391 19700 1174028619 1 f none subversion/tools/client-side/svnmerge/svnmerge_test.py 0755 bin bin 51249 3383 1213801523 1 d none subversion/tools/client-side/vim 0755 bin bin 1 f none subversion/tools/client-side/vim/diff-to-logmsg.vim 0644 bin bin 1126 26938 1174028619 1 f none subversion/tools/client-side/vim/svn.vim 0644 bin bin 1891 31307 1174028619 1 f none subversion/tools/client-side/wcgrep 0755 bin bin 2387 56942 1079640774 1 d none subversion/tools/examples 0755 bin bin 1 f none subversion/tools/examples/SvnCLBrowse 0755 bin bin 18255 2452 1203641040 1 f none subversion/tools/examples/blame.py 0755 bin bin 2270 39708 1230083891 1 f none subversion/tools/examples/check-modified.py 0755 bin bin 885 2591 1230083891 1 f none subversion/tools/examples/dumpprops.py 0755 bin bin 1499 59171 1230083891 1 f none subversion/tools/examples/get-location-segments.py 0755 bin bin 2845 43770 1230083891 1 f none subversion/tools/examples/getfile.py 0755 bin bin 1073 22467 1230083891 1 f none subversion/tools/examples/getlocks_test.c 0644 bin bin 8454 4204 1188090288 1 f none subversion/tools/examples/geturl.py 0755 bin bin 565 45855 1230083891 1 f none subversion/tools/examples/headrev.c 0644 bin bin 7041 34277 1188090288 1 f none subversion/tools/examples/minimal_client.c 0644 bin bin 9261 8663 1188090288 1 f none subversion/tools/examples/putfile.py 0755 bin bin 1737 11999 1230083891 1 f none subversion/tools/examples/revplist.py 0755 bin bin 1800 8534 1230083891 1 f none subversion/tools/examples/svnlog2html.rb 0755 bin bin 1804 10819 1191617780 1 f none subversion/tools/examples/svnlook.py 0755 bin bin 12461 64531 1230083891 1 f none subversion/tools/examples/svnlook.rb 0755 bin bin 13104 45496 1191617780 1 f none subversion/tools/examples/svnput.c 0644 bin bin 11442 45264 1188090288 1 f none subversion/tools/examples/svnserve-sgid.c 0644 bin bin 1047 21639 1122158619 1 f none subversion/tools/examples/svnshell.py 0755 bin bin 10989 2021 1233348466 1 f none subversion/tools/examples/svnshell.rb 0755 bin bin 11018 20386 1191617780 1 f none subversion/tools/examples/testwrite.c 0644 bin bin 8714 38746 1188090288 1 d none subversion/tools/hook-scripts 0755 bin bin 1 f none subversion/tools/hook-scripts/README 0644 bin bin 95 8751 1146507500 1 f none subversion/tools/hook-scripts/case-insensitive.py 0755 bin bin 4782 7009 1192658646 1 f none subversion/tools/hook-scripts/check-mime-type.pl 0755 bin bin 6527 40004 1191617780 1 f none subversion/tools/hook-scripts/commit-access-control.cfg.example 0644 bin bin 2982 59946 1047448581 1 f none subversion/tools/hook-scripts/commit-access-control.pl 0755 bin bin 11503 5137 1260208980 1 f none subversion/tools/hook-scripts/commit-access-control.pl.in 0755 bin bin 11507 5294 1206456152 1 f none subversion/tools/hook-scripts/commit-block-joke.py 0755 bin bin 2147 41160 1192032640 1 f none subversion/tools/hook-scripts/commit-email.pl 0755 bin bin 26475 44253 1260208980 1 f none subversion/tools/hook-scripts/commit-email.pl.in 0755 bin bin 26479 44410 1226379622 1 f none subversion/tools/hook-scripts/commit-email.rb 0755 bin bin 2128 43705 1217571213 1 f none subversion/tools/hook-scripts/detect-merge-conflicts.sh 0755 bin bin 1106 23452 1176749122 1 d none subversion/tools/hook-scripts/enforcer 0755 bin bin 1 f none subversion/tools/hook-scripts/enforcer/enforcer 0755 bin bin 17259 35519 1228503354 1 f none subversion/tools/hook-scripts/enforcer/enforcer.conf 0644 bin bin 3609 10487 1177098861 1 f none subversion/tools/hook-scripts/log-police.py 0755 bin bin 4399 46185 1232852708 1 d none subversion/tools/hook-scripts/mailer 0755 bin bin 1 f none subversion/tools/hook-scripts/mailer/mailer.conf.example 0644 bin bin 12898 12415 1190733357 1 f none subversion/tools/hook-scripts/mailer/mailer.py 0755 bin bin 45385 33269 1233369365 1 d none subversion/tools/hook-scripts/mailer/tests 0755 bin bin 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-init.sh 0755 bin bin 2315 65138 1206456152 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-t1.output 0644 bin bin 14332 24192 1190733357 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-t1.sh 0755 bin bin 938 12195 1223164281 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-tweak.py 0755 bin bin 1116 24890 1230083891 1 f none subversion/tools/hook-scripts/mailer/tests/mailer.conf 0644 bin bin 13003 21546 1190733357 1 f none subversion/tools/hook-scripts/pre-commit-check.py 0755 bin bin 3150 5474 1192032640 1 f none subversion/tools/hook-scripts/pre-lock-require-needs-lock.py 0755 bin bin 1809 21407 1192032640 1 f none subversion/tools/hook-scripts/remove-zombie-locks.py 0755 bin bin 6725 41042 1188090288 1 f none subversion/tools/hook-scripts/require-mergeinfo.pl 0755 bin bin 1112 30006 1231516768 1 f none subversion/tools/hook-scripts/svn-keyword-check.pl 0755 bin bin 8341 403 1210875854 1 f none subversion/tools/hook-scripts/svn2feed.py 0755 bin bin 16469 51791 1234542146 1 f none subversion/tools/hook-scripts/svnperms.conf.example 0644 bin bin 3089 2816 1125010600 1 f none subversion/tools/hook-scripts/svnperms.py 0755 bin bin 11815 21449 1230151759 1 f none subversion/tools/hook-scripts/syntax-check.sh 0755 bin bin 5551 8984 1200499795 1 f none subversion/tools/hook-scripts/verify-po.py 0755 bin bin 3158 54367 1232863744 1 d none subversion/tools/server-side 0755 bin bin 1 f none subversion/tools/server-side/add-needs-lock.py 0755 bin bin 6471 53556 1217430515 1 f none subversion/tools/server-side/authz_svn_group.py 0755 bin bin 5911 22827 1149001637 1 f none subversion/tools/server-side/backup-recipe.sh 0755 bin bin 9273 14138 1086641239 1 f none subversion/tools/server-side/fsfsverify.py 0755 bin bin 33899 39130 1203370596 1 f none subversion/tools/server-side/load_repo_with_mergesensitive_copy.sh 0755 bin bin 4319 31367 1191856145 1 d none subversion/tools/server-side/mod_dontdothat 0755 bin bin 1 f none subversion/tools/server-side/mod_dontdothat/README 0644 bin bin 1902 37593 1209132877 1 f none subversion/tools/server-side/mod_dontdothat/mod_dontdothat.c 0644 bin bin 18623 24093 1208357277 1 f none subversion/tools/server-side/svn-fast-backup 0755 bin bin 9952 2396 1168920422 1 f none subversion/tools/server-side/svn-tweak-author.py 0755 bin bin 4687 48017 1188090288 1 f none subversion/tools/server-side/svnmirror-test.sh 0755 bin bin 3281 33561 1228426298 1 f none subversion/tools/server-side/svnmirror.sh 0755 bin bin 12334 50961 1139348169 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000b00000000TRAILER!!! 07070100027250000081a4000017820000044e000000014b1d4576000004290000022d0000016a00000000000000000000000800000000pkginfo PKG=LNFsubversion-docs ARCH=i386 VERSION=1.6.6 MAXINST=1000 SERIALNUM=001 NAME=Subversion - documentation CATEGORY=development,utils,application EMAIL=developers@linofee.org VENDOR=LINOFEE, http://www.linofee.org BASEDIR=/usr/doc DESC=This package contains additional documentation for subversion like a html formatted Subversion book, best practice infos, HOWTOs and tools examples. Subversion is a concurrent version control system which enables one or more users to collaborate in developing and maintaining a hierarchy of files and directories while keeping a history of all changes. Subversion only stores the differences between versions, instead of every complete file. Subversion also keeps a log of who, when, and why changes occurred. As such it basically does the same thing CVS does (Concurrent Versioning System) but has major enhancements compared to CVS and fixes a lot of the annoyances that CVS users face. LICINFO=Subversion LICURL=http://subversion.tigris.org/project_license.html LICFILE=subversion.txt PSTAMP=idev20091207191206 CLASSES=none 0707010002724f000081a4000017820000044e000000014b1d457a00009bb00000022d0000016a00000000000000000000000700000000pkgmap : 1 11756 1 i pkginfo 1065 30565 1260209526 1 d none subversion 0755 bin bin 1 f none subversion/BUGS 0644 bin bin 107 9904 1127249608 1 f none subversion/CHANGES 0644 bin bin 161545 4728 1255623308 1 f none subversion/COMMITTERS 0644 bin bin 10964 3588 1232110285 1 f none subversion/HACKING 0644 bin bin 113 10488 1121977084 1 f none subversion/INSTALL 0644 bin bin 67415 40467 1244483735 1 f none subversion/README 0644 bin bin 2244 45546 1196408919 1 f none subversion/WritingChangeLogs.txt 0644 bin bin 9158 9663 1151009799 1 f none subversion/cvs-crossover-guide.html 0644 bin bin 26602 37963 1260209521 1 f none subversion/lj_article.txt 0644 bin bin 13988 543 1169554058 1 d none subversion/notes 0755 bin bin 1 f none subversion/notes/EuroOSCON-2005-vc-bof.txt 0644 bin bin 12611 48091 1212910340 1 f none subversion/notes/alternate-bdb-version 0644 bin bin 4147 35765 1140370184 1 f none subversion/notes/anchors_and_targets.txt 0644 bin bin 6911 10672 1064532772 1 f none subversion/notes/asp-dot-net-hack.txt 0644 bin bin 1473 179 1129756132 1 f none subversion/notes/assurance.txt 0644 bin bin 3975 20877 1067709195 1 f none subversion/notes/authz_policy.txt 0644 bin bin 7307 14366 1147674776 1 f none subversion/notes/autoversion-compatibility.txt 0644 bin bin 4835 56169 1043340094 1 f none subversion/notes/autoversioning-strategy.txt 0644 bin bin 13946 64668 1099674504 1 f none subversion/notes/changelist-design.txt 0644 bin bin 20247 58858 1200951093 1 f none subversion/notes/changeset-signing.txt 0644 bin bin 3156 19695 1125234027 1 f none subversion/notes/cli-repo-root-relative-support.txt 0644 bin bin 1505 56294 1212910340 1 d none subversion/notes/commit-access-templates 0755 bin bin 1 f none subversion/notes/commit-access-templates/contrib-committer.tmpl 0644 bin bin 2503 28553 1212910340 1 f none subversion/notes/commit-access-templates/full-committer.tmpl 0644 bin bin 1695 23420 1212910340 1 f none subversion/notes/commit-access-templates/partial-committer.tmpl 0644 bin bin 1720 25537 1212910340 1 f none subversion/notes/compatibility.txt 0644 bin bin 2506 16873 1221000077 1 f none subversion/notes/copies-during-updates.txt 0644 bin bin 2173 56109 1189025345 1 f none subversion/notes/diff-encodings.txt 0644 bin bin 5646 50284 1133270626 1 f none subversion/notes/dump-load-format.txt 0644 bin bin 8396 59959 1227531121 1 f none subversion/notes/entries-caching 0644 bin bin 7539 14665 1099426521 1 f none subversion/notes/fs-improvements.txt 0644 bin bin 22987 39807 1221099732 1 f none subversion/notes/fs_dumprestore.txt 0644 bin bin 161 14798 1184549121 1 f none subversion/notes/fsfs 0644 bin bin 10993 10326 1212757098 1 f none subversion/notes/http-protocol-v2.txt 0644 bin bin 9978 30320 1233696840 1 f none subversion/notes/interactive-conflict-resolution.txt 0644 bin bin 3017 972 1212910340 1 f none subversion/notes/l10n-problems 0644 bin bin 9760 29147 1224677261 1 f none subversion/notes/line-endings-and-keywords.txt 0644 bin bin 12000 54363 1093814085 1 d none subversion/notes/locking 0755 bin bin 1 f none subversion/notes/locking/TODO.txt 0644 bin bin 828 64231 1124654813 1 f none subversion/notes/locking/locking-functional-spec.txt 0644 bin bin 8453 27971 1106065781 1 f none subversion/notes/locking/locking-implementation.txt 0644 bin bin 9072 49317 1124654813 1 f none subversion/notes/locking/locking-ui.txt 0644 bin bin 16838 13752 1160078426 1 f none subversion/notes/locking/ra_dav_strategy.txt 0644 bin bin 2739 23687 1124654813 1 f none subversion/notes/locking/svn-needs-lock-impl.txt 0644 bin bin 1913 34686 1107898105 1 d none subversion/notes/logo 0755 bin bin 1 d none subversion/notes/logo/16-colour 0755 bin bin 1 f none subversion/notes/logo/16-colour/subversion_logo_notxt-16m.png 0644 bin bin 237 19245 1031081549 1 f none subversion/notes/logo/16-colour/subversion_logo_notxt-32m.png 0644 bin bin 292 27924 1031081549 1 f none subversion/notes/logo/16-colour/subversion_logo_notxt-48m.png 0644 bin bin 348 34710 1031081549 1 d none subversion/notes/logo/256-colour 0755 bin bin 1 f none subversion/notes/logo/256-colour/subversion_logo-200x173.png 0644 bin bin 5150 28038 1031730945 1 f none subversion/notes/logo/256-colour/subversion_logo-384x332.png 0644 bin bin 10063 41000 1031171168 1 f none subversion/notes/logo/256-colour/subversion_logo.pal 0644 bin bin 2538 43266 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_hor-237x32.png 0644 bin bin 2426 35229 1031732581 1 f none subversion/notes/logo/256-colour/subversion_logo_hor-468x64.png 0644 bin bin 4094 39948 1031141795 1 f none subversion/notes/logo/256-colour/subversion_logo_notxt-16.png 0644 bin bin 1038 60119 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_notxt-32.png 0644 bin bin 1214 14381 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_notxt-48.png 0644 bin bin 1390 37150 1031081549 1 f none subversion/notes/logo/256-colour/subversion_logo_txt.pal 0644 bin bin 3048 4731 1031141795 1 d none subversion/notes/logo/grayscale 0755 bin bin 1 f none subversion/notes/logo/grayscale/subversion_logo_notxt-16g.png 0644 bin bin 274 28499 1031081549 1 f none subversion/notes/logo/grayscale/subversion_logo_notxt-32g.png 0644 bin bin 457 50018 1031081549 1 f none subversion/notes/logo/grayscale/subversion_logo_notxt-48g.png 0644 bin bin 632 8700 1031081549 1 f none subversion/notes/logo/subversion_logo.eps.gz 0644 bin bin 105590 47434 1031081549 1 f none subversion/notes/logo/subversion_logo.icns 0644 bin bin 29722 56195 1031732581 1 f none subversion/notes/logo/subversion_logo.ico 0644 bin bin 10134 1892 1098244297 1 f none subversion/notes/logo/subversion_logo.png 0644 bin bin 36976 34089 1031081549 1 f none subversion/notes/logo/subversion_logo_notxt.png 0644 bin bin 24955 3610 1031081549 1 f none subversion/notes/object-model.txt 0644 bin bin 6347 38502 1206378634 1 d none subversion/notes/obliterate 0755 bin bin 1 f none subversion/notes/obliterate/obliterate-functional-spec.txt 0644 bin bin 26893 50382 1212528268 1 f none subversion/notes/propmerging_sanity.txt 0644 bin bin 5132 11494 1119994314 1 f none subversion/notes/repos_upgrade_HOWTO 0644 bin bin 4585 53749 1165858085 1 f none subversion/notes/sasl.txt 0644 bin bin 9581 21488 1250534092 1 f none subversion/notes/schema-tradeoffs.txt 0644 bin bin 4661 12783 1124654813 1 f none subversion/notes/skip-deltas 0644 bin bin 6852 43706 1212910340 1 f none subversion/notes/sparse-directories.txt 0644 bin bin 19548 45801 1207347367 1 f none subversion/notes/sql-backend 0644 bin bin 1551 10681 1212910340 1 f none subversion/notes/ssh-tricks 0644 bin bin 4061 23417 1212910340 1 f none subversion/notes/svndiff 0644 bin bin 4377 53454 1175902320 1 f none subversion/notes/svnsync.txt 0644 bin bin 7849 33213 1220478936 1 f none subversion/notes/test-writing 0644 bin bin 6291 15272 1212910340 1 d none subversion/notes/tree-conflicts 0755 bin bin 1 f none subversion/notes/tree-conflicts/all-tests.sh 0644 bin bin 447 37261 1225732931 1 f none subversion/notes/tree-conflicts/design-overview.txt 0644 bin bin 8592 11897 1227137892 1 f none subversion/notes/tree-conflicts/detection.txt 0644 bin bin 14234 49828 1223302969 1 f none subversion/notes/tree-conflicts/requirements.txt 0644 bin bin 7807 35517 1227137892 1 f none subversion/notes/tree-conflicts/resolution.txt 0644 bin bin 19905 26254 1234285351 1 f none subversion/notes/tree-conflicts/scratch-pad.txt 0644 bin bin 7420 47333 1207115210 1 f none subversion/notes/tree-conflicts/use-cases-resolution.txt 0644 bin bin 11053 37044 1227205581 1 f none subversion/notes/tree-conflicts/use-cases.txt 0644 bin bin 15169 60940 1200320840 1 f none subversion/notes/txdelta_sanity 0644 bin bin 1936 36548 1042497793 1 f none subversion/notes/unicode-composition-for-filenames 0644 bin bin 10178 41408 1206900758 1 f none subversion/notes/wc-improvements 0644 bin bin 9830 37155 1212910340 1 f none subversion/notes/wc-ng-design 0644 bin bin 40095 27258 1231534971 1 f none subversion/notes/webdav-acl-notes 0644 bin bin 12522 5810 1151513780 1 f none subversion/notes/webdav-general-summary 0644 bin bin 17159 54976 1169554058 1 f none subversion/notes/webdav-protocol 0644 bin bin 12030 14193 1221514555 1 f none subversion/notes/webdav-proxy 0644 bin bin 3438 43454 1230494626 1 f none subversion/notes/windows-service.txt 0644 bin bin 8836 56062 1142198486 1 s none subversion/styles.css=svnbook/styles.css 1 f none subversion/svn-best-practices.html 0644 bin bin 10800 8379 1260209521 1 f none subversion/svn-doc.el 0644 bin bin 670 56367 1042497793 1 f none subversion/svn-misc-docs.html 0644 bin bin 38845 52584 1260209479 1 d none subversion/svnbook 0755 bin bin 1 d none subversion/svnbook/images 0755 bin bin 1 f none subversion/svnbook/images/ch01dia1.png 0644 bin bin 55406 46785 1260169409 1 f none subversion/svnbook/images/ch02dia1.png 0644 bin bin 2544 56813 1260169409 1 f none subversion/svnbook/images/ch02dia2.png 0644 bin bin 11754 41703 1260169409 1 f none subversion/svnbook/images/ch02dia3.png 0644 bin bin 14307 46783 1260169409 1 f none subversion/svnbook/images/ch02dia4.png 0644 bin bin 11705 59086 1260169409 1 f none subversion/svnbook/images/ch02dia5.png 0644 bin bin 12176 58829 1260169409 1 f none subversion/svnbook/images/ch02dia6.png 0644 bin bin 4023 20011 1260169409 1 f none subversion/svnbook/images/ch02dia7.png 0644 bin bin 5495 59920 1260169409 1 f none subversion/svnbook/images/ch04dia1.png 0644 bin bin 2713 12573 1260169409 1 f none subversion/svnbook/images/ch04dia2.png 0644 bin bin 4127 54100 1260169409 1 f none subversion/svnbook/images/ch04dia3.png 0644 bin bin 6537 38498 1260169409 1 f none subversion/svnbook/images/ch04dia4.png 0644 bin bin 3849 31231 1260169409 1 f none subversion/svnbook/images/ch08dia1.png 0644 bin bin 2644 1706 1260169409 1 f none subversion/svnbook/images/ch08dia2.png 0644 bin bin 3910 40439 1260169409 1 f none subversion/svnbook/images/note.png 0644 bin bin 2015 55452 1260169409 1 f none subversion/svnbook/images/tip.png 0644 bin bin 2685 1692 1260169409 1 f none subversion/svnbook/images/warning.png 0644 bin bin 1690 8095 1260169409 1 f none subversion/svnbook/index.html 0644 bin bin 107207 60790 1260169409 1 f none subversion/svnbook/styles.css 0644 bin bin 5332 50752 1260169409 1 f none subversion/svnbook/svn.advanced.changelists.html 0644 bin bin 18731 31474 1260169409 1 f none subversion/svnbook/svn.advanced.confarea.html 0644 bin bin 47261 45662 1260169409 1 f none subversion/svnbook/svn.advanced.externaldifftools.html 0644 bin bin 17044 41625 1260169409 1 f none subversion/svnbook/svn.advanced.externaleditors.html 0644 bin bin 7499 24189 1260169409 1 f none subversion/svnbook/svn.advanced.externals.html 0644 bin bin 23934 27799 1260169409 1 f none subversion/svnbook/svn.advanced.html 0644 bin bin 10898 12108 1260169409 1 f none subversion/svnbook/svn.advanced.l10n.html 0644 bin bin 11605 33482 1260169409 1 f none subversion/svnbook/svn.advanced.locking.html 0644 bin bin 38337 30524 1260169409 1 f none subversion/svnbook/svn.advanced.pegrevs.html 0644 bin bin 21708 35939 1260169409 1 f none subversion/svnbook/svn.advanced.props.file-portability.html 0644 bin bin 21113 58926 1260169409 1 f none subversion/svnbook/svn.advanced.props.html 0644 bin bin 37348 24571 1260169409 1 f none subversion/svnbook/svn.advanced.props.special.ignore.html 0644 bin bin 20280 32255 1260169409 1 f none subversion/svnbook/svn.advanced.props.special.keywords.html 0644 bin bin 19496 16928 1260169409 1 f none subversion/svnbook/svn.advanced.sparsedirs.html 0644 bin bin 16097 27084 1260169409 1 f none subversion/svnbook/svn.advanced.summary.html 0644 bin bin 4018 57026 1260169409 1 f none subversion/svnbook/svn.advanced.vendorbr.html 0644 bin bin 22882 5841 1260169409 1 f none subversion/svnbook/svn.basic.html 0644 bin bin 7080 54834 1260169409 1 f none subversion/svnbook/svn.basic.in-action.html 0644 bin bin 37194 21761 1260169409 1 f none subversion/svnbook/svn.basic.repository.html 0644 bin bin 5457 52933 1260169409 1 f none subversion/svnbook/svn.basic.summary.html 0644 bin bin 4044 56131 1260169409 1 f none subversion/svnbook/svn.basic.vsn-models.html 0644 bin bin 16205 61767 1260169409 1 f none subversion/svnbook/svn.branchmerge.advanced.html 0644 bin bin 51392 26134 1260169409 1 f none subversion/svnbook/svn.branchmerge.basicmerging.html 0644 bin bin 43452 58255 1260169409 1 f none subversion/svnbook/svn.branchmerge.commonpatterns.html 0644 bin bin 12750 47146 1260169409 1 f none subversion/svnbook/svn.branchmerge.html 0644 bin bin 12175 13375 1260169409 1 f none subversion/svnbook/svn.branchmerge.maint.html 0644 bin bin 10330 64022 1260169409 1 f none subversion/svnbook/svn.branchmerge.summary.html 0644 bin bin 9877 43868 1260169409 1 f none subversion/svnbook/svn.branchmerge.switchwc.html 0644 bin bin 11391 15441 1260169409 1 f none subversion/svnbook/svn.branchmerge.tags.html 0644 bin bin 11090 60520 1260169409 1 f none subversion/svnbook/svn.branchmerge.using.html 0644 bin bin 21606 30954 1260169409 1 f none subversion/svnbook/svn.branchmerge.whatis.html 0644 bin bin 5362 43175 1260169409 1 f none subversion/svnbook/svn.copyright.html 0644 bin bin 17399 13517 1260169409 1 f none subversion/svnbook/svn.customization.html 0644 bin bin 6805 43811 1260169409 1 f none subversion/svnbook/svn.customization.summary.html 0644 bin bin 3953 60084 1260169409 1 f none subversion/svnbook/svn.developer.html 0644 bin bin 7046 7382 1260169409 1 f none subversion/svnbook/svn.developer.insidewc.html 0644 bin bin 9474 56565 1260169409 1 f none subversion/svnbook/svn.developer.layerlib.html 0644 bin bin 34042 29432 1260169409 1 f none subversion/svnbook/svn.developer.summary.html 0644 bin bin 3852 49230 1260169409 1 f none subversion/svnbook/svn.developer.usingapi.html 0644 bin bin 36307 21392 1260169409 1 f none subversion/svnbook/svn.forcvs.auth.html 0644 bin bin 4504 40847 1260169409 1 f none subversion/svnbook/svn.forcvs.binary-and-trans.html 0644 bin bin 5841 27690 1260169409 1 f none subversion/svnbook/svn.forcvs.branches-and-tags.html 0644 bin bin 5034 4648 1260169409 1 f none subversion/svnbook/svn.forcvs.conflicts.html 0644 bin bin 4355 28220 1260169409 1 f none subversion/svnbook/svn.forcvs.convert.html 0644 bin bin 4578 48484 1260169409 1 f none subversion/svnbook/svn.forcvs.directories.html 0644 bin bin 6976 51676 1260169409 1 f none subversion/svnbook/svn.forcvs.disconnected.html 0644 bin bin 5667 58155 1260169409 1 f none subversion/svnbook/svn.forcvs.html 0644 bin bin 6059 62066 1260169409 1 f none subversion/svnbook/svn.forcvs.modules.html 0644 bin bin 3572 24898 1260169409 1 f none subversion/svnbook/svn.forcvs.properties.html 0644 bin bin 3759 41324 1260169409 1 f none subversion/svnbook/svn.forcvs.revnums.html 0644 bin bin 5557 63967 1260169409 1 f none subversion/svnbook/svn.forcvs.status-vs-update.html 0644 bin bin 9511 38303 1260169409 1 f none subversion/svnbook/svn.foreword.html 0644 bin bin 9224 55678 1260169409 1 f none subversion/svnbook/svn.index.html 0644 bin bin 15811 19104 1260169409 1 f none subversion/svnbook/svn.intro.html 0644 bin bin 4521 24978 1260169409 1 f none subversion/svnbook/svn.intro.install.html 0644 bin bin 7884 63158 1260169409 1 f none subversion/svnbook/svn.intro.quickstart.html 0644 bin bin 11481 34510 1260169409 1 f none subversion/svnbook/svn.intro.whatis.html 0644 bin bin 21584 1754 1260169409 1 f none subversion/svnbook/svn.preface.acks.html 0644 bin bin 12303 35921 1260169409 1 f none subversion/svnbook/svn.preface.audience.html 0644 bin bin 5035 17161 1260169409 1 f none subversion/svnbook/svn.preface.conventions.html 0644 bin bin 5888 45162 1260169409 1 f none subversion/svnbook/svn.preface.free.html 0644 bin bin 4855 62642 1260169409 1 f none subversion/svnbook/svn.preface.howread.html 0644 bin bin 8524 41697 1260169409 1 f none subversion/svnbook/svn.preface.html 0644 bin bin 8468 44817 1260169409 1 f none subversion/svnbook/svn.preface.organization.html 0644 bin bin 9738 21868 1260169409 1 f none subversion/svnbook/svn.ref.html 0644 bin bin 31410 54283 1260169409 1 f none subversion/svnbook/svn.ref.mod_authz_svn.conf.html 0644 bin bin 6916 7182 1260169409 1 f none subversion/svnbook/svn.ref.mod_authz_svn.html 0644 bin bin 3056 46552 1260169409 1 f none subversion/svnbook/svn.ref.mod_dav_svn.conf.html 0644 bin bin 18595 30936 1260169409 1 f none subversion/svnbook/svn.ref.mod_dav_svn.html 0644 bin bin 2975 38318 1260169409 1 f none subversion/svnbook/svn.ref.properties.html 0644 bin bin 11615 21658 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.html 0644 bin bin 3050 45099 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-commit.html 0644 bin bin 4702 41009 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-lock.html 0644 bin bin 4571 27331 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-revprop-change.html 0644 bin bin 5527 37750 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.post-unlock.html 0644 bin bin 4613 32390 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-commit.html 0644 bin bin 4575 30042 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-lock.html 0644 bin bin 4722 39708 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-revprop-change.html 0644 bin bin 5341 23012 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.pre-unlock.html 0644 bin bin 4749 40732 1260169409 1 f none subversion/svnbook/svn.ref.reposhooks.start-commit.html 0644 bin bin 4789 43588 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.add.html 0644 bin bin 5716 44716 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.blame.html 0644 bin bin 6026 7998 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.cat.html 0644 bin bin 5621 32571 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.changelist.html 0644 bin bin 5353 14962 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.checkout.html 0644 bin bin 6796 7230 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.cleanup.html 0644 bin bin 5314 18933 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.commit.html 0644 bin bin 7954 28998 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.copy.html 0644 bin bin 10441 53250 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.delete.html 0644 bin bin 6227 25010 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.diff.html 0644 bin bin 15967 21752 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.export.html 0644 bin bin 6476 42555 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.help.html 0644 bin bin 4234 62260 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.import.html 0644 bin bin 6199 21757 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.info.html 0644 bin bin 9762 1094 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.list.html 0644 bin bin 7774 5835 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.lock.html 0644 bin bin 5372 20423 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.log.html 0644 bin bin 15240 34609 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.merge.html 0644 bin bin 8477 6427 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.mergeinfo.html 0644 bin bin 5821 59348 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.mkdir.html 0644 bin bin 5267 12256 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.move.html 0644 bin bin 7306 16543 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propdel.html 0644 bin bin 5067 65340 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propedit.html 0644 bin bin 5401 29925 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propget.html 0644 bin bin 5525 37728 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.proplist.html 0644 bin bin 5785 57858 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.propset.html 0644 bin bin 8585 9813 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.resolve.html 0644 bin bin 7454 40098 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.resolved.html 0644 bin bin 6750 64897 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.revert.html 0644 bin bin 6525 41864 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.status.html 0644 bin bin 19826 21074 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.switch.html 0644 bin bin 11812 58 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.unlock.html 0644 bin bin 5214 10302 1260169409 1 f none subversion/svnbook/svn.ref.svn.c.update.html 0644 bin bin 9083 15874 1260169409 1 f none subversion/svnbook/svn.ref.svn.html 0644 bin bin 34950 24069 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.crashtest.html 0644 bin bin 4085 55462 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.create.html 0644 bin bin 5758 53642 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.deltify.html 0644 bin bin 4158 494 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.dump.html 0644 bin bin 7446 8675 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.help.html 0644 bin bin 3708 27581 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.hotcopy.html 0644 bin bin 5260 18630 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.list-dblogs.html 0644 bin bin 4138 1916 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.list-unused-dblogs.html 0644 bin bin 4539 32721 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.load.html 0644 bin bin 4815 51145 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.lslocks.html 0644 bin bin 4439 17521 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.lstxns.html 0644 bin bin 4007 54941 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.pack.html 0644 bin bin 3749 33081 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.recover.html 0644 bin bin 5556 54822 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.rmlocks.html 0644 bin bin 4136 61077 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.rmtxns.html 0644 bin bin 4439 24443 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.setlog.html 0644 bin bin 5329 19126 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.setrevprop.html 0644 bin bin 4755 47610 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.setuuid.html 0644 bin bin 4760 46077 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.upgrade.html 0644 bin bin 5405 25740 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.c.verify.html 0644 bin bin 4487 25143 1260169409 1 f none subversion/svnbook/svn.ref.svnadmin.html 0644 bin bin 10767 63822 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.commands.c.exclude.html 0644 bin bin 4683 45798 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.commands.c.help.html 0644 bin bin 3858 42588 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.commands.c.include.html 0644 bin bin 4735 50006 1260169409 1 f none subversion/svnbook/svn.ref.svndumpfilter.html 0644 bin bin 6664 49123 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.author.html 0644 bin bin 3853 36486 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.cat.html 0644 bin bin 4224 61409 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.changed.html 0644 bin bin 6662 45236 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.date.html 0644 bin bin 3898 38150 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.diff.html 0644 bin bin 5002 58044 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.dirs-changed.html 0644 bin bin 4019 51157 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.help.html 0644 bin bin 4043 53849 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.history.html 0644 bin bin 4713 31258 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.info.html 0644 bin bin 4032 50023 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.lock.html 0644 bin bin 4247 479 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.log.html 0644 bin bin 3861 37000 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.propget.html 0644 bin bin 4395 16035 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.proplist.html 0644 bin bin 4755 44783 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.tree.html 0644 bin bin 4375 9656 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.uuid.html 0644 bin bin 4139 60014 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.c.youngest.html 0644 bin bin 3763 30633 1260169409 1 f none subversion/svnbook/svn.ref.svnlook.html 0644 bin bin 7817 4061 1260169409 1 f none subversion/svnbook/svn.ref.svnserve.html 0644 bin bin 12072 11255 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.copy-revprops.html 0644 bin bin 5144 14512 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.help.html 0644 bin bin 3949 44955 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.info.html 0644 bin bin 4451 20340 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.init.html 0644 bin bin 5384 35513 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.c.sync.html 0644 bin bin 5409 36647 1260169409 1 f none subversion/svnbook/svn.ref.svnsync.html 0644 bin bin 9737 22720 1260169409 1 f none subversion/svnbook/svn.ref.svnversion.html 0644 bin bin 2973 38456 1260169409 1 f none subversion/svnbook/svn.ref.svnversion.re.html 0644 bin bin 7636 944 1260169409 1 f none subversion/svnbook/svn.reposadmin.basics.html 0644 bin bin 7085 41486 1260169409 1 f none subversion/svnbook/svn.reposadmin.create.html 0644 bin bin 20163 3556 1260169409 1 f none subversion/svnbook/svn.reposadmin.html 0644 bin bin 12514 44116 1260169409 1 f none subversion/svnbook/svn.reposadmin.maint.html 0644 bin bin 127526 61226 1260169409 1 f none subversion/svnbook/svn.reposadmin.maint.moving-and-removing.html 0644 bin bin 5337 51132 1260169409 1 f none subversion/svnbook/svn.reposadmin.planning.html 0644 bin bin 38161 51064 1260169409 1 f none subversion/svnbook/svn.reposadmin.summary.html 0644 bin bin 3587 27454 1260169409 1 f none subversion/svnbook/svn.serverconfig.choosing.html 0644 bin bin 16017 62326 1260169409 1 f none subversion/svnbook/svn.serverconfig.html 0644 bin bin 13350 21447 1260169409 1 f none subversion/svnbook/svn.serverconfig.httpd.html 0644 bin bin 82508 29837 1260169409 1 f none subversion/svnbook/svn.serverconfig.multimethod.html 0644 bin bin 10094 38681 1260169409 1 f none subversion/svnbook/svn.serverconfig.netmodel.html 0644 bin bin 18503 61765 1260169409 1 f none subversion/svnbook/svn.serverconfig.overview.html 0644 bin bin 10131 5414 1260169409 1 f none subversion/svnbook/svn.serverconfig.pathbasedauthz.html 0644 bin bin 18621 50850 1260169409 1 f none subversion/svnbook/svn.serverconfig.svnserve.html 0644 bin bin 54349 26593 1260169409 1 f none subversion/svnbook/svn.tour.cleanup.html 0644 bin bin 7103 52266 1260169409 1 f none subversion/svnbook/svn.tour.cycle.html 0644 bin bin 66678 36616 1260169409 1 f none subversion/svnbook/svn.tour.help.html 0644 bin bin 5326 33749 1260169409 1 f none subversion/svnbook/svn.tour.history.html 0644 bin bin 24053 15757 1260169409 1 f none subversion/svnbook/svn.tour.html 0644 bin bin 12688 31192 1260169409 1 f none subversion/svnbook/svn.tour.importing.html 0644 bin bin 6620 15853 1260169409 1 f none subversion/svnbook/svn.tour.initial.html 0644 bin bin 14437 18251 1260169409 1 f none subversion/svnbook/svn.tour.revs.specifiers.html 0644 bin bin 13832 26151 1260169409 1 f none subversion/svnbook/svn.tour.summary.html 0644 bin bin 3690 35163 1260169409 1 f none subversion/svnbook/svn.tour.treeconflicts.html 0644 bin bin 16529 43183 1260169409 1 f none subversion/svnbook/svn.webdav.autoversioning.html 0644 bin bin 8556 59756 1260169409 1 f none subversion/svnbook/svn.webdav.basic.html 0644 bin bin 7833 64390 1260169409 1 f none subversion/svnbook/svn.webdav.clients.html 0644 bin bin 25741 2759 1260169409 1 f none subversion/svnbook/svn.webdav.html 0644 bin bin 6812 35580 1260169409 1 d none subversion/tools 0755 bin bin 1 d none subversion/tools/bdb 0755 bin bin 1 f none subversion/tools/bdb/erase-all-text-data.py 0755 bin bin 2211 41563 1230083891 1 f none subversion/tools/bdb/skel.py 0644 bin bin 6379 25645 1224435754 1 f none subversion/tools/bdb/svn-bdb-view.py 0755 bin bin 7726 45315 1233348466 1 f none subversion/tools/bdb/svnfs.py 0644 bin bin 2295 50390 1188090288 1 f none subversion/tools/bdb/whatis-rep.py 0755 bin bin 1674 63417 1230083891 1 d none subversion/tools/cgi 0755 bin bin 1 f none subversion/tools/cgi/mirror_dir_through_svn.README 0644 bin bin 3082 13610 1062093803 1 f none subversion/tools/cgi/mirror_dir_through_svn.cgi 0755 bin bin 6645 64371 1206456152 1 f none subversion/tools/cgi/tweak-log.cgi 0644 bin bin 10422 30545 1192032640 1 d none subversion/tools/client-side 0755 bin bin 1 f none subversion/tools/client-side/asvn 0755 bin bin 11406 446 1201479865 1 f none subversion/tools/client-side/diff-wrap.sh 0755 bin bin 1465 54160 1205172428 1 f none subversion/tools/client-side/diff3wrap.bat 0644 bin bin 870 7708 1120723506 1 f none subversion/tools/client-side/diffwrap.bat 0644 bin bin 503 41357 1213103562 1 d none subversion/tools/client-side/emacs 0755 bin bin 1 f none subversion/tools/client-side/emacs/dsvn.el 0644 bin bin 76185 29274 1243350930 1 f none subversion/tools/client-side/emacs/psvn.el 0644 bin bin 297077 63375 1234388114 1 f none subversion/tools/client-side/emacs/vc-svn.el 0644 bin bin 18514 35473 1174028619 1 f none subversion/tools/client-side/incremental-update.py 0755 bin bin 6038 12754 1188090288 1 f none subversion/tools/client-side/search-svnlog.pl 0755 bin bin 3227 55404 1206456152 1 f none subversion/tools/client-side/svn-clean 0755 bin bin 6564 47482 1201381347 1 f none subversion/tools/client-side/svn-hgmerge.py 0755 bin bin 1963 37155 1213716052 1 f none subversion/tools/client-side/svn-log.pl 0644 bin bin 736 57837 1188090288 1 f none subversion/tools/client-side/svn-merge-vendor.py 0755 bin bin 18252 43981 1192781826 1 d none subversion/tools/client-side/svn-push 0755 bin bin 1 f none subversion/tools/client-side/svn-push/svn-push.c 0644 bin bin 6126 35042 1232851210 1 f none subversion/tools/client-side/svn-resolve 0755 bin bin 3284 56393 1149730698 1 f none subversion/tools/client-side/svn-viewdiff 0755 bin bin 4796 22362 1143668223 1 d none subversion/tools/client-side/svn2cl 0755 bin bin 1 f none subversion/tools/client-side/svn2cl/NEWS 0644 bin bin 3232 15258 1229874436 1 f none subversion/tools/client-side/svn2cl/README 0644 bin bin 4226 24672 1207491166 1 f none subversion/tools/client-side/svn2cl/TODO 0644 bin bin 457 42374 1207491166 1 f none subversion/tools/client-side/svn2cl/authors.xml 0644 bin bin 374 32262 1161209035 1 f none subversion/tools/client-side/svn2cl/svn2cl.1 0644 bin bin 8399 59978 1229874436 1 f none subversion/tools/client-side/svn2cl/svn2cl.sh 0755 bin bin 11155 34097 1229874436 1 f none subversion/tools/client-side/svn2cl/svn2cl.xsl 0644 bin bin 17216 7108 1229874436 1 f none subversion/tools/client-side/svn2cl/svn2html.css 0644 bin bin 1218 34123 1144705185 1 f none subversion/tools/client-side/svn2cl/svn2html.xsl 0644 bin bin 7360 62250 1229874436 1 f none subversion/tools/client-side/svn_all_diffs.pl 0755 bin bin 3927 45696 1206456152 1 f none subversion/tools/client-side/svn_apply_autoprops.py 0755 bin bin 4764 763 1153366888 1 f none subversion/tools/client-side/svn_export_empty_files.py 0755 bin bin 14560 12242 1197931724 1 d none subversion/tools/client-side/svn_load_dirs 0755 bin bin 1 f none subversion/tools/client-side/svn_load_dirs/LICENSE_AFL3.txt 0644 bin bin 10962 53979 1255352236 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs.README 0644 bin bin 9577 37287 1174028619 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs.pl 0755 bin bin 67158 20860 1260208980 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs.pl.in 0755 bin bin 67162 21017 1255352236 1 f none subversion/tools/client-side/svn_load_dirs/svn_load_dirs_property_table.example 0644 bin bin 1334 51041 1174028619 1 f none subversion/tools/client-side/svn_update.pl 0755 bin bin 9999 57147 1191617780 1 d none subversion/tools/client-side/svncopy 0755 bin bin 1 f none subversion/tools/client-side/svncopy/svncopy.README 0644 bin bin 9772 62860 1174028619 1 f none subversion/tools/client-side/svncopy/svncopy.pl 0755 bin bin 31528 17695 1260208980 1 f none subversion/tools/client-side/svncopy/svncopy.pl.in 0644 bin bin 31532 17852 1174028619 1 f none subversion/tools/client-side/svncopy/testsvncopy.pl 0755 bin bin 31911 55974 1260208980 1 f none subversion/tools/client-side/svncopy/testsvncopy.pl.in 0644 bin bin 31915 56131 1174028619 1 d none subversion/tools/client-side/svnmerge 0755 bin bin 1 f none subversion/tools/client-side/svnmerge/svnmerge-migrate-history-remotely.py 0755 bin bin 18703 28884 1232490354 1 f none subversion/tools/client-side/svnmerge/svnmerge-migrate-history.py 0755 bin bin 16115 10755 1234816525 1 f none subversion/tools/client-side/svnmerge/svnmerge-migrate-test.sh 0755 bin bin 2925 23971 1210699417 1 f none subversion/tools/client-side/svnmerge/svnmerge.README 0644 bin bin 1011 23837 1174028619 1 f none subversion/tools/client-side/svnmerge/svnmerge.py 0755 bin bin 83614 10837 1238432827 1 f none subversion/tools/client-side/svnmerge/svnmerge.sh 0755 bin bin 24391 19700 1174028619 1 f none subversion/tools/client-side/svnmerge/svnmerge_test.py 0755 bin bin 51249 3383 1213801523 1 d none subversion/tools/client-side/vim 0755 bin bin 1 f none subversion/tools/client-side/vim/diff-to-logmsg.vim 0644 bin bin 1126 26938 1174028619 1 f none subversion/tools/client-side/vim/svn.vim 0644 bin bin 1891 31307 1174028619 1 f none subversion/tools/client-side/wcgrep 0755 bin bin 2387 56942 1079640774 1 d none subversion/tools/examples 0755 bin bin 1 f none subversion/tools/examples/SvnCLBrowse 0755 bin bin 18255 2452 1203641040 1 f none subversion/tools/examples/blame.py 0755 bin bin 2270 39708 1230083891 1 f none subversion/tools/examples/check-modified.py 0755 bin bin 885 2591 1230083891 1 f none subversion/tools/examples/dumpprops.py 0755 bin bin 1499 59171 1230083891 1 f none subversion/tools/examples/get-location-segments.py 0755 bin bin 2845 43770 1230083891 1 f none subversion/tools/examples/getfile.py 0755 bin bin 1073 22467 1230083891 1 f none subversion/tools/examples/getlocks_test.c 0644 bin bin 8454 4204 1188090288 1 f none subversion/tools/examples/geturl.py 0755 bin bin 565 45855 1230083891 1 f none subversion/tools/examples/headrev.c 0644 bin bin 7041 34277 1188090288 1 f none subversion/tools/examples/minimal_client.c 0644 bin bin 9261 8663 1188090288 1 f none subversion/tools/examples/putfile.py 0755 bin bin 1737 11999 1230083891 1 f none subversion/tools/examples/revplist.py 0755 bin bin 1800 8534 1230083891 1 f none subversion/tools/examples/svnlog2html.rb 0755 bin bin 1804 10819 1191617780 1 f none subversion/tools/examples/svnlook.py 0755 bin bin 12461 64531 1230083891 1 f none subversion/tools/examples/svnlook.rb 0755 bin bin 13104 45496 1191617780 1 f none subversion/tools/examples/svnput.c 0644 bin bin 11442 45264 1188090288 1 f none subversion/tools/examples/svnserve-sgid.c 0644 bin bin 1047 21639 1122158619 1 f none subversion/tools/examples/svnshell.py 0755 bin bin 10989 2021 1233348466 1 f none subversion/tools/examples/svnshell.rb 0755 bin bin 11018 20386 1191617780 1 f none subversion/tools/examples/testwrite.c 0644 bin bin 8714 38746 1188090288 1 d none subversion/tools/hook-scripts 0755 bin bin 1 f none subversion/tools/hook-scripts/README 0644 bin bin 95 8751 1146507500 1 f none subversion/tools/hook-scripts/case-insensitive.py 0755 bin bin 4782 7009 1192658646 1 f none subversion/tools/hook-scripts/check-mime-type.pl 0755 bin bin 6527 40004 1191617780 1 f none subversion/tools/hook-scripts/commit-access-control.cfg.example 0644 bin bin 2982 59946 1047448581 1 f none subversion/tools/hook-scripts/commit-access-control.pl 0755 bin bin 11503 5137 1260208980 1 f none subversion/tools/hook-scripts/commit-access-control.pl.in 0755 bin bin 11507 5294 1206456152 1 f none subversion/tools/hook-scripts/commit-block-joke.py 0755 bin bin 2147 41160 1192032640 1 f none subversion/tools/hook-scripts/commit-email.pl 0755 bin bin 26475 44253 1260208980 1 f none subversion/tools/hook-scripts/commit-email.pl.in 0755 bin bin 26479 44410 1226379622 1 f none subversion/tools/hook-scripts/commit-email.rb 0755 bin bin 2128 43705 1217571213 1 f none subversion/tools/hook-scripts/detect-merge-conflicts.sh 0755 bin bin 1106 23452 1176749122 1 d none subversion/tools/hook-scripts/enforcer 0755 bin bin 1 f none subversion/tools/hook-scripts/enforcer/enforcer 0755 bin bin 17259 35519 1228503354 1 f none subversion/tools/hook-scripts/enforcer/enforcer.conf 0644 bin bin 3609 10487 1177098861 1 f none subversion/tools/hook-scripts/log-police.py 0755 bin bin 4399 46185 1232852708 1 d none subversion/tools/hook-scripts/mailer 0755 bin bin 1 f none subversion/tools/hook-scripts/mailer/mailer.conf.example 0644 bin bin 12898 12415 1190733357 1 f none subversion/tools/hook-scripts/mailer/mailer.py 0755 bin bin 45385 33269 1233369365 1 d none subversion/tools/hook-scripts/mailer/tests 0755 bin bin 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-init.sh 0755 bin bin 2315 65138 1206456152 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-t1.output 0644 bin bin 14332 24192 1190733357 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-t1.sh 0755 bin bin 938 12195 1223164281 1 f none subversion/tools/hook-scripts/mailer/tests/mailer-tweak.py 0755 bin bin 1116 24890 1230083891 1 f none subversion/tools/hook-scripts/mailer/tests/mailer.conf 0644 bin bin 13003 21546 1190733357 1 f none subversion/tools/hook-scripts/pre-commit-check.py 0755 bin bin 3150 5474 1192032640 1 f none subversion/tools/hook-scripts/pre-lock-require-needs-lock.py 0755 bin bin 1809 21407 1192032640 1 f none subversion/tools/hook-scripts/remove-zombie-locks.py 0755 bin bin 6725 41042 1188090288 1 f none subversion/tools/hook-scripts/require-mergeinfo.pl 0755 bin bin 1112 30006 1231516768 1 f none subversion/tools/hook-scripts/svn-keyword-check.pl 0755 bin bin 8341 403 1210875854 1 f none subversion/tools/hook-scripts/svn2feed.py 0755 bin bin 16469 51791 1234542146 1 f none subversion/tools/hook-scripts/svnperms.conf.example 0644 bin bin 3089 2816 1125010600 1 f none subversion/tools/hook-scripts/svnperms.py 0755 bin bin 11815 21449 1230151759 1 f none subversion/tools/hook-scripts/syntax-check.sh 0755 bin bin 5551 8984 1200499795 1 f none subversion/tools/hook-scripts/verify-po.py 0755 bin bin 3158 54367 1232863744 1 d none subversion/tools/server-side 0755 bin bin 1 f none subversion/tools/server-side/add-needs-lock.py 0755 bin bin 6471 53556 1217430515 1 f none subversion/tools/server-side/authz_svn_group.py 0755 bin bin 5911 22827 1149001637 1 f none subversion/tools/server-side/backup-recipe.sh 0755 bin bin 9273 14138 1086641239 1 f none subversion/tools/server-side/fsfsverify.py 0755 bin bin 33899 39130 1203370596 1 f none subversion/tools/server-side/load_repo_with_mergesensitive_copy.sh 0755 bin bin 4319 31367 1191856145 1 d none subversion/tools/server-side/mod_dontdothat 0755 bin bin 1 f none subversion/tools/server-side/mod_dontdothat/README 0644 bin bin 1902 37593 1209132877 1 f none subversion/tools/server-side/mod_dontdothat/mod_dontdothat.c 0644 bin bin 18623 24093 1208357277 1 f none subversion/tools/server-side/svn-fast-backup 0755 bin bin 9952 2396 1168920422 1 f none subversion/tools/server-side/svn-tweak-author.py 0755 bin bin 4687 48017 1188090288 1 f none subversion/tools/server-side/svnmirror-test.sh 0755 bin bin 3281 33561 1228426298 1 f none subversion/tools/server-side/svnmirror.sh 0755 bin bin 12334 50961 1139348169 07070100027251000041ed000017820000044e000000034b1d457a000000000000022d0000016a00000000000000000000000600000000reloc 07070100027252000041ed000017820000044e000000054b1d4582000000000000022d0000016a00000000000000000000001100000000reloc/subversion 070701000272ba000041ed000017820000044e000000034b1d4582000000000000022d0000016a00000000000000000000001900000000reloc/subversion/svnbook 070701000272f4000081a4000017820000044e000000014b1ca8c100000f0c0000022d0000016a00000000000000000000003400000000reloc/subversion/svnbook/svn.developer.summary.html
One of Subversion's greatest features isn't something you get from running its command-line client or other tools. It's the fact that Subversion was designed modularly and provides a stable, public API so that others—like yourself, perhaps—can write custom software that drives Subversion's core logic.
In this chapter, we took a closer look at Subversion's architecture, examining its logical layers and describing that public API, the very same API that Subversion's own layers use to communicate with each other. Many developers have found interesting uses for the Subversion API, from simple repository hook scripts, to integrations between Subversion and some other application, to completely different version control systems. What unique itch will you scratch with it?
Table of Contents
Version control can be a complex subject, as much art as science, that offers myriad ways of getting stuff done. Throughout this book, you've read of the various Subversion command-line client subcommands and the options that modify their behavior. In this chapter, we'll look into still more ways to customize the way Subversion works for you—setting up the Subversion runtime configuration, using external helper applications, Subversion's interaction with the operating system's configured locale, and so on.
svn mergeinfo — Query merge-related information. See the section called “Mergeinfo and Previews†for details.
Query information related to merges (or potential
merges) between SOURCE-URL
and
TARGET
. If
the --show-revs
option is not provided,
display revisions which have been merged
from SOURCE-URL
to TARGET
. Otherwise, display
either merged
or eligible
revisions as specified by
the --show-revs
option.
Find out which changesets your have been merged from your trunk directory into your test branch:
$ svn pget svn:mergeinfo ^/branches/test /branches/other:3-4 /trunk:11-13,14,16 $ svn mergeinfo --show-revs merged ^/trunk ^/branches/test r11 r12 r13 r14 r16 $
Note that the default output from the svn
mergeinfo command is to display merged revisions, so
the --show-revs
option shown in the
command line of the previous example is not strictly
required.
Find out which changesets from your trunk directory have not yet been merged into your test branch:
$ svn mergeinfo --show-revs eligible ^/trunk ^/branches/test r15 r17 r20 r21 r22 $
svnadmin upgrade — Upgrade a repository to the latest supported schema version.
Upgrade the repository located
at REPOS_PATH
to the latest
supported schema version.
This functionality is provided as a convenience for repository administrators who wish to make use of new Subversion functionality without having to undertake a potentially costly full repository dump and load operation. As such, the upgrade performs only the minimum amount of work needed to accomplish this while still maintaining the integrity of the repository. While a dump and subsequent load guarantee the most optimized repository state, svnadmin upgrade does not.
Warning | |
---|---|
You should always back up your repository before upgrading. |
svnadmin load — Read a
repository dump stream from
stdin
.
Read a repository dump stream from
stdin
, committing new revisions into the repository's
filesystem. Send progress feedback to stdout
.
--force-uuid --ignore-uuid --parent-dir --quiet (-q) --use-post-commit-hook --use-pre-commit-hook
This shows the beginning of loading a repository from a backup file (made, of course, with svnadmin dump):
$ svnadmin load /var/svn/restored < repos-backup <<< Started new txn, based on original revision 1 * adding path : test ... done. * adding path : test/a ... done. …
Or if you want to load into a subdirectory:
$ svnadmin load --parent-dir new/subdir/for/project \ /var/svn/restored < repos-backup <<< Started new txn, based on original revision 1 * adding path : test ... done. * adding path : test/a ... done. …
Subversion's copy-modify-merge version control model lives and dies on its data merging algorithms—specifically on how well those algorithms perform when trying to resolve conflicts caused by multiple users modifying the same file concurrently. Subversion itself provides only one such algorithm: a three-way differencing algorithm that is smart enough to handle data at a granularity of a single line of text. Subversion also allows you to supplement its content merge processing with external differencing utilities (as described in the section called “External diff3â€), some of which may do an even better job, perhaps providing granularity of a word or a single character of text. But common among those algorithms is that they generally work only on text files. The landscape starts to look pretty grim when you start talking about content merges of nontextual file formats. And when you can't find a tool that can handle that type of merging, you begin to run into problems with the copy-modify-merge model.
Let's look at a real-life example of where this model runs aground. Harry and Sally are both graphic designers working on the same project, a bit of marketing collateral for an automobile mechanic. Central to the design of a particular poster is an image of a car in need of some bodywork, stored in a file using the PNG image format. The poster's layout is almost finished, and both Harry and Sally are pleased with the particular photo they chose for their damaged car—a baby blue 1967 Ford Mustang with an unfortunate bit of crumpling on the left front fender.
Now, as is common in graphic design work, there's a change
in plans, which causes the car's color to be a concern. So Sally
updates her working copy to HEAD
, fires up
her photo-editing software, and sets about tweaking the image so
that the car is now cherry red. Meanwhile, Harry, feeling
particularly inspired that day, decides that the image would
have greater impact if the car also appears to have suffered
greater impact. He, too, updates to HEAD
,
and then draws some cracks on the vehicle's windshield. He
manages to finish his work before Sally finishes hers, and after
admiring the fruits of his undeniable talent, he commits the
modified image. Shortly thereafter, Sally is finished with the
car's new finish and tries to commit her changes. But, as
expected, Subversion fails the commit, informing Sally that
her version of the image is now out of date.
Here's where the difficulty sets in. If Harry and Sally were making changes to a text file, Sally would simply update her working copy, receiving Harry's changes in the process. In the worst possible case, they would have modified the same region of the file, and Sally would have to work out by hand the proper resolution to the conflict. But these aren't text files—they are binary images. And while it's a simple matter to describe what one would expect the results of this content merge to be, there is precious little chance that any software exists that is smart enough to examine the common baseline image that each of these graphic artists worked against, the changes that Harry made, and the changes that Sally made, and then spit out an image of a busted-up red Mustang with a cracked windshield!
Of course, things would have gone more smoothly if Harry and Sally had serialized their modifications to the image—if, say, Harry had waited to draw his windshield cracks on Sally's now-red car, or if Sally had tweaked the color of a car whose windshield was already cracked. As is discussed in the section called “The Copy-Modify-Merge Solutionâ€, most of these types of problems go away entirely where perfect communication between Harry and Sally exists. [14] But as one's version control system is, in fact, one form of communication, it follows that having that software facilitate the serialization of nonparallelizable editing efforts is no bad thing. This is where Subversion's implementation of the lock-modify-unlock model steps into the spotlight. This is where we talk about Subversion's locking feature, which is similar to the “reserved checkouts†mechanisms of other version control systems.
Subversion's locking feature exists ultimately to minimize wasted time and effort. By allowing a user to programmatically claim the exclusive right to change a file in the repository, that user can be reasonably confident that any energy he invests on unmergeable changes won't be wasted—his commit of those changes will succeed. Also, because Subversion communicates to other users that serialization is in effect for a particular versioned object, those users can reasonably expect that the object is about to be changed by someone else. They, too, can then avoid wasting their time and energy on unmergeable changes that won't be committable due to eventual out-of-dateness.
When referring to Subversion's locking feature, one is actually talking about a fairly diverse collection of behaviors, which include the ability to lock a versioned file [15] (claiming the exclusive right to modify the file), to unlock that file (yielding that exclusive right to modify), to see reports about which files are locked and by whom, to annotate files for which locking before editing is strongly advised, and so on. In this section, we'll cover all of these facets of the larger locking feature.
In the Subversion repository, a lock is a piece of metadata that grants exclusive access to one user to change a file. This user is said to be the lock owner. Each lock also has a unique identifier, typically a long string of characters, known as the lock token. The repository manages locks, ultimately handling their creation, enforcement, and removal. If any commit transaction attempts to modify or delete a locked file (or delete one of the parent directories of the file), the repository will demand two pieces of information—that the client performing the commit be authenticated as the lock owner, and that the lock token has been provided as part of the commit process as a form of proof that the client knows which lock it is using.
To demonstrate lock creation, let's refer back to our example of multiple graphic designers working on the same binary image files. Harry has decided to change a JPEG image. To prevent other people from committing changes to the file while he is modifying it (as well as alerting them that he is about to change it), he locks the file in the repository using the svn lock command.
$ svn lock banana.jpg -m "Editing file for tomorrow's release." 'banana.jpg' locked by user 'harry'. $
The preceding example demonstrates a number of new things.
First, notice that Harry passed the
--message
(-m
) option to
svn lock. Similar to svn
commit, the svn lock command can
take comments—via either --message
(-m
) or --file
(-F
)—to describe the reason for locking the
file. Unlike svn commit, however,
svn lock will not demand a message by
launching your preferred text editor. Lock comments are
optional, but still recommended to aid communication.
Second, the lock attempt succeeded. This means that the file wasn't already locked, and that Harry had the latest version of the file. If Harry's working copy of the file had been out of date, the repository would have rejected the request, forcing Harry to svn update and reattempt the locking command. The locking command would also have failed if the file had already been locked by someone else.
As you can see, the svn lock command prints confirmation of the successful lock. At this point, the fact that the file is locked becomes apparent in the output of the svn status and svn info reporting subcommands.
$ svn status K banana.jpg $ svn info banana.jpg Path: banana.jpg Name: banana.jpg URL: http://svn.example.com/repos/project/banana.jpg Repository UUID: edb2f264-5ef2-0310-a47a-87b0ce17a8ec Revision: 2198 Node Kind: file Schedule: normal Last Changed Author: frank Last Changed Rev: 1950 Last Changed Date: 2006-03-15 12:43:04 -0600 (Wed, 15 Mar 2006) Text Last Updated: 2006-06-08 19:23:07 -0500 (Thu, 08 Jun 2006) Properties Last Updated: 2006-06-08 19:23:07 -0500 (Thu, 08 Jun 2006) Checksum: 3b110d3b10638f5d1f4fe0f436a5a2a5 Lock Token: opaquelocktoken:0c0f600b-88f9-0310-9e48-355b44d4a58e Lock Owner: harry Lock Created: 2006-06-14 17:20:31 -0500 (Wed, 14 Jun 2006) Lock Comment (1 line): Editing file for tomorrow's release. $
The fact that the svn info command,
which does not contact the repository when run against working
copy paths, can display the lock token reveals an important
piece of information about those tokens: they are cached in
the working copy. The presence of the lock token is critical.
It gives the working copy authorization to make use of the
lock later on. Also, the svn status
command shows a K
next to the file (short
for locKed), indicating that the lock token is present.
Now that Harry has locked banana.jpg
,
Sally is unable to change or delete that file:
$ svn delete banana.jpg D banana.jpg $ svn commit -m "Delete useless file." Deleting banana.jpg svn: Commit failed (details follow): svn: Server sent unexpected return value (423 Locked) in response to DELETE\ request for '/repos/project/!svn/wrk/64bad3a9-96f9-0310-818a-df4224ddc35d/\ banana.jpg' $
But Harry, after touching up the banana's shade of yellow, is able to commit his changes to the file. That's because he authenticates as the lock owner and also because his working copy holds the correct lock token:
$ svn status M K banana.jpg $ svn commit -m "Make banana more yellow" Sending banana.jpg Transmitting file data . Committed revision 2201. $ svn status $
Notice that after the commit is finished, svn
status shows that the lock token is no longer
present in the working copy. This is the standard behavior of
svn commit—it searches the working
copy (or list of targets, if you provide such a list) for
local modifications and sends all the lock tokens it
encounters during this walk to the server as part of the
commit transaction. After the commit completes successfully,
all of the repository locks that were mentioned are
released—even on files that weren't
committed. This is meant to discourage users from
being sloppy about locking or from holding locks for too long.
If Harry haphazardly locks 30 files in a directory named
images
because he's unsure of which files
he needs to change, yet changes only four of those files, when he
runs svn commit images
, the process will
still release all 30 locks.
This behavior of automatically releasing locks can be
overridden with the --no-unlock
option to
svn commit. This is best used for those
times when you want to commit changes, but still plan to make
more changes and thus need to retain existing locks. You can
also make this your default behavior by setting the
no-unlock
runtime configuration option (see
the section called “Runtime Configuration Areaâ€).
Of course, locking a file doesn't oblige one to commit a change to it. The lock can be released at any time with a simple svn unlock command:
$ svn unlock banana.c 'banana.c' unlocked.
When a commit fails due to someone else's locks, it's
fairly easy to learn about them. The easiest way is to run
svn status -u
:
$ svn status -u M 23 bar.c M O 32 raisin.jpg * 72 foo.h Status against revision: 105 $
In this example, Sally can see not only that her copy of
foo.h
is out of date, but also that one of the
two modified files she plans to commit is locked in the
repository. The O
symbol stands for
“Other,†meaning that a lock exists on the file
and was created by somebody else. If she were to attempt a
commit, the lock on raisin.jpg
would
prevent it. Sally is left wondering who made the lock, when,
and why. Once again, svn info has the
answers:
$ svn info http://svn.example.com/repos/project/raisin.jpg Path: raisin.jpg Name: raisin.jpg URL: http://svn.example.com/repos/project/raisin.jpg Repository UUID: edb2f264-5ef2-0310-a47a-87b0ce17a8ec Revision: 105 Node Kind: file Last Changed Author: sally Last Changed Rev: 32 Last Changed Date: 2006-01-25 12:43:04 -0600 (Sun, 25 Jan 2006) Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b Lock Owner: harry Lock Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006) Lock Comment (1 line): Need to make a quick tweak to this image. $
Just as you can use svn info to examine objects in the working copy, you can also use it to examine objects in the repository. If the main argument to svn info is a working copy path, then all of the working copy's cached information is displayed; any mention of a lock means that the working copy is holding a lock token (if a file is locked by another user or in another working copy, svn info on a working copy path will show no lock information at all). If the main argument to svn info is a URL, the information reflects the latest version of an object in the repository, and any mention of a lock describes the current lock on the object.
So in this particular example, Sally can see that Harry locked the file on February 16 to “make a quick tweak.†It being June, she suspects that he probably forgot all about the lock. She might phone Harry to complain and ask him to release the lock. If he's unavailable, she might try to forcibly break the lock herself or ask an administrator to do so.
A repository lock isn't sacred—in Subversion's default configuration state, locks can be released not only by the person who created them, but by anyone. When somebody other than the original lock creator destroys a lock, we refer to this as breaking the lock.
From the administrator's chair, it's simple to break locks. The svnlook and svnadmin programs have the ability to display and remove locks directly from the repository. (For more information about these tools, see the section called “An Administrator's Toolkitâ€.)
$ svnadmin lslocks /var/svn/repos Path: /project2/images/banana.jpg UUID Token: opaquelocktoken:c32b4d88-e8fb-2310-abb3-153ff1236923 Owner: frank Created: 2006-06-15 13:29:18 -0500 (Thu, 15 Jun 2006) Expires: Comment (1 line): Still improving the yellow color. Path: /project/raisin.jpg UUID Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b Owner: harry Created: 2006-02-16 13:29:18 -0500 (Thu, 16 Feb 2006) Expires: Comment (1 line): Need to make a quick tweak to this image. $ svnadmin rmlocks /var/svn/repos /project/raisin.jpg Removed lock on '/project/raisin.jpg'. $
The more interesting option is to allow users to break
each other's locks over the network. To do this, Sally simply
needs to pass the --force
to the svn
unlock command:
$ svn status -u M 23 bar.c M O 32 raisin.jpg * 72 foo.h Status against revision: 105 $ svn unlock raisin.jpg svn: 'raisin.jpg' is not locked in this working copy $ svn info raisin.jpg | grep URL URL: http://svn.example.com/repos/project/raisin.jpg $ svn unlock http://svn.example.com/repos/project/raisin.jpg svn: Unlock request failed: 403 Forbidden (http://svn.example.com) $ svn unlock --force http://svn.example.com/repos/project/raisin.jpg 'raisin.jpg' unlocked. $
Now, Sally's initial attempt to unlock failed because she
ran svn unlock directly on her working copy
of the file, and no lock token was present. To remove the
lock directly from the repository, she needs to pass a URL
to svn unlock. Her first attempt to unlock
the URL fails, because she can't authenticate as the lock
owner (nor does she have the lock token). But when she
passes --force
, the authentication and
authorization requirements are ignored, and the remote lock is
broken.
Simply breaking a lock may not be enough. In
the running example, Sally may not only want to break Harry's
long-forgotten lock, but relock the file for her own use.
She can accomplish this by using svn unlock
with --force
and then svn lock
back-to-back, but there's a small chance that somebody else
might lock the file between the two commands. The simpler thing
to do is to steal the lock, which involves
breaking and relocking the file all in one atomic step. To
do this, Sally passes the --force
option
to svn lock:
$ svn lock raisin.jpg svn: Lock request failed: 423 Locked (http://svn.example.com) $ svn lock --force raisin.jpg 'raisin.jpg' locked by user 'sally'. $
In any case, whether the lock is broken or stolen, Harry may be in for a surprise. Harry's working copy still contains the original lock token, but that lock no longer exists. The lock token is said to be defunct. The lock represented by the lock token has either been broken (no longer in the repository) or stolen (replaced with a different lock). Either way, Harry can see this by asking svn status to contact the repository:
$ svn status K raisin.jpg $ svn status -u B 32 raisin.jpg $ svn update B raisin.jpg $ svn status $
If the repository lock was broken, then svn
status --show-updates
(-u
)
displays a B
(Broken) symbol next to the
file. If a new lock exists in place of the old one, then a
T
(sTolen) symbol is shown. Finally,
svn update notices any defunct lock tokens
and removes them from the working copy.
We've seen how svn lock and svn unlock can be used to create, release, break, and steal locks. This satisfies the goal of serializing commit access to a file. But what about the larger problem of preventing wasted time?
For example, suppose Harry locks an image file and then
begins editing it. Meanwhile, miles away, Sally wants to do
the same thing. She doesn't think to run svn status
-u
, so she has no idea that Harry has
already locked the file. She spends hours editing the file,
and when she tries to commit her change, she discovers that
either the file is locked or that she's out of date.
Regardless, her changes aren't mergeable with Harry's. One of
these two people has to throw away his or her work, and a lot of
time has been wasted.
Subversion's solution to this problem is to provide a
mechanism to remind users that a file ought to be locked
before the editing begins. The mechanism
is a special property: svn:needs-lock
. If
that property is attached to a file (regardless of its value,
which is irrelevant), Subversion will try to use
filesystem-level permissions to make the file read-only—unless,
of course, the user has explicitly locked the file.
When a lock token is present (as a result of using
svn lock), the file becomes read/write.
When the lock is released, the file becomes read-only
again.
The theory, then, is that if the image file has this property attached, Sally would immediately notice something is strange when she opens the file for editing: many applications alert users immediately when a read-only file is opened for editing, and nearly all would prevent her from saving changes to the file. This reminds her to lock the file before editing, whereby she discovers the preexisting lock:
$ /usr/local/bin/gimp raisin.jpg gimp: error: file is read-only! $ ls -l raisin.jpg -r--r--r-- 1 sally sally 215589 Jun 8 19:23 raisin.jpg $ svn lock raisin.jpg svn: Lock request failed: 423 Locked (http://svn.example.com) $ svn info http://svn.example.com/repos/project/raisin.jpg | grep Lock Lock Token: opaquelocktoken:fc2b4dee-98f9-0310-abf3-653ff3226e6b Lock Owner: harry Lock Created: 2006-06-08 07:29:18 -0500 (Thu, 08 June 2006) Lock Comment (1 line): Making some tweaks. Locking for the next two hours. $
Tip | |
---|---|
Users and administrators alike are encouraged to attach
the |
Note that this property is a communication tool that works independently from the locking system. In other words, any file can be locked, whether or not this property is present. And conversely, the presence of this property doesn't make the repository require a lock when committing.
Unfortunately, the system isn't flawless. It's possible that even when a file has the property, the read-only reminder won't always work. Sometimes applications misbehave and “hijack†the read-only file, silently allowing users to edit and save the file anyway. There's not much that Subversion can do in this situation—at the end of the day, there's simply no substitution for good interpersonal communication. [16]
The following typographic conventions are used in this book:
Constant width
Used for literal user input, command output, and command-line options
Italic
Used for program and Subversion tool subcommand names, file and directory names, and new terms
Constant width italic
Used for replaceable items in code and text
Also, we sprinkled especially helpful or important bits of information throughout the book (in contextually relevant locations), set off visually so they're easy to find. Look for the following icons as you read:
Note | |
---|---|
This icon designates a special point of interest. |
Tip | |
---|---|
This icon designates a helpful tip or recommended best practice. |
Warning | |
---|---|
This icon designates a warning. Pay close attention to these to avoid running into problems. |
svnlook history — Print information about the history of a path in the repository (or the root directory if no path is supplied).
Print information about the history of a path in the repository (or the root directory if no path is supplied).
This shows the history output for the path
/branches/bookstore
as of revision 13 in our
sample repository:
$ svnlook history -r 13 /var/svn/repos /branches/bookstore --show-ids REVISION PATH <ID> -------- --------- 13 /branches/bookstore <1.1.r13/390> 12 /branches/bookstore <1.1.r12/413> 11 /branches/bookstore <1.1.r11/0> 9 /trunk <1.0.r9/551> 8 /trunk <1.0.r8/131357096> 7 /trunk <1.0.r7/294> 6 /trunk <1.0.r6/353> 5 /trunk <1.0.r5/349> 4 /trunk <1.0.r4/332> 3 /trunk <1.0.r3/335> 2 /trunk <1.0.r2/295> 1 /trunk <1.0.r1/532>
svnlook cat — Print the contents of a file.
This shows the contents of a file in transaction
ax8
, located at
/trunk/README
:
$ svnlook cat -t ax8 /var/svn/repos /trunk/README Subversion, a version control system. ===================================== $LastChangedDate: 2003-07-17 10:45:25 -0500 (Thu, 17 Jul 2003) $ Contents: I. A FEW POINTERS II. DOCUMENTATION III. PARTICIPATING IN THE SUBVERSION COMMUNITY …
post-unlock — Notification of a successful path unlock.
The post-unlock
hook runs after one
or more paths have been unlocked. It is typically used to
send email notification of the unlock event.
If the post-unlock
hook returns a
nonzero exit status, the unlock will
not be aborted since it has already
completed. However, anything that the hook printed
to stderr
will be marshalled back to the
client, making it easier to diagnose hook failures.
svndumpfilter exclude — Filter out nodes with given prefixes from the dump stream.
This can be used to exclude nodes that begin with one or
more PATH_PREFIX
es from a
filtered dump file.
If we have a dump file from a repository with a number of
different picnic-related directories in it, but we want to keep
everything except
the sandwiches
part of the repository,
we'll exclude only that path:
$ svndumpfilter exclude sandwiches < dumpfile > filtered-dumpfile Excluding prefixes: '/sandwiches' Revision 0 committed as 0. Revision 1 committed as 1. Revision 2 committed as 2. Revision 3 committed as 3. Revision 4 committed as 4. Dropped 1 node(s): '/sandwiches'
Table of Contents
This appendix is a guide for CVS users new to Subversion. It's essentially a list of differences between the two systems as “viewed from 10,000 feet.†For each section, we provide references to relevant chapters when possible.
Although the goal of Subversion is to take over the current and future CVS user base, some new features and design changes were required to fix certain “broken†behaviors that CVS had. This means that, as a CVS user, you may need to break habits—ones that you forgot were odd to begin with.
start-commit — Notification of the beginning of a commit.
The start-commit hook is run before the commit transaction is even created. It is typically used to decide whether the user has commit privileges at all.
If the start-commit hook program returns a nonzero exit
value, the commit is stopped before the commit transaction
is even created, and anything printed to stderr
is
marshalled back to the client.
svnadmin deltify — Deltify changed paths in a revision range.
svnadmin deltify exists in current versions of Subversion only for historical reasons. This command is deprecated and no longer needed.
It dates from a time when Subversion offered administrators greater control over compression strategies in the repository. This turned out to be a lot of complexity for very little gain, and this “feature†was deprecated.
We've already covered in detail how Subversion stores and retrieves various versions of files and directories in its repository. Whole chapters have been devoted to this most fundamental piece of functionality provided by the tool. And if the versioning support stopped there, Subversion would still be complete from a version control perspective.
But it doesn't stop there.
In addition to versioning your directories and files, Subversion provides interfaces for adding, modifying, and removing versioned metadata on each of your versioned directories and files. We refer to this metadata as properties, and they can be thought of as two-column tables that map property names to arbitrary values attached to each item in your working copy. Generally speaking, the names and values of the properties can be whatever you want them to be, with the constraint that the names must contain only ASCII characters. And the best part about these properties is that they, too, are versioned, just like the textual contents of your files. You can modify, commit, and revert property changes as easily as you can file content changes. And the sending and receiving of property changes occurs as part of your typical commit and update operations—you don't have to change your basic processes to accommodate them.
Note | |
---|---|
Subversion has reserved the set of properties whose names
begin with |
Properties show up elsewhere in Subversion, too. Just as files and directories may have arbitrary property names and values attached to them, each revision as a whole may have arbitrary properties attached to it. The same constraints apply—human-readable names and anything-you-want binary values. The main difference is that revision properties are not versioned. In other words, if you change the value of, or delete, a revision property, there's no way, within the scope of Subversion's functionality, to recover the previous value.
Subversion has no particular policy regarding the use of
properties. It asks only that you not use property names that
begin with the prefix svn:
. That's the
namespace that it sets aside for its own use. And Subversion
does, in fact, use properties—both the versioned and
unversioned variety. Certain versioned properties have special
meaning or effects when found on files and directories, or they
house a particular bit of information about the revisions on
which they are found. Certain revision properties are
automatically attached to revisions by Subversion's commit
process, and they carry information about the revision. Most of
these properties are mentioned elsewhere in this or other
chapters as part of the more general topics to which they are
related. For an exhaustive list of Subversion's predefined
properties, see the section called “Subversion Propertiesâ€.
Note | |
---|---|
While Subversion automatically attaches properties
( |
In this section, we will examine the utility—both to users of Subversion and to Subversion itself—of property support. You'll learn about the property-related svn subcommands and how property modifications affect your normal Subversion workflow.
Just as Subversion uses properties to store extra information about the files, directories, and revisions that it contains, you might also find properties to be of similar use. You might find it useful to have a place close to your versioned data to hang custom metadata about that data.
Say you wish to design a web site that houses many digital photos and displays them with captions and a datestamp. Now, your set of photos is constantly changing, so you'd like to have as much of this site automated as possible. These photos can be quite large, so as is common with sites of this nature, you want to provide smaller thumbnail images to your site visitors.
Now, you can get this functionality using traditional
files. That is, you can have your
image123.jpg
and an
image123-thumbnail.jpg
side by side in a
directory. Or if you want to keep the filenames the same, you
might have your thumbnails in a different directory, such as
thumbnails/image123.jpg
. You can also
store your captions and datestamps in a similar fashion, again
separated from the original image file. But the problem here
is that your collection of files multiplies with each new
photo added to the site.
Now consider the same web site deployed in a way that
makes use of Subversion's file properties. Imagine having a
single image file, image123.jpg
, with
properties set on that file that are named
caption
, datestamp
, and
even thumbnail
. Now your working copy
directory looks much more manageable—in fact, it looks
to the casual browser like there are nothing but image files
in it. But your automation scripts know better. They know
that they can use svn (or better yet, they
can use the Subversion language bindings—see the section called “Using the APIsâ€) to dig out the extra
information that your site needs to display without having to
read an index file or play path manipulation games.
Note | |
---|---|
While Subversion places few restrictions on the names and values you use for properties, it has not been designed to optimally carry large property values or large sets of properties on a given file or directory. Subversion commonly holds all the property names and values associated with a single item in memory at the same time, which can cause detrimental performance or failed operations when extremely large property sets are used. |
Custom revision properties are also frequently used. One
common such use is a property whose value contains an issue
tracker ID with which the revision is associated, perhaps
because the change made in that revision fixes a bug filed in
the tracker issue with that ID. Other uses include hanging
more friendly names on the revision—it might be hard to
remember that revision 1935 was a fully tested revision. But
if there's, say, a test-results
property on
that revision with the value all passing
,
that's meaningful information to have.
The svn program affords a few ways to add or modify file and directory properties. For properties with short, human-readable values, perhaps the simplest way to add a new property is to specify the property name and value on the command line of the svn propset subcommand:
$ svn propset copyright '(c) 2006 Red-Bean Software' calc/button.c property 'copyright' set on 'calc/button.c' $
But we've been touting the flexibility that Subversion
offers for your property values. And if you are planning to
have a multiline textual, or even binary, property value, you
probably do not want to supply that value on the command line.
So the svn propset subcommand takes a
--file
(-F
) option for
specifying the name of a file that contains the new property
value.
$ svn propset license -F /path/to/LICENSE calc/button.c property 'license' set on 'calc/button.c' $
There are some restrictions on the names you can use for
properties. A property name must start with a letter, a colon
(:
), or an underscore
(_
); after that, you can also use digits,
hyphens (-
), and periods
(.
).
[8]
In addition to the propset command, the svn program supplies the propedit command. This command uses the configured editor program (see the section called “Configâ€) to add or modify properties. When you run the command, svn invokes your editor program on a temporary file that contains the current value of the property (or that is empty, if you are adding a new property). Then, you just modify that value in your editor program until it represents the new value you wish to store for the property, save the temporary file, and then exit the editor program. If Subversion detects that you've actually changed the existing value of the property, it will accept that as the new property value. If you exit your editor without making any changes, no property modification will occur:
$ svn propedit copyright calc/button.c ### exit the editor without changes No changes to property 'copyright' on 'calc/button.c' $
We should note that, as with other svn subcommands, those related to properties can act on multiple paths at once. This enables you to modify properties on whole sets of files with a single command. For example, we could have done the following:
$ svn propset copyright '(c) 2006 Red-Bean Software' calc/* property 'copyright' set on 'calc/Makefile' property 'copyright' set on 'calc/button.c' property 'copyright' set on 'calc/integer.c' … $
All of this property adding and editing isn't really very useful if you can't easily get the stored property value. So the svn program supplies two subcommands for displaying the names and values of properties stored on files and directories. The svn proplist command will list the names of properties that exist on a path. Once you know the names of the properties on the node, you can request their values individually using svn propget. This command will, given a property name and a path (or set of paths), print the value of the property to the standard output stream.
$ svn proplist calc/button.c Properties on 'calc/button.c': copyright license $ svn propget copyright calc/button.c (c) 2006 Red-Bean Software
There's even a variation of the
proplist command that will list both the
name and the value for all of the properties. Simply supply the
--verbose
(-v
) option.
$ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright (c) 2006 Red-Bean Software license ================================================================ Copyright (c) 2006 Red-Bean Software. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the recipe for Fitz's famous red-beans-and-rice. …
The last property-related subcommand is propdel. Since Subversion allows you to store properties with empty values, you can't remove a property altogether using svn propedit or svn propset. For example, this command will not yield the desired effect:
$ svn propset license "" calc/button.c property 'license' set on 'calc/button.c' $ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright (c) 2006 Red-Bean Software license $
You need to use the propdel subcommand to delete properties altogether. The syntax is similar to the other property commands:
$ svn propdel license calc/button.c property 'license' deleted from 'calc/button.c'. $ svn proplist -v calc/button.c Properties on 'calc/button.c': copyright (c) 2006 Red-Bean Software $
Remember those unversioned revision properties? You can
modify those, too, using the same svn
subcommands that we just described. Simply add the
--revprop
command-line parameter and specify
the revision whose property you wish to modify. Since
revisions are global, you don't need to specify a target path
to these property-related commands so long as you are
positioned in a working copy of the repository whose
revision property you wish to modify. Otherwise, you can
simply provide the URL of any path in the repository of
interest (including the repository's root URL). For example,
you might want to replace the commit log message of an
existing revision.
[9]
If your current working directory is part of a working copy of
your repository, you can simply run the
svn propset command with no target path:
$ svn propset svn:log "* button.c: Fix a compiler warning." -r11 --revprop property 'svn:log' set on repository revision '11' $
But even if you haven't checked out a working copy from that repository, you can still effect the property change by providing the repository's root URL:
$ svn propset svn:log "* button.c: Fix a compiler warning." -r11 --revprop \ http://svn.example.com/repos/project property 'svn:log' set on repository revision '11' $
Note that the ability to modify these unversioned properties must be explicitly added by the repository administrator (see the section called “Commit Log Message Correctionâ€). That's because the properties aren't versioned, so you run the risk of losing information if you aren't careful with your edits. The repository administrator can set up methods to protect against this loss, and by default, modification of unversioned properties is disabled.
Tip | |
---|---|
Users should, where possible, use svn propedit instead of svn propset. While the end result of the commands is identical, the former will allow them to see the current value of the property that they are about to change, which helps them to verify that they are, in fact, making the change they think they are making. This is especially true when modifying unversioned revision properties. Also, it is significantly easier to modify multiline property values in a text editor than at the command line. |
Now that you are familiar with all of the property-related svn subcommands, let's see how property modifications affect the usual Subversion workflow. As we mentioned earlier, file and directory properties are versioned, just like your file contents. As a result, Subversion provides the same opportunities for merging—cleanly or with conflicts—someone else's modifications into your own.
As with file contents, your property changes are local modifications, made permanent only when you commit them to the repository with svn commit. Your property changes can be easily unmade, too—the svn revert command will restore your files and directories to their unedited states—contents, properties, and all. Also, you can receive interesting information about the state of your file and directory properties by using the svn status and svn diff commands.
$ svn status calc/button.c M calc/button.c $ svn diff calc/button.c Property changes on: calc/button.c ___________________________________________________________________ Name: copyright + (c) 2006 Red-Bean Software $
Notice how the status subcommand
displays M
in the second column instead of
the first. That is because we have modified the properties on
calc/button.c
, but not its textual
contents. Had we changed both, we would have seen
M
in the first column, too. (We cover
svn status in the section called “See an overview of your changesâ€).
You might also have noticed the nonstandard way that Subversion currently displays property differences. You can still use svn diff and redirect its output to create a usable patch file. The patch program will ignore property patches—as a rule, it ignores any noise it can't understand. This does, unfortunately, mean that to fully apply a patch generated by svn diff, any property modifications will need to be applied by hand.
Properties are a powerful feature of Subversion, acting as key components of many Subversion features discussed elsewhere in this and other chapters—textual diff and merge support, keyword substitution, newline translation, and so on. But to get the full benefit of properties, they must be set on the right files and directories. Unfortunately, that step can be easily forgotten in the routine of things, especially since failing to set a property doesn't usually result in an obvious error (at least compared to, say, failing to add a file to version control). To help your properties get applied to the places that need them, Subversion provides a couple of simple but useful features.
Whenever you introduce a file to version control using the
svn add or svn import
commands, Subversion tries to assist by setting some common
file properties automatically. First, on operating systems
whose filesystems support an execute permission bit,
Subversion will automatically set the
svn:executable
property on newly added or
imported files whose execute bit is enabled. (See the section called “File Executability†later in
this chapter for more about this property.)
Second, Subversion tries to determine the file's MIME
type. If you've configured a
mime-types-files
runtime configuration
parameter, Subversion will try to find a MIME type mapping in
that file for your file's extension. If it finds such a
mapping, it will set your file's
svn:mime-type
property to the MIME type it
found. If no mapping file is configured, or no mapping for
your file's extension could be found, Subversion runs a very
basic heuristic to determine whether the file contains nontextual
content. If so, it automatically sets the
svn:mime-type
property on that file to
application/octet-stream
(the generic
“this is a collection of bytes†MIME type). Of
course, if Subversion guesses incorrectly, or if you wish to
set the svn:mime-type
property to something
more precise—perhaps image/png
or
application/x-shockwave-flash
—you can
always remove or edit that property. (For more on
Subversion's use of MIME types, see the section called “File Content Type†later in
this chapter.)
Subversion also provides, via its runtime configuration
system (see the section called “Runtime Configuration Areaâ€), a more
flexible automatic property setting feature that allows you
to create mappings of filename patterns to property names and
values. Once again, these mappings affect adds and imports,
and can not only override the default MIME type decision made
by Subversion during those operations, but can also set
additional Subversion or custom properties, too. For example,
you might create a mapping that says that anytime you add
JPEG files—ones whose names match the pattern
*.jpg
—Subversion should automatically
set the svn:mime-type
property on those
files to image/jpeg
. Or perhaps any files
that match *.cpp
should have
svn:eol-style
set to
native
, and svn:keywords
set to Id
. Automatic property support is
perhaps the handiest property-related tool in the Subversion
toolbox. See the section called “Config†for more about
configuring that support.
Subversion has numerous features, options, bells, and whistles, but on a day-to-day basis, odds are that you will use only a few of them. In this section, we'll run through the most common things that you might find yourself doing with Subversion in the course of a day's work.
The typical work cycle looks like this:
Update your working copy.
svn update
Make changes.
svn add
svn delete
svn copy
svn move
Examine your changes.
svn status
svn diff
Possibly undo some changes.
svn revert
Resolve conflicts (merge others' changes).
svn update
svn resolve
Commit your changes.
svn commit
When working on a project with a team, you'll want to update your working copy to receive any changes other developers on the project have made since your last update. Use svn update to bring your working copy into sync with the latest revision in the repository:
$ svn update U foo.c U bar.c Updated to revision 2.
In this case, it appears that someone checked in
modifications to both foo.c
and bar.c
since the last time you
updated, and Subversion has updated your working copy to
include those changes.
When the server sends changes to your working copy via
svn update, a letter code is displayed next
to each item to let you know what actions Subversion performed
to bring your working copy up to date. To find out what these
letters mean, run svn help update
.
Now you can get to work and make changes in your working copy. It's usually most convenient to decide on a discrete change (or set of changes) to make, such as writing a new feature, fixing a bug, and so on. The Subversion commands that you will use here are svn add, svn delete, svn copy, svn move, and svn mkdir. However, if you are merely editing files that are already in Subversion, you may not need to use any of these commands until you commit.
You can make two kinds of changes to your working copy: file changes and tree changes. You don't need to tell Subversion that you intend to change a file; just make your changes using your text editor, word processor, graphics program, or whatever tool you would normally use. Subversion automatically detects which files have been changed, and in addition, it handles binary files just as easily as it handles text files—and just as efficiently, too. For tree changes, you can ask Subversion to “mark†files and directories for scheduled removal, addition, copying, or moving. These changes may take place immediately in your working copy, but no additions or removals will happen in the repository until you commit them.
Here is an overview of the five Subversion subcommands that you'll use most often to make tree changes:
svn add foo
Schedule file, directory, or symbolic link
foo
to be added to the repository.
When you next commit, foo
will
become a child of its parent directory. Note that if
foo
is a directory, everything
underneath foo
will be scheduled
for addition. If you want only to add
foo
itself, pass the
--depth empty
option.
svn delete foo
Schedule file, directory, or symbolic link
foo
to be deleted from the
repository. If foo
is a file or
link, it is immediately deleted from your working copy.
If foo
is a directory, it is not
deleted, but Subversion schedules it for deletion. When
you commit your changes, foo
will
be entirely removed from your working copy and the
repository.
[3]
svn copy foo bar
Create a new item bar
as a
duplicate of foo
and automatically
schedule bar
for addition. When
bar
is added to the repository on
the next commit, its copy history is recorded (as having
originally come from foo
).
svn copy does not create intermediate
directories unless you pass the
--parents
option.
svn move foo bar
This command is exactly the same as running
svn copy foo bar; svn delete foo
.
That is, bar
is scheduled for
addition as a copy of foo
, and
foo
is scheduled for removal.
svn move does not create intermediate
directories unless you pass the
--parents
option.
svn mkdir blort
This command is exactly the same as running
mkdir blort; svn add blort
. That is,
a new directory named blort
is
created and scheduled for addition.
Once you've finished making changes, you need to commit them to the repository, but before you do so, it's usually a good idea to take a look at exactly what you've changed. By examining your changes before you commit, you can make a more accurate log message. You may also discover that you've inadvertently changed a file, and this gives you a chance to revert those changes before committing. Additionally, this is a good opportunity to review and scrutinize changes before publishing them. You can see an overview of the changes you've made by using svn status, and dig into the details of those changes by using svn diff.
Subversion has been optimized to help you with this task,
and it is able to do many things without communicating with
the repository. In particular, your working copy contains a
hidden cached “pristine†copy of each version-controlled
file within the .svn
area.
Because of this, Subversion can quickly show you how your
working files have changed or even allow you to undo your
changes without contacting the repository.
To get an overview of your changes, you'll use the svn status command. You'll probably use svn status more than any other Subversion command.
If you run svn status at the top of
your working copy with no arguments, it will detect all file
and tree changes you've made. Here are a few examples of
the most common status codes that svn
status can return. (Note that the text following
#
is not
actually printed by svn status.)
? scratch.c # file is not under version control A stuff/loot/bloo.h # file is scheduled for addition C stuff/loot/lump.c # file has textual conflicts from an update D stuff/fish.c # file is scheduled for deletion M bar.c # the content in bar.c has local modifications
In this output format, svn status prints six columns of characters, followed by several whitespace characters, followed by a file or directory name. The first column tells the status of a file or directory and/or its contents. The codes we listed are:
A item
The file, directory, or symbolic link
item
has been scheduled for
addition into the repository.
C item
The file item
is in a state
of conflict. That is, changes received from the
server during an update overlap with local changes
that you have in your working copy (and weren't
resolved during the update). You must resolve this
conflict before committing your changes to the
repository.
D item
The file, directory, or symbolic link
item
has been scheduled for
deletion from the repository.
M item
The contents of the file item
have been modified.
If you pass a specific path to svn status, you get information about that item alone:
$ svn status stuff/fish.c D stuff/fish.c
svn status also has a
--verbose
(-v
) option,
which will show you the status of every
item in your working copy, even if it has not been
changed:
$ svn status -v M 44 23 sally README 44 30 sally INSTALL M 44 20 harry bar.c 44 18 ira stuff 44 35 harry stuff/trout.c D 44 19 ira stuff/fish.c 44 21 sally stuff/things A 0 ? ? stuff/things/bloo.h 44 36 harry stuff/things/gloo.c
This is the “long form†output of svn status. The letters in the first column mean the same as before, but the second column shows the working revision of the item. The third and fourth columns show the revision in which the item last changed, and who changed it.
None of the prior invocations to svn
status contact the repository—instead, they
compare the metadata in the .svn
directory with the working copy. Finally, there is the
--show-updates
(-u
)
option, which contacts the repository and adds information
about things that are out of date:
$ svn status -u -v M * 44 23 sally README M 44 20 harry bar.c * 44 35 harry stuff/trout.c D 44 19 ira stuff/fish.c A 0 ? ? stuff/things/bloo.h Status against revision: 46
Notice the two asterisks: if you were to run
svn update
at this point, you would
receive changes to README
and trout.c
. This tells you some very
useful information—you'll need to update and get the
server changes on README
before you
commit, or the repository will reject your commit for being
out of date (more on this subject later).
svn status can display much more information about the files and directories in your working copy than we've shown here—for an exhaustive description of svn status and its output, see svn status.
Another way to examine your changes is with the
svn diff command. You can find out
exactly how you've modified things by
running svn diff
with no arguments, which
prints out file changes in unified diff
format:
$ svn diff Index: bar.c =================================================================== --- bar.c (revision 3) +++ bar.c (working copy) @@ -1,7 +1,12 @@ +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <stdio.h> int main(void) { - printf("Sixty-four slices of American Cheese...\n"); + printf("Sixty-five slices of American Cheese...\n"); return 0; } Index: README =================================================================== --- README (revision 3) +++ README (working copy) @@ -193,3 +193,4 @@ +Note to self: pick up laundry. Index: stuff/fish.c =================================================================== --- stuff/fish.c (revision 1) +++ stuff/fish.c (working copy) -Welcome to the file known as 'fish'. -Information on fish will be here soon. Index: stuff/things/bloo.h =================================================================== --- stuff/things/bloo.h (revision 8) +++ stuff/things/bloo.h (working copy) +Here is a new file to describe +things about bloo.
The svn diff command produces this
output by comparing your working files against the cached
“pristine†copies within the
.svn
area. Files scheduled for
addition are displayed as all added text, and files
scheduled for deletion are displayed as all deleted
text.
Output is displayed in unified diff format. That is,
removed lines are prefaced with -
, and
added lines are prefaced with
+
. svn diff also
prints filename and offset information useful to the
patch program, so you can generate
“patches†by redirecting the diff output to a
file:
$ svn diff > patchfile
You could, for example, email the patch file to another developer for review or testing prior to a commit.
Subversion uses its internal diff engine, which produces
unified diff format, by default. If you want diff output in
a different format, specify an external diff program using
--diff-cmd
and pass any flags you'd like to
it using the --extensions
(-x
) option. For example, to see local
differences in file foo.c
in context
output format while ignoring case differences, you might run
svn diff --diff-cmd /usr/bin/diff -x "-i"
foo.c
.
Suppose while viewing the output of svn diff you determine that all the changes you made to a particular file are mistakes. Maybe you shouldn't have changed the file at all, or perhaps it would be easier to make different changes starting from scratch.
This is a perfect opportunity to use svn revert:
$ svn revert README Reverted 'README'
Subversion reverts the file to its premodified state by
overwriting it with the cached “pristine†copy
from the .svn
area. But also note that
svn revert can undo
any scheduled operations—for
example, you might decide that you don't want to add a new
file after all:
$ svn status foo ? foo $ svn add foo A foo $ svn revert foo Reverted 'foo' $ svn status foo ? foo
Note | |
---|---|
|
Or perhaps you mistakenly removed a file from version control:
$ svn status README $ svn delete README D README $ svn revert README Reverted 'README' $ svn status README
We've already seen how svn status -u
can predict conflicts. Suppose you run svn
update
and some interesting things occur:
$ svn update U INSTALL G README Conflict discovered in 'bar.c'. Select: (p) postpone, (df) diff-full, (e) edit, (h) help for more options:
The U
and
G
codes are no cause for
concern; those files cleanly absorbed changes from the
repository. The files marked with
U
contained no local changes
but were U
pdated with changes
from the repository. The G
stands for merG
ed, which
means that the file had local changes to begin with, but the
changes coming from the repository didn't overlap with the local
changes.
But the next two lines are part of a feature (new in
Subversion 1.5) called interactive conflict
resolution. This means that the changes from the
server overlapped with your own, and you have the opportunity
to resolve this conflict. The most commonly used options are
displayed, but you can see all of the options by
typing h
:
… (p) postpone - mark the conflict to be resolved later (df) diff-full - show all changes made to merged file (e) edit - change merged file in an editor (r) resolved - accept merged version of file (mf) mine-full - accept my version of entire file (ignore their changes) (tf) theirs-full - accept their version of entire file (lose my changes) (l) launch - launch external tool to resolve conflict (h) help - show this list
Let's briefly review each of these options before we go into detail on what each option means.
p
)ostpone
Leave the file in a conflicted state for you to resolve after your update is complete.
d
)iff-(f
)ull
Display the differences between the base revision and the conflicted file itself in unified diff format.
e
)dit
Open the file in conflict with your favorite editor,
as set in the environment variable
EDITOR
.
r
)esolved
After editing a file, tell svn that you've resolved the conflicts in the file and that it should accept the current contents—basically that you've “resolved†the conflict.
m
)ine-(f
)ull
Discard the newly received changes from the server and use only your local changes for the file under review.
t
)heirs-(f
)ull
Discard your local changes to the file under review and use only the newly received changes from the server.
l
)aunch
Launch an external program to perform the conflict resolution. This requires a bit of preparation beforehand.
h
)elp
Show the list of all possible commands you can use in interactive conflict resolution.
We'll cover these commands in more detail now, grouping them together by related functionality.
Before deciding how to attack a conflict interactively,
odds are that you'd like to see exactly what is in conflict,
and the diff-full command
(df
) is what you'll use for this:
… Select: (p) postpone, (df) diff-full, (e) edit, (h)elp for more options : df --- .svn/text-base/sandwich.txt.svn-base Tue Dec 11 21:33:57 2007 +++ .svn/tmp/tempfile.32.tmp Tue Dec 11 21:34:33 2007 @@ -1 +1,5 @@ -Just buy a sandwich. +<<<<<<< .mine +Go pick up a cheesesteak. +======= +Bring me a taco! +>>>>>>> .r32 …
The first line of the diff content shows the previous
contents of the working copy (the BASE
revision), the next content line is your change, and the
last content line is the change that was just received from
the server (usually the
HEAD
revision). With this information in
hand, you're ready to move on to the next action.
There are four different ways to resolve conflicts interactively—two of which allow you to selectively merge and edit changes, and two of which allow you to simply pick a version of the file and move along.
If you wish to choose some combination of your local
changes, you can use the “edit†command
(e
) to manually edit the file with
conflict markers in a text editor (determined by the
EDITOR
environment variable). Editing
the file by hand in your favorite text editor is a somewhat
low-tech way of remedying conflicts (see the section called “Merging conflicts by hand†for a
walkthrough), so some people like to use fancy graphical
merge tools instead.
To use a merge tool, you need to either set the
SVN_MERGE
environment variable or define
the merge-tool-cmd
option in your
Subversion configuration file (see the section called “Configuration Options†for more details).
Subversion will pass four arguments to the merge tool: the
BASE
revision of the file, the revision
of the file received from the server as part of the update,
the copy of the file containing your local edits, and
the merged copy of the file (which contains conflict
markers). If your merge tool is expecting arguments in a
different order or format, you'll need to write a wrapper
script for Subversion to invoke. After you've edited the
file, if you're satisfied with the changes you've made, you
can tell Subversion that the edited file is no longer in
conflict by using the “resolve†command
(r
).
If you decide that you don't need to merge any changes,
but just want to accept one version of the file or the
other, you can either choose your changes (a.k.a.
“mineâ€) by using the “mine-fullâ€
command (mf
) or choose theirs by using the
“theirs-full†command
(tf
).
This may sound like an appropriate section for avoiding
marital disagreements, but it's actually still about
Subversion, so read on. If you're doing an update and
encounter a conflict that you're not prepared to review or
resolve, you can type p
to postpone
resolving a conflict on a file-by-file basis when you run
svn update
. If you're running an update
and don't want to resolve any conflicts, you can pass the
--non-interactive
option to svn
update, and any file in conflict will be marked
with a C
automatically.
The C
stands for
c
onflict. This means that
the changes from the server overlapped with your own, and
now you have to manually choose between them after the
update has completed. When you postpone a conflict
resolution, svn typically does three
things to assist you in noticing and resolving that
conflict:
Subversion prints a C
during the update and remembers that the file is in a
state of conflict.
If Subversion considers the file to be mergeable, it
places conflict
markers—special strings of text that
delimit the “sides†of the
conflict—into the file to visibly demonstrate the
overlapping areas. (Subversion uses the
svn:mime-type
property to decide whether a
file is capable of contextual, line-based merging. See
the section called “File Content Typeâ€
to learn more.)
For every conflicted file, Subversion places three extra unversioned files in your working copy:
filename.mine
This is your file as it existed in your working
copy before you updated your working copy—that
is, without conflict markers. This file has only
your latest changes in it. (If Subversion considers
the file to be unmergeable, the
.mine
file isn't created, since
it would be identical to the working file.)
filename.rOLDREV
This is the file that was the
BASE
revision before you updated
your working copy. That is, the file that you
checked out before you made your latest
edits.
filename.rNEWREV
This is the file that your Subversion client
just received from the server when you updated your
working copy. This file corresponds to the
HEAD
revision of the
repository.
Here OLDREV
is the revision number
of the file in your .svn
directory,
and NEWREV
is the revision number of
the repository HEAD
.
For example, Sally makes changes to the file
sandwich.txt
, but does not yet commit
those changes. Meanwhile, Harry commits changes to that
same file. Sally updates her working copy before committing
and she gets a conflict, which she postpones:
$ svn update Conflict discovered in 'sandwich.txt'. Select: (p) postpone, (df) diff-full, (e) edit, (h)elp for more options : p C sandwich.txt Updated to revision 2. $ ls -1 sandwich.txt sandwich.txt.mine sandwich.txt.r1 sandwich.txt.r2
At this point, Subversion will not
allow Sally to commit the file
sandwich.txt
until the three temporary
files are removed:
$ svn commit -m "Add a few more things" svn: Commit failed (details follow): svn: Aborting commit: '/home/sally/svn-work/sandwich.txt' remains in conflict
If you've postponed a conflict, you need to resolve the
conflict before Subversion will allow you to commit your
changes. You'll do this with the svn
resolve command and one of several arguments to
the --accept
option.
If you want to choose the version of the file that you
last checked out before making your edits, choose
the base
argument.
If you want to choose the version that contains only
your edits, choose the mine-full
argument.
If you want to choose the version that your most recent
update pulled from the server (and thus discarding your
edits entirely), choose
the theirs-full
argument.
However, if you want to pick and choose from your
changes and the changes that your update fetched from the
server, merge the conflicted text “by hand†(by
examining and editing the conflict markers within the file)
and then choose the working
argument.
svn resolve removes the three
temporary files and accepts the version of the file that you
specified with the --accept
option, and
Subversion no longer considers the file to be in a state of
conflict:
$ svn resolve --accept working sandwich.txt Resolved conflicted state of 'sandwich.txt'
Merging conflicts by hand can be quite intimidating the first time you attempt it, but with a little practice, it can become as easy as falling off a bike.
Here's an example. Due to a miscommunication, you and
Sally, your collaborator, both edit the file
sandwich.txt
at the same time. Sally
commits her changes, and when you go to update your working
copy, you get a conflict and you're going to have to edit
sandwich.txt
to resolve the conflict.
First, let's take a look at the file:
$ cat sandwich.txt Top piece of bread Mayonnaise Lettuce Tomato Provolone <<<<<<< .mine Salami Mortadella Prosciutto ======= Sauerkraut Grilled Chicken >>>>>>> .r2 Creole Mustard Bottom piece of bread
The strings of less-than signs, equals signs, and greater-than signs are conflict markers and are not part of the actual data in conflict. You generally want to ensure that those are removed from the file before your next commit. The text between the first two sets of markers is composed of the changes you made in the conflicting area:
<<<<<<< .mine Salami Mortadella Prosciutto =======
The text between the second and third sets of conflict markers is the text from Sally's commit:
======= Sauerkraut Grilled Chicken >>>>>>> .r2
Usually you won't want to just delete the conflict markers and Sally's changes—she's going to be awfully surprised when the sandwich arrives and it's not what she wanted. This is where you pick up the phone or walk across the office and explain to Sally that you can't get sauerkraut from an Italian deli. [5] Once you've agreed on the changes you will commit, edit your file and remove the conflict markers:
Top piece of bread Mayonnaise Lettuce Tomato Provolone Salami Mortadella Prosciutto Creole Mustard Bottom piece of bread
Now use svn resolve, and you're ready to commit your changes:
$ svn resolve --accept working sandwich.txt Resolved conflicted state of 'sandwich.txt' $ svn commit -m "Go ahead and use my sandwich, discarding Sally's edits."
Note that svn resolve, unlike most of the other commands we deal with in this chapter, requires that you explicitly list any filenames that you wish to resolve. In any case, you want to be careful and use svn resolve only when you're certain that you've fixed the conflict in your file—once the temporary files are removed, Subversion will let you commit the file even if it still contains conflict markers.
If you ever get confused while editing the conflicted file, you can always consult the three files that Subversion creates for you in your working copy—including your file as it was before you updated. You can even use a third-party interactive merging tool to examine those three files.
If you get a conflict and decide that you want to throw
out your changes, you can run svn resolve --accept
theirs-full
and Subversion will discard your edits
and remove the temporary files:CONFLICTED-PATH
$ svn update Conflict discovered in 'sandwich.txt'. Select: (p) postpone, (df) diff-full, (e) edit, (h) help for more options: p C sandwich.txt Updated to revision 2. $ ls sandwich.* sandwich.txt sandwich.txt.mine sandwich.txt.r2 sandwich.txt.r1 $ svn resolve --accept theirs-full sandwich.txt Resolved conflicted state of 'sandwich.txt'
If you decide that you want to throw out your changes and start your edits again (whether this occurs after a conflict or anytime), just revert your changes:
$ svn revert sandwich.txt Reverted 'sandwich.txt' $ ls sandwich.* sandwich.txt
Note that when you revert a conflicted file, you don't have to use svn resolve.
Finally! Your edits are finished, you've merged all changes from the server, and you're ready to commit your changes to the repository.
The svn commit command sends all of
your changes to the repository. When you commit a change, you
need to supply a log message
describing your change. Your log message will be attached to
the new revision you create. If your log message is brief,
you may wish to supply it on the command line using the
--message
(-m
)
option:
$ svn commit -m "Corrected number of cheese slices." Sending sandwich.txt Transmitting file data . Committed revision 3.
However, if you've been composing your log message as you
work, you may want to tell Subversion to get the message from
a file by passing the filename with the
--file
(-F
) option:
$ svn commit -F logmsg Sending sandwich.txt Transmitting file data . Committed revision 4.
If you fail to specify either the
--message
(-m
)
or --file
(-F
) option,
Subversion will automatically launch your favorite editor (see
the information on editor-cmd
in
the section called “Configâ€) for
composing a log message.
Tip | |
---|---|
If you're in your editor writing a commit message and decide that you want to cancel your commit, you can just quit your editor without saving changes. If you've already saved your commit message, simply delete the text, save again, and then abort: $ svn commit Waiting for Emacs...Done Log message unchanged or not specified (a)bort, (c)ontinue, (e)dit a $ |
The repository doesn't know or care whether your changes make any sense as a whole; it checks only to make sure nobody else has changed any of the same files that you did when you weren't looking. If somebody has done that, the entire commit will fail with a message informing you that one or more of your files are out of date:
$ svn commit -m "Add another rule" Sending rules.txt svn: Commit failed (details follow): svn: File '/sandwich.txt' is out of date …
(The exact wording of this error message depends on the network protocol and server you're using, but the idea is the same in all cases.)
At this point, you need to run svn
update
, deal with any merges or conflicts that
result, and attempt your commit again.
That covers the basic work cycle for using Subversion. Subversion offers many other features that you can use to manage your repository and working copy, but most of your day-to-day use of Subversion will involve only the commands that we've discussed so far in this chapter. We will, however, cover a few more commands that you'll use fairly often.
[3] Of course, nothing is ever totally deleted from
the repository—just from the
HEAD
of the repository. You can
get back anything you delete by checking out (or
updating your working copy to) a revision earlier
than the one in which you deleted it. Also see the section called “Resurrecting Deleted Itemsâ€.
[4] And you don't have a WLAN card. Thought you got us, huh?
[5] And if you ask them for it, they may very well ride you out of town on a rail.
svn switch — Update working copy to a different URL.
The first variant of this subcommand (without the
--relocate
option) updates your working
copy to point to a new URL—usually a URL that
shares a common ancestor with your working copy, although
not necessarily. This is the Subversion way to move a
working copy to a new branch. If specified,
PEGREV
determines in which
revision the target is first looked up. See the section called “Traversing Branches†for an in-depth look
at switching.
If --force
is used, unversioned
obstructing paths in the working copy do not automatically
cause a failure if the switch attempts to add the same
path. If the obstructing path is the same type (file or
directory) as the corresponding path in the repository, it
becomes versioned but its contents are left untouched in
the working copy. This means that an obstructing
directory's unversioned children may also obstruct and
become versioned. For files, any content differences
between the obstruction and the repository are treated
like a local modification to the working copy. All
properties from the repository are applied to the
obstructing path.
As with most subcommands, you can limit the scope of
the switch operation to a particular tree depth using the
--depth
option. Alternatively, you can
use the --set-depth
option to set a new
“sticky†working copy depth on the switch
target. Currently, the depth of a working copy directory
can only be increased (telescoped more deeply); you cannot
make a directory more shallow.
The --relocate
option causes
svn switch to do something different:
it updates your working copy to point to the
same repository directory, only at a different
URL (typically because an administrator has moved the
repository to another server, or to another URL on the
same server).
--accept ACTION --depth ARG --diff3-cmd CMD --force --ignore-externals --quiet (-q) --relocate --revision (-r) REV --set-depth ARG
If you're currently inside the directory
vendors
, which was branched to
vendors-with-fix
, and you'd like to
switch your working copy to that branch:
$ svn switch http://svn.red-bean.com/repos/branches/vendors-with-fix . U myproj/foo.txt U myproj/bar.txt U myproj/baz.c U myproj/qux.c Updated to revision 31.
To switch back, just provide the URL to the location in the repository from which you originally checked out your working copy:
$ svn switch http://svn.red-bean.com/repos/trunk/vendors . U myproj/foo.txt U myproj/bar.txt U myproj/baz.c U myproj/qux.c Updated to revision 31.
Tip | |
---|---|
You can switch just part of your working copy to a branch if you don't want to switch your entire working copy. |
Sometimes an administrator might change the location
(or apparent location) of your repository—in other
words, the content of the repository doesn't change, but
the repository's root URL does. For example, the hostname
may change, the URL scheme may change, or any part of the
URL that leads to the repository itself may change.
Rather than check out a new working copy, you can have the
svn switch command
“rewrite†your working copy's administrative
metadata to refer to the new repository location. If you
use the --relocate
option to svn
switch, Subversion will contact the repository
to validate the relocation request (looking for the
repository at the new URL, of course), and then do this
metadata rewriting. No file contents will be changed as
the result of this type of switch operation—this is
a metadata-only modification to the working copy.
$ svn checkout file:///var/svn/repos test A test/a A test/b … $ mv repos newlocation $ cd test/ $ svn update svn: Unable to open an ra_local session to URL svn: Unable to open repository 'file:///var/svn/repos' $ svn switch --relocate file:///var/svn/repos file:///tmp/newlocation . $ svn update At revision 3.
Warning | |
---|---|
Be careful when using the
|
Subversion provides many optional behaviors that the user can control. Many of these options are of the kind that a user would wish to apply to all Subversion operations. So, rather than forcing users to remember command-line arguments for specifying these options and to use them for every operation they perform, Subversion uses configuration files, segregated into a Subversion configuration area.
The Subversion configuration area is a two-tiered hierarchy of option names and their values. Usually, this boils down to a special directory that contains configuration files (the first tier), which are just text files in standard INI format (with “sections†providing the second tier). You can easily edit these files using your favorite text editor (such as Emacs or vi), and they contain directives read by the client to determine which of several optional behaviors the user prefers.
The first time the svn
command-line client is executed, it creates a per-user
configuration area. On Unix-like systems, this area appears
as a directory named .subversion
in the
user's home directory. On Win32 systems, Subversion creates a
folder named Subversion
, typically inside
the Application Data
area of the user's
profile directory (which, by the way, is usually a hidden
directory). However, on this platform, the exact location
differs from system to system and is dictated by the Windows
Registry.
[50]
We will refer to the per-user configuration area using its Unix
name, .subversion
.
In addition to the per-user configuration area, Subversion
also recognizes the existence of a system-wide configuration
area. This gives system administrators the ability to
establish defaults for all users on a given machine. Note
that the system-wide configuration area alone does not dictate
mandatory policy—the settings in the per-user
configuration area override those in the system-wide one, and
command-line arguments supplied to the svn
program have the final word on behavior. On Unix-like
platforms, the system-wide configuration area is
expected to be the /etc/subversion
directory; on Windows machines, it looks for a
Subversion
directory inside the common
Application Data
location (again, as
specified by the Windows Registry). Unlike the per-user
case, the svn program does not attempt
to create the system-wide configuration area.
The per-user configuration area currently contains three
files—two configuration files (config
and
servers
), and a README.txt
file, which describes the INI format. At the time of their
creation, the files contain default values for each of the
supported Subversion options, mostly commented out and grouped
with textual descriptions about how the values for the key
affect Subversion's behavior. To change a certain behavior,
you need only to load the appropriate configuration file into
a text editor, and to modify the desired option's value. If at
any time you wish to have the default configuration settings
restored, you can simply remove (or rename) your configuration
directory and then run some innocuous svn
command, such as svn --version
. A new
configuration directory with the default contents will be
created.
The per-user configuration area also contains a cache of
authentication data. The auth
directory
holds a set of subdirectories that contain pieces of cached
information used by Subversion's various supported
authentication methods. This directory is created in such a
way that only the user herself has permission to read its
contents.
In addition to the usual INI-based configuration area, Subversion clients running on Windows platforms may also use the Windows Registry to hold the configuration data. The option names and their values are the same as in the INI files. The “file/section†hierarchy is preserved as well, though addressed in a slightly different fashion—in this schema, files and sections are just levels in the Registry key tree.
Subversion looks for system-wide configuration values
under the
HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion
key. For example, the global-ignores
option,
which is in the miscellany
section of the
config
file, would be found at
HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Config\Miscellany\global-ignores
.
Per-user configuration values should be stored under
HKEY_CURRENT_USER\Software\Tigris.org\Subversion
.
Registry-based configuration options are parsed before their file-based counterparts, so they are overridden by values found in the configuration files. In other words, Subversion looks for configuration information in the following locations on a Windows system; lower-numbered locations take precedence over higher-numbered locations:
Command-line options
The per-user INI files
The per-user Registry values
The system-wide INI files
The system-wide Registry values
Also, the Windows Registry doesn't really support the
notion of something being “commented out.â€
However, Subversion will ignore any option key whose name
begins with a hash (#
) character. This
allows you to effectively comment out a Subversion option
without deleting the entire key from the Registry, obviously
simplifying the process of restoring that option.
The svn command-line client never
attempts to write to the Windows Registry and will not attempt
to create a default configuration area there. You can create
the keys you need using the REGEDIT
program. Alternatively, you can create a
.reg
file (such as the one in Example 7.1, “Sample registration entries (.reg) fileâ€), and
then double-click on that file's icon in the Explorer shell,
which will cause the data to be merged into your
Registry.
Example 7.1. Sample registration entries (.reg) file
REGEDIT4 [HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Servers\groups] [HKEY_LOCAL_MACHINE\Software\Tigris.org\Subversion\Servers\global] "#http-proxy-host"="" "#http-proxy-port"="" "#http-proxy-username"="" "#http-proxy-password"="" "#http-proxy-exceptions"="" "#http-timeout"="0" "#http-compression"="yes" "#neon-debug-mask"="" "#ssl-authority-files"="" "#ssl-trust-default-ca"="" "#ssl-client-cert-file"="" "#ssl-client-cert-password"="" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\auth] "#store-passwords"="yes" "#store-auth-creds"="yes" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\helpers] "#editor-cmd"="notepad" "#diff-cmd"="" "#diff3-cmd"="" "#diff3-has-program-arg"="" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\tunnels] [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\miscellany] "#global-ignores"="*.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store" "#log-encoding"="" "#use-commit-times"="" "#no-unlock"="" "#enable-auto-props"="" [HKEY_CURRENT_USER\Software\Tigris.org\Subversion\Config\auto-props]
The previous example shows the contents of a
.reg
file, which contains some of the most
commonly used configuration options and their default values.
Note the presence of both system-wide (for network
proxy-related options) and per-user settings (editor programs
and password storage, among others). Also note that all the
options are effectively commented out. You need only to
remove the hash (#
) character from the
beginning of the option names and set the values as you
desire.
In this section, we will discuss the specific runtime configuration options that Subversion currently supports.
The servers
file contains
Subversion configuration options related to the network
layers. There are two special section names in this
file—groups
and
global
. The groups
section is essentially a cross-reference table. The keys in
this section are the names of other sections in the file;
their values are globs—textual
tokens that possibly contain wildcard
characters—that are compared against the hostnames of
the machine to which Subversion requests are sent.
[groups] beanie-babies = *.red-bean.com collabnet = svn.collab.net [beanie-babies] … [collabnet] …
When Subversion is used over a network, it attempts to
match the name of the server it is trying to reach with a
group name under the groups
section. If
a match is made, Subversion then looks for a section in the
servers
file whose name is the matched
group's name. From that section, it reads the actual network
configuration settings.
The global
section contains the
settings that are meant for all of the servers not matched
by one of the globs under the groups
section. The options available in this section are
exactly the same as those that are valid for the other server
sections in the file (except, of course, the special
groups
section), and are as
follows:
http-proxy-exceptions
This specifies a comma-separated list of patterns for repository hostnames that should be accessed directly, without using the proxy machine. The pattern syntax is the same as is used in the Unix shell for filenames. A repository hostname matching any of these patterns will not be proxied.
http-proxy-host
This specifies the hostname of the proxy computer through which your HTTP-based Subversion requests must pass. It defaults to an empty value, which means that Subversion will not attempt to route HTTP requests through a proxy computer, and will instead attempt to contact the destination machine directly.
http-proxy-port
This specifies the port number on the proxy host to use. It defaults to an empty value.
http-proxy-username
This specifies the username to supply to the proxy machine. It defaults to an empty value.
http-proxy-password
This specifies the password to supply to the proxy machine. It defaults to an empty value.
http-timeout
This specifies the amount of time, in seconds, to
wait for a server response. If you experience
problems with a slow network connection causing
Subversion operations to time out, you should increase
the value of this option. The default value is
0
, which instructs the underlying
HTTP library, Neon, to use its default timeout
setting.
http-compression
This specifies whether Subversion should
attempt to compress network requests made to DAV-ready
servers. The default value is yes
(though compression will occur only if that capability
is compiled into the network layer). Set this to
no
to disable compression, such as
when debugging network transmissions.
http-library
Subversion provides a pair of repository access
modules that understand its WebDAV network protocol.
The original one, which shipped with Subversion 1.0, is
libsvn_ra_neon
(though back then it
was called libsvn_ra_dav
). Newer
Subversion versions also provide
libsvn_ra_serf
, which uses a
different underlying implementation and aims to
support some of the newer HTTP concepts.
At this point, libsvn_ra_serf
is still considered experimental, though it appears to
work in the common cases quite well. To encourage
experimentation, Subversion provides the
http-library
runtime configuration
option to allow users to specify (generally, or in a
per-server-group fashion) which WebDAV access module
they'd prefer to use—neon
or
serf
.
http-auth-types
This option is a semicolon-delimited list of
authentication types supported by the Neon-based
WebDAV repository access modules. Valid members of
this list are basic
,
digest
, and
negotiate
.
neon-debug-mask
This is an integer mask that the underlying HTTP
library, Neon, uses for choosing what type of
debugging output to yield. The default value is
0
, which will silence all debugging
output. For more information about how Subversion
makes use of Neon, see Chapter 8, Embedding Subversion.
ssl-authority-files
This is a semicolon-delimited list of paths to files containing certificates of the certificate authorities (or CAs) that are accepted by the Subversion client when accessing the repository over HTTPS.
ssl-trust-default-ca
Set this variable to yes
if you
want Subversion to automatically trust the set of
default CAs that ship with OpenSSL.
ssl-client-cert-file
If a host (or set of hosts) requires an SSL client certificate, you'll normally be prompted for a path to your certificate. By setting this variable to that same path, Subversion will be able to find your client certificate automatically without prompting you. There's no standard place to store your certificate on disk; Subversion will grab it from any path you specify.
ssl-client-cert-password
If your SSL client certificate file is encrypted
by a passphrase, Subversion will prompt you for the
passphrase whenever the certificate is used. If you
find this annoying (and don't mind storing the
password in the servers
file),
you can set this variable to the certificate's
passphrase. You won't be prompted anymore.
store-plaintext-passwords
This variable is only important on UNIX-like systems.
It controls what the Subversion client does in case
the password for the current authentication realm can
only be cached on disk in unencrypted form, in the
~/.subversion/auth/
caching area.
You can set it to yes
or
no
to enable or disable caching of
passwords in unencrypted form, respectively.
The default setting is ask
, which causes
the Subversion client to ask you each time a
new password is about to be added to
the ~/.subversion/auth/
caching area.
The config
file contains the rest
of the currently available Subversion runtime
options—those not related to networking. There are
only a few options in use as of this writing, but they are
again grouped into sections in expectation of future
additions.
The auth
section contains settings
related to Subversion's authentication and authorization
against the repository. It contains the following:
store-passwords
This instructs Subversion to cache, or not to
cache, passwords that are supplied by the user in
response to server authentication challenges. The
default value is yes
. Set this to
no
to disable this on-disk password
caching. You can override this option for a single
instance of the svn command using
the --no-auth-cache
command-line
parameter (for those subcommands that support it).
For more information, see the section called “Client Credentials Cachingâ€.
store-auth-creds
This setting is the same as
store-passwords
, except that it
enables or disables on-disk caching of
all authentication information:
usernames, passwords, server certificates, and any
other types of cacheable credentials.
The helpers
section controls which
external applications Subversion uses to accomplish its
tasks. Valid options in this section are:
editor-cmd
This specifies the program Subversion will use to query the user for certain types of textual metadata or when interactively resolving conflicts. See the section called “Using External Editors†for more details on using external text editors with Subversion.
diff-cmd
This specifies the absolute path of a differencing program, used when Subversion generates “diff†output (such as when using the svn diff command). By default, Subversion uses an internal differencing library—setting this option will cause it to perform this task using an external program. See the section called “Using External Differencing and Merge Tools†for more details on using such programs.
diff3-cmd
This specifies the absolute path of a three-way differencing program. Subversion uses this program to merge changes made by the user with those received from the repository. By default, Subversion uses an internal differencing library—setting this option will cause it to perform this task using an external program. See the section called “Using External Differencing and Merge Tools†for more details on using such programs.
diff3-has-program-arg
This flag should be set to true
if the program specified by the
diff3-cmd
option accepts a
--diff-program
command-line
parameter.
merge-tool-cmd
This specifies the program that Subversion will use to perform three-way merge operations on your versioned files. See the section called “Using External Differencing and Merge Tools†for more details on using such programs.
The tunnels
section allows you to
define new tunnel schemes for use with
svnserve and svn://
client connections. For more details, see the section called “Tunneling over SSHâ€.
The miscellany
section is where
everything that doesn't belong elsewhere winds up.
[51]
In this section, you can find:
global-ignores
When running the svn status
command, Subversion lists unversioned files and
directories along with the versioned ones, annotating
them with a ?
character (see the section called “See an overview of your changesâ€). Sometimes it can
be annoying to see uninteresting, unversioned
items—for example, object files that result from
a program's compilation—in this display. The
global-ignores
option is a list of
whitespace-delimited globs that describe the names of
files and directories that Subversion should not
display unless they are versioned. The default value
is *.o *.lo *.la *.al .libs *.so *.so.[0-9]*
*.a *.pyc *.pyo *.rej *~ #*# .#* .*.swp .DS_Store
.
As well as svn status, the
svn add and svn import
commands also ignore files that match the list
when they are scanning a directory. You can override this
behavior for a single instance of any of these commands
by explicitly specifying the filename, or by using
the --no-ignore
command-line flag.
For information on finer-grained control of ignored items, see the section called “Ignoring Unversioned Itemsâ€.
enable-auto-props
This instructs Subversion to automatically set
properties on newly added or imported files. The
default value is no
, so set this to
yes
to enable this feature.
The auto-props
section of this file
specifies which properties are to be set on which files.
log-encoding
This variable sets the default character set
encoding for commit log messages. It's a permanent
form of the --encoding
option (see
the section called “svn Optionsâ€). The Subversion
repository stores log messages in UTF-8 and assumes
that your log message is written using your operating
system's native locale. You should specify a
different encoding if your commit messages are written
in any other encoding.
use-commit-times
Normally your working copy files have timestamps that reflect the last time they were touched by any process, whether your own editor or some svn subcommand. This is generally convenient for people developing software, because build systems often look at timestamps as a way of deciding which files need to be recompiled.
In other situations, however, it's sometimes nice
for the working copy files to have timestamps that
reflect the last time they were changed in the
repository. The svn export command
always places these “last-commit
timestamps†on trees that it produces. By
setting this config variable to
yes
, the svn
checkout, svn update,
svn switch, and svn
revert commands will also set last-commit
timestamps on files that they touch.
mime-types-file
This option, new to Subversion 1.5, specifies the
path of a MIME types mapping file, such as the
mime.types
file provided by the
Apache HTTP Server. Subversion uses this file to
assign MIME types to newly added or imported files.
See the section called “Automatic Property Setting†and
the section called “File Content Type†for more about Subversion's detection and use of
file content types.
preserved-conflict-file-exts
The value of this option is a space-delimited list of file extensions that Subversion should preserve when generating conflict filenames. By default, the list is empty. This option is new to Subversion 1.5.
When Subversion detects conflicting file content
changes, it defers resolution of those conflicts to the
user. To assist in the resolution, Subversion keeps
pristine copies of the various competing versions of
the file in the working copy. By default, those
conflict files have names constructed by appending to
the original filename a custom extension such as
.mine
or
.
(where REV
REV
is a revision
number). A mild annoyance with this naming scheme is
that on operating systems where a file's extension
determines the default application used to open and
edit that file, appending a custom extension prevents
the file from being easily opened by its native
application. For example, if the file
ReleaseNotes.pdf
was conflicted,
the conflict files might be named
ReleaseNotes.pdf.mine
or
ReleaseNotes.pdf.r4231
. While
your system might be configured to use Adobe's Acrobat
Reader to open files whose extensions are
.pdf
, there probably isn't an
application configured on your system to open all
files whose extensions are
.r4231
.
You can fix this annoyance by using this
configuration option, though. For files with one of
the specified extensions, Subversion will append to
the conflict file names the custom extension just as
before, but then also reappend the file's original
extension. Using the previous example, and assuming
that pdf
is one of the extensions
configured in this list thereof, the conflict files
generated for ReleaseNotes.pdf
would instead be named
ReleaseNotes.pdf.mine.pdf
and
ReleaseNotes.pdf.r4231.pdf
.
Because each file ends in
.pdf
, the correct default
application will be used to view them.
interactive-conflicts
This is a Boolean option that specifies whether
Subversion should try to resolve conflicts
interactively. If its value is yes
(which is the default value), Subversion will prompt
the user for how to handle conflicts in the manner
demonstrated in the section called “Resolve Conflicts (Merging Others' Changes)â€. Otherwise, it will simply flag the conflict and
continue its operation, postponing resolution to a later
time.
no-unlock
This Boolean option corresponds to svn
commit's --no-unlock
option, which tells Subversion not to release locks on
files you've just committed. If this runtime option
is set to yes
, Subversion will
never release locks automatically, leaving you to run
svn unlock explicitly. It defaults
to no
.
The auto-props
section controls
the Subversion client's ability to automatically set
properties on files when they are added or imported.
It contains any number of key-value pairs in the
format PATTERN = PROPNAME=VALUE[;PROPNAME=VALUE
...]
, where PATTERN
is a file
pattern that matches one or more filenames and the rest of
the line is a semicolon-delimited set of property
assignments. Multiple matches
on a file will result in multiple propsets for that
file; however, there is no guarantee that auto-props
will be applied in the order in which they are listed
in the config file, so you can't have one rule
“override†another. You can find several
examples of auto-props usage in the
config
file. Lastly, don't
forget to set enable-auto-props
to
yes
in the miscellany
section if you want to enable auto-props.
Technical books always face a certain dilemma: whether to cater to top-down or to bottom-up learners. A top-down learner prefers to read or skim documentation, getting a large overview of how the system works; only then does she actually start using the software. A bottom-up learner is a “learn by doing†person—someone who just wants to dive into the software and figure it out as she goes, referring to book sections when necessary. Most books tend to be written for one type of person or the other, and this book is undoubtedly biased toward top-down learners. (And if you're actually reading this section, you're probably already a top-down learner yourself!) However, if you're a bottom-up person, don't despair. While the book may be laid out as a broad survey of Subversion topics, the content of each section tends to be heavy with specific examples that you can try-by-doing. For the impatient folks who just want to get going, you can jump right to Appendix A, Subversion Quick-Start Guide.
Regardless of your learning style, this book aims to be useful to people of widely different backgrounds—from those with no previous experience in version control to experienced system administrators. Depending on your own background, certain chapters may be more or less important to you. The following can be considered a “recommended reading list†for various types of readers:
The assumption here is that you've probably used version control before and are dying to get a Subversion server up and running ASAP. Chapter 5, Repository Administration and Chapter 6, Server Configuration will show you how to create your first repository and make it available over the network. After that's done, Chapter 2, Basic Usage and Appendix B, Subversion for CVS Users are the fastest routes to learning the Subversion client.
Your administrator has probably set up Subversion already, and you need to learn how to use the client. If you've never used a version control system, then Chapter 1, Fundamental Concepts is a vital introduction to the ideas behind version control. Chapter 2, Basic Usage is a guided tour of the Subversion client.
Whether you're a user or administrator, eventually your project will grow larger. You're going to want to learn how to do more advanced things with Subversion, such as how to use Subversion's property support (Chapter 3, Advanced Topics), how to use branches and perform merges (Chapter 4, Branching and Merging), how to configure runtime options (Chapter 7, Customizing Your Subversion Experience), and other things. These chapters aren't critical at first, but be sure to read them once you're comfortable with the basics.
Presumably, you're already familiar with Subversion, and now want to either extend it or build new software on top of its many APIs. Chapter 8, Embedding Subversion is just for you.
The book ends with reference material—Chapter 9, Subversion Complete Reference is a reference guide for all Subversion commands, and the appendixes cover a number of useful topics. These are the chapters you're mostly likely to come back to after you've finished the book.
We covered a lot of ground in this chapter. We discussed the concepts of tags and branches and demonstrated how Subversion implements these concepts by copying directories with the svn copy command. We showed how to use svn merge to copy changes from one branch to another or roll back bad changes. We went over the use of svn switch to create mixed-location working copies. And we talked about how one might manage the organization and lifetimes of branches in a repository.
Remember the Subversion mantra: branches and tags are cheap. So don't be afraid to use them when needed!
As a helpful reminder of all the operations we discussed, here is handy reference table you can consult as you begin to make use of branches.
Table 4.1. Branching and merging commands
Action | Command |
---|---|
Create a branch or tag |
svn copy
|
Switch a working copy to a branch or tag |
svn switch
|
Synchronize a branch with trunk |
svn merge
|
See merge history or eligible changesets |
svn mergeinfo
|
Merge a branch back into trunk |
svn merge --reintegrate
|
Merge one specific change |
svn merge -c
|
Merge a range of changes |
svn merge -r
|
Block a change from automatic merging |
svn merge -c
|
Preview a merge |
svn merge
|
Abandon merge results |
svn revert -R .
|
Resurrect something from history |
svn copy
|
Undo a committed change |
svn merge -c -
|
Examine merge-sensitive history |
svn log -g; svn blame -g
|
Create a tag from a working copy |
svn copy .
|
Rearrange a branch or tag |
svn mv
|
Remove a branch or tag |
svn rm
|
Before reading on, here is the most important command you'll
ever need when using Subversion: svn help.
The Subversion command-line client is self-documenting—at
any time, a quick svn help
will describe
the syntax, options, and behavior of the subcommand.subcommand
$ svn help import import: Commit an unversioned file or tree into the repository. usage: import [PATH] URL Recursively commit a copy of PATH to URL. If PATH is omitted '.' is assumed. Parent directories are created as necessary in the repository. If PATH is a directory, the contents of the directory are added directly under URL. Unversionable items such as device files and pipes are ignored if --force is specified. Valid options: -q [--quiet] : print nothing, or only summary information -N [--non-recursive] : obsolete; try --depth=files or --depth=immediates --depth ARG : limit operation by depth ARG ('empty', 'files', 'immediates', or 'infinity') …
svnadmin is the administrative tool for monitoring and repairing your Subversion repository. For detailed information on repository administration, see the maintenance section for the section called “svnadminâ€.
Since svnadmin works via direct repository access (and thus can only be used on the machine that holds the repository), it refers to the repository with a path, not a URL.
Options in svnadmin are global, just as they are in svn:
--bdb-log-keep
(Berkeley DB-specific.) Disable automatic log removal of database logfiles. Having these logfiles around can be convenient if you need to restore from a catastrophic repository failure.
--bdb-txn-nosync
(Berkeley DB-specific.) Disables fsync when
committing database transactions. Used with the
svnadmin create command to create a
Berkeley DB-backed repository with
DB_TXN_NOSYNC
enabled (which improves
speed but has some risks associated with it).
--bypass-hooks
Bypass the repository hook system.
--clean-logs
Remove unused Berkeley DB logs.
--force-uuid
By default, when loading data into a repository that already contains revisions, svnadmin will ignore the UUID from the dump stream. This option will cause the repository's UUID to be set to the UUID from the stream.
--ignore-uuid
By default, when loading data into an empty repository, svnadmin will set the repository's UUID to the UUID from the dump stream. This option will cause the UUID from the stream to be ignored.
--incremental
Dump a revision only as a diff against the previous revision, instead of the usual fulltext.
--parent-dir
DIR
When loading a dump file, root paths at
DIR
instead of
/
.
--pre-1.4-compatible
When creating a new repository, use a format that is compatible with versions of Subversion earlier than Subversion 1.4.
--pre-1.5-compatible
When creating a new repository, use a format that is compatible with versions of Subversion earlier than Subversion 1.5.
--revision
(-r
)
ARG
Specify a particular revision to operate on.
--quiet
(-q
)
Do not show normal progress—show only errors.
--use-post-commit-hook
When loading a dump file, runs the repository's
post-commit
hook after finalizing each newly loaded
revision.
--use-post-revprop-change-hook
When changing a revision property, runs the
repository's post-revprop-change
hook after changing the
revision property.
--use-pre-commit-hook
When loading a dump file, runs the repository's
pre-commit
hook before finalizing each newly loaded
revision. If the hook fails, aborts the commit and
terminates the load process.
--use-pre-revprop-change-hook
When changing a revision property, runs the
repository's pre-revprop-change
hook before changing the
revision property. If the hook fails, aborts the
modification and terminates.
Subversion tracks tree structures, not just file contents. It's one of the biggest reasons Subversion was written to replace CVS.
Here's what this means to you, as a former CVS user:
The svn add and svn
delete commands work on directories now, just as
they work on files. So do svn copy and
svn move. However, these commands do
not cause any kind of immediate change
in the repository. Instead, the working items are simply
“scheduled†for addition or deletion. No
repository changes happen until you run svn
commit
.
Directories aren't dumb containers anymore; they have
revision numbers like files. (Or more properly, it's
correct to talk about “directory
foo/
in revision 5.â€)
Let's talk more about that last point. Directory versioning is a hard problem; because we want to allow mixed-revision working copies, there are some limitations on how far we can abuse this model.
From a theoretical point of view, we define “revision
5 of directory foo
†to mean a
specific collection of directory entries and properties. Now
suppose we start adding and removing files from
foo
, and then commit. It would be a lie
to say that we still have revision 5 of
foo
. However, if we bumped
foo
's revision number after the commit,
that would be a lie too; there may be other changes to
foo
we haven't yet received, because we
haven't updated yet.
Subversion deals with this problem by quietly tracking
committed adds and deletes in the .svn
area. When you eventually run svn update
,
all accounts are settled with the repository, and the
directory's new revision number is set correctly.
Therefore, only after an update is it truly safe to
say that you have a “perfect†revision of a
directory. Most of the time, your working copy will
contain “imperfect†directory revisions.
Similarly, a problem arises if you attempt to commit property changes on a directory. Normally, the commit would bump the working directory's local revision number. But again, that would be a lie, as there may be adds or deletes that the directory doesn't yet have, because no update has happened. Therefore, you are not allowed to commit property changes on a directory unless the directory is up to date.
For more discussion about the limitations of directory versioning, see the section called “Mixed Revision Working Copiesâ€.
The svn switch command transforms an
existing working copy to reflect a different branch. While this
command isn't strictly necessary for working with branches, it
provides a nice shortcut. In our earlier example,
after creating your private branch, you checked out a fresh
working copy of the new repository directory. Instead, you can
simply ask Subversion to change your working copy of
/calc/trunk
to mirror the new branch
location:
$ cd calc $ svn info | grep URL URL: http://svn.example.com/repos/calc/trunk $ svn switch ^/branches/my-calc-branch U integer.c U button.c U Makefile Updated to revision 341. $ svn info | grep URL URL: http://svn.example.com/repos/calc/branches/my-calc-branch
“Switching†a working copy that has no local modifications to a different branch results in the working copy looking just as it would if you'd done a fresh checkout of the directory. It's usually more efficient to use this command, because often branches differ by only a small degree. The server sends only the minimal set of changes necessary to make your working copy reflect the branch directory.
The svn switch command also takes a
--revision
(-r
) option, so you
need not always move your working copy to the
HEAD
of the branch.
Of course, most projects are more complicated than our
calc
example, and contain multiple
subdirectories. Subversion users often follow a specific
algorithm when using branches:
Copy the project's entire “trunk†to a new branch directory.
Switch only part of the trunk working copy to mirror the branch.
In other words, if a user knows that the branch work needs to happen on only a specific subdirectory, she uses svn switch to move only that subdirectory to the branch. (Or sometimes users will switch just a single working file to the branch!) That way, the user can continue to receive normal “trunk†updates to most of her working copy, but the switched portions will remain immune (unless someone commits a change to her branch). This feature adds a whole new dimension to the concept of a “mixed working copyâ€â€”not only can working copies contain a mixture of working revisions, but they can also contain a mixture of repository locations as well.
If your working copy contains a number of switched subtrees from different repository locations, it continues to function as normal. When you update, you'll receive patches to each subtree as appropriate. When you commit, your local changes will still be applied as a single, atomic change to the repository.
Note that while it's okay for your working copy to reflect a mixture of repository locations, these locations must all be within the same repository. Subversion repositories aren't yet able to communicate with one another; that feature is planned for the future. [25]
Because svn switch is essentially a variant of svn update, it shares the same behaviors; any local modifications in your working copy are preserved when new data arrives from the repository.
Tip | |
---|---|
Have you ever found yourself making some complex edits
(in your $ svn copy http://svn.example.com/repos/calc/trunk \ http://svn.example.com/repos/calc/branches/newbranch \ -m "Create branch 'newbranch'." Committed revision 353. $ svn switch ^/branches/newbranch At revision 353. The svn switch command, like svn update, preserves your local edits. At this point, your working copy is now a reflection of the newly created branch, and your next svn commit invocation will send your changes there. |
[25] You can, however, use svn
switch with the --relocate
option
if the URL of your server changes and you don't want to
abandon an existing working copy. See svn switch for more information and an
example.
svnsync initialize — Initialize a mirror repository for synchronization from the source repository.
svnsync initialize verifies that a repository meets the requirements of a new mirror repository—that it has no previous existing version history and that it allows revision property modifications—and records the initial administrative information that associates the mirror repository with the source repository. This is the first svnsync operation you run on a would-be mirror repository.
--config-dir DIR --no-auth-cache --non-interactive --quiet (-q) --source-password ARG --source-username ARG --sync-password ARG --sync-username ARG --trust-server-cert
Fail to initialize a mirror repository due to inability to modify revision properties:
$ svnsync initialize file:///var/svn/repos-mirror http://svn.example.com/repos svnsync: Repository has not been enabled to accept revision propchanges; ask the administrator to create a pre-revprop-change hook $
Initialize a repository as a mirror, having already
created a pre-revprop-change
hook that
permits all revision property changes:
$ svnsync initialize file:///var/svn/repos-mirror http://svn.example.com/repos Copied properties for revision 0. $
svnadmin setrevprop — Set a property on a revision.
You can get new files into your Subversion repository in two ways: svn import and svn add. We'll discuss svn import now and will discuss svn add later in this chapter when we review a typical day with Subversion.
The svn import command is a quick way to copy an unversioned tree of files into a repository, creating intermediate directories as necessary. svn import doesn't require a working copy, and your files are immediately committed to the repository. You typically use this when you have an existing tree of files that you want to begin tracking in your Subversion repository. For example:
$ svnadmin create /var/svn/newrepos $ svn import mytree file:///var/svn/newrepos/some/project \ -m "Initial import" Adding mytree/foo.c Adding mytree/bar.c Adding mytree/subdir Adding mytree/subdir/quux.h Committed revision 1.
The previous example copied the contents of directory
mytree
under the directory
some/project
in the repository:
$ svn list file:///var/svn/newrepos/some/project bar.c foo.c subdir/
Note that after the import is finished, the original tree is not converted into a working copy. To start working, you still need to svn checkout a fresh working copy of the tree.
While Subversion's flexibility allows you to lay out your
repository in any way that you choose, we recommend that you
create a trunk
directory to hold the
“main line†of development, a
branches
directory to contain branch
copies, and a tags
directory to contain tag
copies. For example:
$ svn list file:///var/svn/repos /trunk /branches /tags
You'll learn more about tags and branches in Chapter 4, Branching and Merging. For details and how to set up multiple projects, see the section called “Repository Layout†and the section called “Planning Your Repository Organization†to read more about project roots.
This book is written for computer-literate folk who want to use Subversion to manage their data. While Subversion runs on a number of different operating systems, its primary user interface is command-line-based. That command-line tool (svn), and some auxiliary programs, are the focus of this book.
For consistency, the examples in this book assume that the reader
is using a Unix-like operating system and is relatively comfortable
with Unix and command-line interfaces. That said, the
svn program also runs on non-Unix platforms
such as Microsoft Windows. With a few minor exceptions, such as
the use of backward slashes (\
) instead of
forward slashes (/
) for path separators, the
input to and output from this tool when run on Windows are
identical to its Unix counterpart.
Most readers are probably programmers or system administrators who need to track changes to source code. This is the most common use for Subversion, and therefore it is the scenario underlying all of the book's examples. But Subversion can be used to manage changes to any sort of information—images, music, databases, documentation, and so on. To Subversion, all data is just data.
While this book is written with the assumption that the reader has never used a version control system, we've also tried to make it easy for users of CVS (and other systems) to make a painless leap into Subversion. Special sidebars may mention other version control systems from time to time, and Appendix B summarizes many of the differences between CVS and Subversion.
Note also that the source code examples used throughout the book are only examples. While they will compile with the proper compiler incantations, they are intended to illustrate a particular scenario and not necessarily to serve as examples of good programming style or practices.
pre-lock — Notification of a path lock attempt.
The pre-lock
hook runs whenever
someone attempts to lock a path. It can be used to prevent
locks altogether or to create a more complex policy
specifying exactly which users are allowed to lock
particular paths. If the hook notices a preexisting lock,
it can also decide whether a user is allowed
to “steal†the existing lock.
If the pre-lock
hook program returns
a nonzero exit value, the lock action is aborted and
anything printed to stderr
is marshalled back to the
client.
Subversion allows users to invent arbitrarily named
versioned properties on files and directories, as well as
unversioned properties on revisions. The only restriction is on
properties whose names begin with svn:
(those
are reserved for Subversion's own use). While these properties
may be set by users to control Subversion's behavior, users may
not invent new svn:
properties.
These are the versioned properties that Subversion reserves for its own use:
svn:executable
If present on a file, the client will make the file executable in Unix-hosted working copies. See the section called “File Executabilityâ€.
svn:mime-type
If present on a file, the value indicates the file's MIME type. This allows the client to decide whether line-based contextual merging is safe to perform during updates, and can also affect how the file behaves when fetched via a web browser. See the section called “File Content Typeâ€.
svn:ignore
If present on a directory, the value is a list of unversioned file patterns to be ignored by svn status and other subcommands. See the section called “Ignoring Unversioned Itemsâ€.
svn:keywords
If present on a file, the value tells the client how to expand particular keywords within the file. See the section called “Keyword Substitutionâ€.
svn:eol-style
If present on a file, the value tells the client how to manipulate the file's line-endings in the working copy and in exported trees. See the section called “End-of-Line Character Sequences†and svn export earlier in this chapter.
svn:externals
If present on a directory, the value is a multiline list of other paths and URLs the client should check out. See the section called “Externals Definitionsâ€.
svn:special
If present on a file, indicates that the file is not an ordinary file, but a symbolic link or other special object. [60]
svn:needs-lock
If present on a file, tells the client to make the file read-only in the working copy, as a reminder that the file should be locked before editing begins. See the section called “Lock Communicationâ€.
svn:mergeinfo
Used by Subversion to track merge data. See the section called “Mergeinfo and Previews†for details, but you should never edit this property unless you really know what you're doing.
These are the unversioned properties that Subversion reserves for its own use:
svn:author
If present, contains the authenticated username of the person who created the revision. (If not present, the revision was committed anonymously.)
svn:date
Contains the UTC time the revision was created, in ISO 8601 format. The value comes from the server machine's clock, not the client's.
svn:log
Contains the log message describing the revision.
svn:autoversioned
If present, the revision was created via the autoversioning feature. See the section called “Autoversioningâ€.
[60] As of this writing, symbolic links are indeed the only “special†objects. But there might be more in future releases of Subversion.
Sometimes there's a single right way to do things; sometimes there are many. Subversion's developers understand that while the majority of its exact behaviors are acceptable to most of its users, there are some corners of its functionality where such a universally pleasing approach doesn't exist. In those places, Subversion offers users the opportunity to tell it how they want it to behave.
In this chapter, we explored Subversion's runtime configuration system and other mechanisms by which users can control those configurable behaviors. If you are a developer, though, the next chapter will take you one step further. It describes how you can further customize your Subversion experience by writing your own software against Subversion's libraries.
In the most general sense, Subversion handles binary files more gracefully than CVS does. Because CVS uses RCS, it can only store successive full copies of a changing binary file. Subversion, however, expresses differences between files using a binary differencing algorithm, regardless of whether they contain textual or binary data. That means all files are stored differentially (compressed) in the repository.
CVS users have to mark binary files with
-kb
flags to prevent data from being
garbled (due to keyword expansion and line-ending translations).
They sometimes forget to do this.
Subversion takes the more paranoid route. First, it never performs any kind of keyword or line-ending translation unless you explicitly ask it to do so (see the section called “Keyword Substitution†and the section called “End-of-Line Character Sequences†for more details). By default, Subversion treats all file data as literal byte strings, and files are always stored in the repository in an untranslated state.
Second, Subversion maintains an internal notion of whether a file is “text†or “binary†data, but this notion is only extant in the working copy. During an svn update, Subversion will perform contextual merges on locally modified text files, but will not attempt to do so for binary files.
To determine whether a contextual merge is possible,
Subversion examines the svn:mime-type
property. If the file has no svn:mime-type
property, or has a MIME type that is textual (e.g.,
text/*
),
Subversion assumes it is text. Otherwise, Subversion assumes
the file is binary. Subversion also helps users by running a
binary-detection algorithm in the svn import
and svn add commands. These commands will
make a good guess and then (possibly) set a binary
svn:mime-type
property on the file being
added. (If Subversion guesses wrong, the user can always remove
or hand-edit the property.)
Suppose it's your job to maintain a document for a division in your company—a handbook of some sort. One day a different division asks you for the same handbook, but with a few parts “tweaked†for them, since they do things slightly differently.
What do you do in this situation? You do the obvious: make a second copy of your document and begin maintaining the two copies separately. As each department asks you to make small changes, you incorporate them into one copy or the other.
You often want to make the same change to both copies. For example, if you discover a typo in the first copy, it's very likely that the same typo exists in the second copy. The two documents are almost the same, after all; they differ only in small, specific ways.
This is the basic concept of a branch—namely, a line of development that exists independently of another line, yet still shares a common history if you look far enough back in time. A branch always begins life as a copy of something, and moves on from there, generating its own history (see Figure 4.1, “Branches of developmentâ€).
Subversion has commands to help you maintain parallel branches of your files and directories. It allows you to create branches by copying your data, and remembers that the copies are related to one another. It also helps you duplicate changes from one branch to another. Finally, it can make portions of your working copy reflect different branches so that you can “mix and match†different lines of development in your daily work.
svnadmin list-unused-dblogs — Ask Berkeley DB which logfiles can be safely
deleted (applies only to repositories using the
bdb
backend).
Berkeley DB creates logs of all changes to the
repository, which allow it to recover in the face of
catastrophe. Unless you enable
DB_LOG_AUTOREMOVE
, the logfiles
accumulate, although most are no longer used and can be
deleted to reclaim disk space. See the section called “Managing Disk Space†for more
information.
svn propset — Set PROPNAME
to PROPVAL
on files, directories, or revisions.
svn propset PROPNAME [PROPVAL | -F VALFILE] PATH...
svn propset PROPNAME --revprop -r REV [PROPVAL | -F VALFILE] [TARGET]
Set PROPNAME
to
PROPVAL
on files, directories,
or revisions. The first example creates a versioned, local
property change in the working copy, and the second
creates an unversioned, remote property change on a
repository revision
(TARGET
determines only which
repository to access).
Tip | |
---|---|
Subversion has a number of “special†properties that affect its behavior. See the section called “Subversion Properties†later in this chapter for more on these properties. |
--changelist ARG --depth ARG --encoding ENC --file (-F) FILENAME --force --quiet (-q) --recursive (-R) --revision (-r) REV --revprop --targets FILENAME
Set the MIME type for a file:
$ svn propset svn:mime-type image/jpeg foo.jpg property 'svn:mime-type' set on 'foo.jpg'
On a Unix system, if you want a file to have the executable permission set:
$ svn propset svn:executable ON somescript property 'svn:executable' set on 'somescript'
Perhaps you have an internal policy to set certain properties for the benefit of your coworkers:
$ svn propset owner sally foo.c property 'owner' set on 'foo.c'
If you made a mistake in a log message for a
particular revision and want to change it, use
--revprop
and set svn:log
to the new log message:
$ svn propset --revprop -r 25 svn:log "Journaled about trip to New York." property 'svn:log' set on repository revision '25'
Or, if you don't have a working copy, you can provide a URL:
$ svn propset --revprop -r 26 svn:log "Document nap." \ http://svn.red-bean.com/repos property 'svn:log' set on repository revision '25'
Lastly, you can tell propset to take its input from a file. You could even use this to set the contents of a property to something binary:
$ svn propset owner-pic -F sally.jpg moo.c property 'owner-pic' set on 'moo.c'
Note | |
---|---|
By default, you cannot modify revision properties
in a Subversion repository. Your repository
administrator must explicitly enable revision property
modifications by creating a hook named
|
svn unlock — Unlock working copy paths or URLs.
Unlock each TARGET
. If any
TARGET
is locked by
another user or no valid lock token exists in the working
copy, print a warning and continue unlocking the rest of
the TARGET
s. Use
--force
to break a lock belonging to
another user or working copy.
Unlock two files in your working copy:
$ svn unlock tree.jpg house.jpg 'tree.jpg' unlocked. 'house.jpg' unlocked.
Unlock a file in your working copy that is currently locked by another user:
$ svn unlock tree.jpg svn: 'tree.jpg' is not locked in this working copy $ svn unlock --force tree.jpg 'tree.jpg' unlocked.
Unlock a file without a working copy:
$ svn unlock http://svn.red-bean.com/repos/test/tree.jpg 'tree.jpg unlocked.
For further details, see the section called “Lockingâ€.
Subversion is built on a portability layer called APR—the Apache Portable Runtime library. The APR library provides all the interfaces that Subversion needs to function on different operating systems: disk access, network access, memory management, and so on. While Subversion is able to use Apache as one of its network server programs, its dependence on APR does not mean that Apache is a required component. APR is a standalone library usable by any application. It does mean, however, that like Apache, Subversion clients and servers run on any operating system that the Apache httpd server runs on: Windows, Linux, all flavors of BSD, Mac OS X, NetWare, and others.
The easiest way to get Subversion is to download a binary package built for your operating system. Subversion's web site (http://subversion.tigris.org) often has these packages available for download, posted by volunteers. The site usually contains graphical installer packages for users of Microsoft operating systems. If you run a Unix-like operating system, you can use your system's native package distribution system (RPMs, DEBs, the ports tree, etc.) to get Subversion.
Alternatively, you can build Subversion directly from source
code, though it's not always an easy task. (If you're not
experienced at building open source software packages, you're
probably better off downloading a binary distribution instead!)
From the Subversion web site, download the latest source code
release. After unpacking it, follow the instructions in
the INSTALL
file to build it. Note that a
released source package may not contain everything you need to
build a command-line client capable of talking to a remote
repository. Starting with Subversion 1.4 and later, the
libraries Subversion depends on (apr, apr-util, and neon) are
distributed in a separate source package suffixed
with -deps
. These libraries are now common
enough that they may already be installed on your system. If
not, you'll need to unpack the dependency package into the same
directory where you unpacked the main Subversion source.
Regardless, it's possible that you may want to fetch other
optional dependencies such as Berkeley DB and possibly Apache
httpd. If you want to do a complete build,
make sure you have all of the packages documented in
the INSTALL
file.
If you're one of those folks that likes to use bleeding-edge software, you can also get the Subversion source code from the Subversion repository in which it lives. Obviously, you'll need to already have a Subversion client on hand to do this. But once you do, you can check out a working copy of the Subversion source repository from http://svn.collab.net/repos/svn/trunk/: [61]
$ svn checkout http://svn.collab.net/repos/svn/trunk subversion A subversion/HACKING A subversion/INSTALL A subversion/README A subversion/autogen.sh A subversion/build.conf …
The preceding command will create a working copy of the
latest (unreleased) Subversion source code into a subdirectory
named subversion
in your current working
directory. You can adjust that last argument as you see fit.
Regardless of what you call the new working copy directory,
though, after this operation completes, you will now have the
Subversion source code. Of course, you will still need to fetch
a few helper libraries (apr, apr-util, etc.)—see the
INSTALL
file in the top level of the
working copy for details.
[61] Note that the URL checked out in the example ends not
with svn
, but with a subdirectory thereof
called trunk
. See our discussion of
Subversion's branching and tagging model for the reasoning
behind this.
svn copy — Copy a file or directory in a working copy or in the repository.
Copy one or more files in a working copy or in the
repository. When copying multiple sources, they will be
added as children of DST
, which must be a directory.
SRC
and
DST
can each be either a
working copy (WC) path or URL:
Copy and schedule an item for addition (with history).
Immediately commit a copy of WC to URL.
Check out URL into WC and schedule it for addition.
Complete server-side copy. This is usually used to branch and tag.
When copying multiple sources, they will be added as
children of DST
, which must be
a directory.
If no peg revision (i.e.,
@REV
) is supplied, by default
the BASE
revision will be used for
files copied from the working copy, while the
HEAD
revision will be used for files
copied from a URL.
Note | |
---|---|
You can only copy files within a single repository. Subversion does not support cross-repository copying. |
Yes, if source or destination is in the repository, or if needed to look up the source revision number.
--editor-cmd CMD --encoding ENC --file (-F) FILENAME --force-log --ignore-externals --message (-m) MESSAGE --parents --quiet (-q) --revision (-r) REV --with-revprop ARG
Copy an item within your working copy (this schedules the copy—nothing goes into the repository until you commit):
$ svn copy foo.txt bar.txt A bar.txt $ svn status A + bar.txt
Copy several files in a working copy into a subdirectory:
$ svn copy bat.c baz.c qux.c src A src/bat.c A src/baz.c A src/qux.c
Copy revision 8 of bat.c
into your
working copy under a different name:
$ svn copy -r 8 bat.c ya-old-bat.c A ya-old-bat.c
Copy an item in your working copy to a URL in the repository (this is an immediate commit, so you must supply a commit message):
$ svn copy near.txt file:///var/svn/repos/test/far-away.txt -m "Remote copy." Committed revision 8.
Copy an item from the repository to your working copy (this just schedules the copy—nothing goes into the repository until you commit):
$ svn copy file:///var/svn/repos/test/far-away -r 6 near-here A near-here
Tip | |
---|---|
This is the recommended way to resurrect a dead file in your repository! |
And finally, copy between two URLs:
$ svn copy file:///var/svn/repos/test/far-away \ file:///var/svn/repos/test/over-there -m "remote copy." Committed revision 9.
$ svn copy file:///var/svn/repos/test/trunk \ file:///var/svn/repos/test/tags/0.6.32-prerelease -m "tag tree" Committed revision 12.
Tip | |
---|---|
This is the easiest way to “tag†a
revision in your repository—just svn
copy that revision (usually
|
And don't worry if you forgot to tag—you can always specify an older revision and tag anytime:
$ svn copy -r 11 file:///var/svn/repos/test/trunk \ file:///var/svn/repos/test/tags/0.6.32-prerelease \ -m "Forgot to tag at rev 11" Committed revision 13.
In CVS, revision numbers are per file. This is because CVS stores its data in RCS files; each file has a corresponding RCS file in the repository, and the repository is roughly laid out according to the structure of your project tree.
In Subversion, the repository looks like a single filesystem. Each commit results in an entirely new filesystem tree; in essence, the repository is an array of trees. Each of these trees is labeled with a single revision number. When someone talks about “revision 54â€, he's talking about a particular tree (and indirectly, the way the filesystem looked after the 54th commit).
Technically, it's not valid to talk about “revision 5
of foo.c
.†Instead, one would say
“foo.c
as it appears in revision
5.†Also, be careful when making assumptions about the
evolution of a file. In CVS, revisions 5 and 6 of
foo.c
are always different. In Subversion,
it's most likely that foo.c
did
not change between revisions 5 and
6.
Similarly, in CVS, a tag or branch is an annotation on the
file or on the version information for that individual file,
whereas in Subversion, a tag or branch is a copy of an entire
tree (by convention, into the /branches
or /tags
directories that appear at the top
level of the repository, beside /trunk
). In
the repository as a whole, many versions of each file may be
visible: the latest version on each branch, every tagged
version, and of course the latest version on the trunk
itself. So, to refine the terms even further, one would often
say “foo.c
as it appears in
/branches/REL1
in revision
5.â€
For more details on this topic, see the section called “Revisionsâ€.
Subversion attempts to erase a lot of the confusion between the cvs status and cvs update commands.
The cvs status command has two purposes:
first, to show the user any local modifications in the working
copy, and second, to show the user which files are out of date.
Unfortunately, because of CVS's hard-to-read status output, many
CVS users don't take advantage of this command at all. Instead,
they've developed a habit of running cvs
update
or cvs -n update
to quickly
see their changes. If users forget to use
the -n
option, this has the side effect of
merging repository changes they may not be ready to deal
with.
Subversion removes this muddle by making the output of svn status easy to read for both humans and parsers. Also, svn update prints only information about files that are updated, not local modifications.
svn status prints all files that have local modifications. By default, the repository is not contacted. While this subcommand accepts a fair number of options, the following are the most commonly used ones:
-u
Contact the repository to determine, and then display, out-of-dateness information.
-v
Show all entries under version control.
-N
Run nonrecursively (do not descend into subdirectories).
The svn status command has two output formats. In the default “short†format, local modifications look like this:
$ svn status M foo.c M bar/baz.c
If you specify the --show-updates
(-u
) option, a longer output format is
used:
$ svn status -u M 1047 foo.c * 1045 faces.html * bloo.png M 1050 bar/baz.c Status against revision: 1066
In this case, two new columns appear. The second column
contains an asterisk if the file or directory is out of date.
The third column shows the working copy's revision number of the
item. In the previous example, the asterisk indicates that
faces.html
would be patched if we updated,
and that bloo.png
is a newly added file in
the repository. (The absence of any revision number next to
bloo.png
means that it doesn't yet exist in
the working copy.)
At this point, you should take a quick look at the list of all possible status codes in svn status. Here are a few of the more common status codes you'll see:
A Resource is scheduled for Addition D Resource is scheduled for Deletion M Resource has local Modifications C Resource has Conflicts (changes have not been completely merged between the repository and working copy version) X Resource is eXternal to this working copy (may come from another repository). See the section called “Externals Definitions†? Resource is not under version control ! Resource is missing or incomplete (removed by a tool other than Subversion)
For a more detailed discussion of svn status, see the section called “See an overview of your changesâ€.
svn update updates your working copy, and prints only information about files that it updates.
Subversion has combined CVS's P
and
U
codes into just U
. When
a merge or conflict occurs, Subversion simply prints
G
or C
, rather than a
whole sentence about it.
For a more detailed discussion of svn update, see the section called “Update Your Working Copyâ€.
To use the command-line client, type svn, the subcommand you wish to use, [58] and any options or targets that you wish to operate on—the subcommand and the options need not appear in a specific order. For example, all of the following are valid ways to use svn status:
$ svn -v status $ svn status -v $ svn status -v myfile
You can find many more examples of how to use most client commands in Chapter 2, Basic Usage and commands for managing properties in the section called “Propertiesâ€.
While Subversion has different options for its
subcommands, all options exist in a single
namespace—that is, each option is guaranteed to mean the
same thing regardless of the subcommand you use it with. For
example, --verbose
(-v
)
always means “verbose output,†regardless of the
subcommand you use it with.
The svn command-line client usually exits quickly with an error if you pass it an option which does not apply to the specified subcommand. But as of Subversion 1.5, several of the options which apply to all—or nearly all—of the subcommands have been deemed acceptable by all subcommands, even if they have no effect on some of them. They appear grouped together in the command-line client's usage messages as global options. This was done to assist folks who write scripts which wrap the command-line client. These global options are as follows:
--config-dir
DIR
Instructs Subversion to read configuration
information from the specified directory instead of the
default location (.subversion
in
the user's home directory).
--no-auth-cache
Prevents caching of authentication information (e.g., username and password) in the Subversion runtime configuration directories.
--non-interactive
Disables all interactive prompting. Some examples of interactive prompting include requests for authentication credentials and conflict resolution decisions. This is useful if you're running Subversion inside an automated script and it's more appropriate to have Subversion fail than to prompt for more information.
--password
PASSWD
Specifies the password to use when authenticating against a Subversion server. If not provided, or if incorrect, Subversion will prompt you for this information as needed.
--username
NAME
Specifies the username to use when authenticating against a Subversion server. If not provided, or if incorrect, Subversion will prompt you for this information as needed.
The rest of the options apply and are accepted by only a subset of the subcommand. They are as follows:
--accept
ACTION
Specifies an action for automatic conflict resolution.
Possible actions are postpone
,
base
, mine-full
,
theirs-full
, edit
, and
launch
.
--auto-props
Enables auto-props, overriding the
enable-auto-props
directive in the
config
file.
--change
(-c
)
ARG
Used as a means to refer to a specific “change†(a.k.a. a revision). This option is syntactic sugar for “-r ARG-1:ARGâ€.
--changelist
ARG
Instructs Subversion to operate only on members of the changelist named
ARG
. You can use this option
multiple times to specify sets of changelists.
--cl
ARG
An alias for the
--changelist
option.
--depth
ARG
Instructs Subversion to limit the scope of an operation to a particular tree
depth. ARG
is one of
empty
, files
,
immediates
, or
infinity
.
--diff-cmd
CMD
Specifies an external program to use to show
differences between files. When svn
diff is invoked without this option, it uses
Subversion's internal diff engine, which provides
unified diffs by default. If you want to use an
external diff program, use --diff-cmd
.
You can pass options to the diff program with the
--extensions
(-x
)
option (more on that later in this section).
--diff3-cmd
CMD
Specifies an external program to use to merge files.
--dry-run
Goes through all the motions of running a command, but makes no actual changes—either on disk or in the repository.
--editor-cmd
CMD
Specifies an external program to use to edit a log message
or a property value. See the editor-cmd
section in the section called “Configâ€
for ways to specify a default editor.
--encoding
ENC
Tells Subversion that your commit message is encoded in the charset provided. The default is your operating system's native locale, and you should specify the encoding if your commit message is in any other encoding.
--extensions
(-x
)
ARG
Specifies an argument or arguments that Subversion
should pass to an external diff command. This option is
valid only when used with the svn
diff or svn merge commands,
with the
--diff-cmd
option.
If you wish to pass multiple
arguments, you must enclose all of them in quotes (e.g.,
svn diff --diff-cmd /usr/bin/diff -x
"-b -E"
).
--file
(-F
)
FILENAME
Uses the contents of the named file for the specified subcommand, though different subcommands do different things with this content. For example, svn commit uses the content as a commit log, whereas svn propset uses it as a property value.
--force
Forces a particular command or operation to run. Subversion will prevent you from performing some operations in normal usage, but you can pass the force option to tell Subversion “I know what I'm doing as well as the possible repercussions of doing it, so let me at 'em.†This option is the programmatic equivalent of doing your own electrical work with the power on—if you don't know what you're doing, you're likely to get a nasty shock.
--force-log
Forces a suspicious parameter passed to the
--message
(-m
) or
--file
(-F
) option to
be accepted as valid. By default, Subversion will
produce an error if parameters to these options look
like they might instead be targets of the subcommand.
For example, if you pass a versioned file's path to the
--file
(-F
) option,
Subversion will assume you've made a mistake, that the
path was instead intended as the target of the
operation, and that you simply failed to provide some
other—unversioned—file as the source of your
log message. To assert your intent and override these
types of errors, pass the --force-log
option to subcommands that accept log messages.
--help
(-h
) or
-?
)
If used with one or more subcommands, shows the built-in help text for each. If used alone, it displays the general client help text.
--ignore-ancestry
Tells Subversion to ignore ancestry when calculating differences (rely on path contents alone).
--ignore-externals
Tells Subversion to ignore externals definitions and the external working copies managed by them.
--incremental
Prints output in a format suitable for concatenation.
--keep-changelists
Tells Subversion not to delete changelists after committing.
--keep-local
Keeps the local copy of a file or directory (used with the svn delete command).
--limit
(-l
)
NUM
Shows only the first NUM
log messages.
--message
(-m
)
MESSAGE
Indicates that you will specify either a log message or a lock comment on the command line, following this option. For example:
$ svn commit -m "They don't make Sunday."
--new
ARG
Uses ARG
as the newer
target (for use with svn diff).
--no-auto-props
Disables auto-props, overriding the
enable-auto-props
directive in the
config
file.
--no-diff-deleted
Prevents Subversion from printing differences for deleted files. The default behavior when you remove a file is for svn diff to print the same differences that you would see if you had left the file but removed all the content.
--no-ignore
Shows files in the status listing that would
normally be omitted since they match a pattern in the
global-ignores
configuration option
or the svn:ignore
property. See the section called “Config†and the section called “Ignoring Unversioned Items†for more
information.
--no-unlock
Tells Subversion not to automatically unlock files (the default commit behavior is to unlock all files listed as part of the commit). See the section called “Locking†for more information.
--non-recursive
(-N
)
Deprecated. Stops a subcommand from recursing into subdirectories. Most subcommands recurse by default, but some subcommands—usually those that have the potential to remove or undo your local modifications—do not.
--notice-ancestry
Pays attention to ancestry when calculating differences.
--old
ARG
Uses ARG
as the older
target (for use with svn diff).
--parents
Creates and adds nonexistent or nonversioned parent subdirectories to the working copy or repository as part of an operation. This is useful for automatically creating multiple subdirectories where none currently exist. If performed on a URL, all the directories will be created in a single commit.
--quiet
(-q
)
Requests that the client print only essential information while performing an operation.
--record-only
Marks revisions as merged, for use with
--revision
(-r
).
--recursive
(-R
)
Makes a subcommand recurse into subdirectories. Most subcommands recurse by default.
--reintegrate
Used with the svn merge subcommand, merges all of the source URL's changes into the working copy. See the section called “Keeping a Branch in Sync†for details.
--relocate
FROM TO
[PATH...]
Used with the svn switch subcommand, changes the location of the repository that your working copy references. This is useful if the location of your repository changes and you have an existing working copy that you'd like to continue to use. See svn switch for an example.
--remove
ARG
Disassociates ARG
from a
changelist
--revision
(-r
)
REV
Indicates that you're going to supply a revision (or range of revisions) for a particular operation. You can provide revision numbers, keywords, or dates (in curly braces) as arguments to the revision option. If you wish to offer a range of revisions, you can provide two revisions separated by a colon. For example:
$ svn log -r 1729 $ svn log -r 1729:HEAD $ svn log -r 1729:1744 $ svn log -r {2001-12-04}:{2002-02-17} $ svn log -r 1729:{2002-02-17}
See the section called “Revision Keywords†for more information.
--revprop
Operates on a revision property instead of a
property specific to a file or directory. This option
requires that you also pass a revision with the
--revision
(-r
)
option.
--set-depth
ARG
Sets the sticky depth on a directory in a working
copy to one of empty
,
files
, immediates
,
or infinity
.
--show-revs
ARG
Used to make svn mergeinfo
display either merged
or eligible
revisions.
--show-updates
(-u
)
Causes the client to display information about which files in your working copy are out of date. This doesn't actually update any of your files—it just shows you which files will be updated if you then use svn update.
--stop-on-copy
Causes a Subversion subcommand that traverses the history of a versioned resource to stop harvesting that historical information when a copy—that is, a location in history where that resource was copied from another location in the repository—is encountered.
--strict
Causes Subversion to use strict semantics, a notion that is rather vague unless talking about specific subcommands (namely, svn propget).
--targets
FILENAME
Tells Subversion to get the list of files that you wish to operate on from the filename that you provide instead of listing all the files on the command line.
--use-merge-history
(-g
)
Uses or displays additional information from merge history.
--verbose
(-v
)
Requests that the client print out as much information as it can while running any subcommand. This may result in Subversion printing out additional fields, detailed information about every file, or additional information regarding its actions.
--version
Prints the client version info. This information
includes not only the version number of the client, but
also a listing of all repository access modules that the
client can use to access a Subversion repository.
With --quiet
(-q
) it
prints only the version number in a compact form.
--with-all-revprops
Used with the --xml
option to svn log,
will retrieve and display all revision
properties in the log output.
--with-revprop
ARG
When used with any command that writes to the
repository, sets the revision property, using the
NAME=VALUE
format,
NAME
to
VALUE
. When used with
svn log in --xml
mode, this displays the value of
ARG
in the log output.
--xml
Prints output in XML format.
Here are the various subcommands for the svn program. For the sake of brevity, we omit the global options (described in the section called “svn Optionsâ€) from the subcommand descriptions which follow.
[58] Well, you don't need a subcommand to use the
--version
option, but we'll get to that in
just a minute.
The chapters that follow and their contents are listed here:
Explains the basics of version control and different versioning models, along with Subversion's repository, working copies, and revisions.
Walks you through a day in the life of a Subversion user. It demonstrates how to use a Subversion client to obtain, modify, and commit data.
Covers more complex features that regular users will eventually come into contact with, such as versioned metadata, file locking, and peg revisions.
Discusses branches, merges, and tagging, including best practices for branching and merging, common use cases, how to undo changes, and how to easily swing from one branch to the next.
Describes the basics of the Subversion repository, how to create, configure, and maintain a repository, and the tools you can use to do all of this.
Explains how to configure your Subversion server and
offers different ways to access your repository:
HTTP
, the svn
protocol, and local disk access. It also covers the details
of authentication, authorization and anonymous
access.
Explores the Subversion client configuration files, the handling of internationalized text, and how to make external tools cooperate with Subversion.
Describes the internals of Subversion, the Subversion filesystem, and the working copy administrative areas from a programmer's point of view. It also demonstrates how to use the public APIs to write a program that uses Subversion.
Explains in great detail every subcommand of svn, svnadmin, and svnlook with plenty of examples for the whole family!
For the impatient, a whirlwind explanation of how to install Subversion and start using it immediately. You have been warned.
Covers the similarities and differences between Subversion and CVS, with numerous suggestions on how to break all the bad habits you picked up from years of using CVS. Included are descriptions of Subversion revision numbers, versioned directories, offline operations, update versus status, branches, tags, metadata, conflict resolution, and authentication.
Describes the details of WebDAV and DeltaV and how you can configure your Subversion repository to be mounted read/write as a DAV share.
A copy of the Creative Commons Attribution License, under which this book is licensed.
Subversion is a free/open source version control system. That is, Subversion manages files and directories, and the changes made to them, over time. This allows you to recover older versions of your data or examine the history of how your data changed. In this regard, many people think of a version control system as a sort of “time machine.â€
Subversion can operate across networks, which allows it to be used by people on different computers. At some level, the ability for various people to modify and manage the same set of data from their respective locations fosters collaboration. Progress can occur more quickly without a single conduit through which all modifications must occur. And because the work is versioned, you need not fear that quality is the trade-off for losing that conduit—if some incorrect change is made to the data, just undo that change.
Some version control systems are also software configuration management (SCM) systems. These systems are specifically tailored to manage trees of source code and have many features that are specific to software development—such as natively understanding programming languages, or supplying tools for building software. Subversion, however, is not one of these systems. It is a general system that can be used to manage any collection of files. For you, those files might be source code—for others, anything from grocery shopping lists to digital video mixdowns and beyond.
If you're a user or system administrator pondering the use of Subversion, the first question you should ask yourself is: "Is this the right tool for the job?" Subversion is a fantastic hammer, but be careful not to view every problem as a nail.
If you need to archive old versions of files and directories, possibly resurrect them, or examine logs of how they've changed over time, then Subversion is exactly the right tool for you. If you need to collaborate with people on documents (usually over a network) and keep track of who made which changes, then Subversion is also appropriate. This is why Subversion is so often used in software development environments—working on a development team is an inherently social activity, and Subversion makes it easy to collaborate with other programmers. Of course, there's a cost to using Subversion as well: administrative overhead. You'll need to manage a data repository to store the information and all its history, and be diligent about backing it up. When working with the data on a daily basis, you won't be able to copy, move, rename, or delete files the way you usually do. Instead, you'll have to do all of those things through Subversion.
Assuming you're fine with the extra workflow, you should still make sure you're not using Subversion to solve a problem that other tools solve better. For example, because Subversion replicates data to all the collaborators involved, a common misuse is to treat it as a generic distribution system. People will sometimes use Subversion to distribute huge collections of photos, digital music, or software packages. The problem is that this sort of data usually isn't changing at all. The collection itself grows over time, but the individual files within the collection aren't being changed. In this case, using Subversion is “overkill.†[2] There are simpler tools that efficiently replicate data without the overhead of tracking changes, such as rsync or unison.
In early 2000, CollabNet, Inc. (http://www.collab.net) began seeking developers to write a replacement for CVS. CollabNet offers a collaboration software suite called CollabNet Enterprise Edition (CEE), of which one component is version control. Although CEE used CVS as its initial version control system, CVS's limitations were obvious from the beginning, and CollabNet knew it would eventually have to find something better. Unfortunately, CVS had become the de facto standard in the open source world largely because there wasn't anything better, at least not under a free license. So CollabNet determined to write a new version control system from scratch, retaining the basic ideas of CVS, but without the bugs and misfeatures.
In February 2000, they contacted Karl Fogel, the author of Open Source Development with CVS (Coriolis, 1999), and asked if he'd like to work on this new project. Coincidentally, at the time Karl was already discussing a design for a new version control system with his friend Jim Blandy. In 1995, the two had started Cyclic Software, a company providing CVS support contracts, and although they later sold the business, they still used CVS every day at their jobs. Their frustration with CVS had led Jim to think carefully about better ways to manage versioned data, and he'd already come up with not only the name “Subversion,†but also the basic design of the Subversion data store. When CollabNet called, Karl immediately agreed to work on the project, and Jim got his employer, Red Hat Software, to essentially donate him to the project for an indefinite period of time. CollabNet hired Karl and Ben Collins-Sussman, and detailed design work began in May 2000. With the help of some well-placed prods from Brian Behlendorf and Jason Robbins of CollabNet, and from Greg Stein (at the time an independent developer active in the WebDAV/DeltaV specification process), Subversion quickly attracted a community of active developers. It turned out that many people had encountered the same frustrating experiences with CVS and welcomed the chance to finally do something about it.
The original design team settled on some simple goals. They didn't want to break new ground in version control methodology, they just wanted to fix CVS. They decided that Subversion would match CVS's features and preserve the same development model, but not duplicate CVS's most obvious flaws. And although it did not need to be a drop-in replacement for CVS, it should be similar enough that any CVS user could make the switch with little effort.
After 14 months of coding, Subversion became “self-hosting†on August 31, 2001. That is, Subversion developers stopped using CVS to manage Subversion's own source code and started using Subversion instead.
While CollabNet started the project, and still funds a large chunk of the work (it pays the salaries of a few full-time Subversion developers), Subversion is run like most open source projects, governed by a loose, transparent set of rules that encourage meritocracy. CollabNet's copyright license is fully compliant with the Debian Free Software Guidelines. In other words, anyone is free to download, modify, and redistribute Subversion as he pleases; no permission from CollabNet or anyone else is required.
Figure 1, “Subversion's architecture†illustrates a “mile-high†view of Subversion's design.
On one end is a Subversion repository that holds all of your versioned data. On the other end is your Subversion client program, which manages local reflections of portions of that versioned data (called “working copiesâ€). Between these extremes are multiple routes through various Repository Access (RA) layers. Some of these routes go across computer networks and through network servers which then access the repository. Others bypass the network altogether and access the repository directly.
Subversion, once installed, has a number of different pieces. The following is a quick overview of what you get. Don't be alarmed if the brief descriptions leave you scratching your head—plenty more pages in this book are devoted to alleviating that confusion.
The command-line client program
A program for reporting the state (in terms of revisions of the items present) of a working copy
A tool for directly inspecting a Subversion repository
A tool for creating, tweaking, or repairing a Subversion repository
A plug-in module for the Apache HTTP Server, used to make your repository available to others over a network
A custom standalone server program, runnable as a daemon process or invokable by SSH; another way to make your repository available to others over a network.
A program for filtering Subversion repository dump streams
A program for incrementally mirroring one repository to another over a network
The first edition of this book was released in 2004, shortly after Subversion had reached 1.0. Over the following four years Subversion released five major new versions, fixing bugs and adding major new features. While we've managed to keep the online version of this book up to date, we're thrilled that the second edition from O'Reilly now covers Subversion up through release 1.5, a major milestone for the project. Here's a quick summary of major new changes since Subversion 1.0. Note that this is not a complete list; for full details, please visit Subversion's web site at http://subversion.tigris.org.
Release 1.1 introduced FSFS, a flat-file repository storage option for the repository. While the Berkeley DB backend is still widely used and supported, FSFS has since become the default choice for newly created repositories due to its low barrier to entry and minimal maintenance requirements. Also in this release came the ability to put symbolic links under version control, auto-escaping of URLs, and a localized user interface.
Release 1.2 introduced the ability to create server-side locks on files, thus serializing commit access to certain resources. While Subversion is still a fundamentally concurrent version control system, certain types of binary files (e.g. art assets) cannot be merged together. The locking feature fulfills the need to version and protect such resources. With locking also came a complete WebDAV auto-versioning implementation, allowing Subversion repositories to be mounted as network folders. Finally, Subversion 1.2 began using a new, faster binary-differencing algorithm to compress and retrieve old versions of files.
Release 1.3 brought path-based authorization controls to the svnserve server, matching a feature formerly found only in the Apache server. The Apache server, however, gained some new logging features of its own, and Subversion's API bindings to other languages also made great leaps forward.
Release 1.4 introduced a whole new tool—svnsync—for doing one-way repository replication over a network. Major parts of the working copy metadata were revamped to no longer use XML (resulting in client-side speed gains), while the Berkeley DB repository backend gained the ability to automatically recover itself after a server crash.
Release 1.5 took much longer to finish than prior releases, but the headliner feature was gigantic: semi-automated tracking of branching and merging. This was a huge boon for users, and pushed Subversion far beyond the abilities of CVS and into the ranks of commercial competitors such as Perforce and ClearCase. Subversion 1.5 also introduced a bevy of other user-focused features, such as interactive resolution of file conflicts, partial checkouts, client-side management of changelists, powerful new syntax for externals definitions, and SASL authentication support for the svnserve server.
???
A bad Frequently Asked Questions (FAQ) sheet is one that is composed not of the questions people actually ask, but of the questions the FAQ's author wishes people would ask. Perhaps you've seen the type before:
Q: How can I use Glorbosoft XYZ to maximize team productivity?
A: Many of our customers want to know how they can maximize productivity through our patented office groupware innovations. The answer is simple. First, click on the
File
menu, scroll down toIncrease Productivity
, then…
The problem with such FAQs is that they are not, in a literal sense, FAQs at all. No one ever called the tech support line and asked, “How can we maximize productivity?†Rather, people asked highly specific questions, such as “How can we change the calendaring system to send reminders two days in advance instead of one?†and so on. But it's a lot easier to make up imaginary Frequently Asked Questions than it is to discover the real ones. Compiling a true FAQ sheet requires a sustained, organized effort: over the lifetime of the software, incoming questions must be tracked, responses monitored, and all gathered into a coherent, searchable whole that reflects the collective experience of users in the wild. It calls for the patient, observant attitude of a field naturalist. No grand hypothesizing, no visionary pronouncements here—open eyes and accurate note-taking are what's needed most.
What I love about this book is that it grew out of just such a process, and shows it on every page. It is the direct result of the authors' encounters with users. It began with Ben Collins-Sussman's observation that people were asking the same basic questions over and over on the Subversion mailing lists: what are the standard workflows to use with Subversion? Do branches and tags work the same way as in other version control systems? How can I find out who made a particular change?
Frustrated at seeing the same questions day after day, Ben worked intensely over a month in the summer of 2002 to write The Subversion Handbook, a 60-page manual that covered all the basics of using Subversion. The manual made no pretense of being complete, but it was distributed with Subversion and got users over that initial hump in the learning curve. When O'Reilly decided to publish a full-length Subversion book, the path of least resistance was obvious: just expand the Subversion handbook.
The three coauthors of the new book were thus presented with an unusual opportunity. Officially, their task was to write a book top-down, starting from a table of contents and an initial draft. But they also had access to a steady stream—indeed, an uncontrollable geyser—of bottom-up source material. Subversion was already in the hands of thousands of early adopters, and those users were giving tons of feedback, not only about Subversion, but also about its existing documentation.
During the entire time they wrote this book, Ben, Mike, and Brian haunted the Subversion mailing lists and chat rooms incessantly, carefully noting the problems users were having in real-life situations. Monitoring such feedback was part of their job descriptions at CollabNet anyway, and it gave them a huge advantage when they set out to document Subversion. The book they produced is grounded firmly in the bedrock of experience, not in the shifting sands of wishful thinking; it combines the best aspects of user manual and FAQ sheet. This duality might not be noticeable on a first reading. Taken in order, front to back, the book is simply a straightforward description of a piece of software. There's the overview, the obligatory guided tour, the chapter on administrative configuration, some advanced topics, and of course, a command reference and troubleshooting guide. Only when you come back to it later, seeking the solution to some specific problem, does its authenticity shine out: the telling details that can only result from encounters with the unexpected, the examples honed from genuine use cases, and most of all the sensitivity to the user's needs and the user's point of view.
Of course, no one can promise that this book will answer
every question you have about Subversion. Sometimes the
precision with which it anticipates your questions will seem
eerily telepathic; yet occasionally, you will stumble into a
hole in the community's knowledge and come away empty-handed.
When this happens, the best thing you can do is email
<users@subversion.tigris.org>
and present your
problem. The authors are still there and still watching, and the
authors include not just the three listed on the cover, but many others
who contributed corrections and original material. From the
community's point of view, solving your problem is merely a
pleasant side effect of a much larger project—namely,
slowly adjusting this book, and ultimately Subversion itself, to
more closely match the way people actually use it. They are
eager to hear from you, not only because they can help you, but
because you can help them. With Subversion, as with all active
free software projects, you are not
alone.
Let this book be your first companion.
Each of Subversion's core libraries can be said to exist in
one of three main layers—the Repository layer, the
Repository Access (RA) layer, or the Client layer (see Figure 1, “Subversion's architecture†in the Preface). We will examine
these layers shortly, but first, let's briefly summarize
Subversion's various libraries. For the sake of consistency, we
will refer to the libraries by their extensionless Unix library
names (libsvn_fs
, libsvn_wc
,
mod_dav_svn
, etc.).
Primary interface for client programs
Tree and byte-stream differencing routines
Contextual differencing and merging routines
Filesystem commons and module loader
The Berkeley DB filesystem backend
The native filesystem (FSFS) backend
Repository Access commons and module loader
The local Repository Access module
The WebDAV Repository Access module
Another (experimental) WebDAV Repository Access module
The custom protocol Repository Access module
Repository interface
Miscellaneous helpful subroutines
The working copy management library
Apache authorization module for Subversion repositories access via WebDAV
Apache module for mapping WebDAV operations to Subversion ones
The fact that the word “miscellaneous†appears only once in the previous list is a good sign. The Subversion development team is serious about making sure that functionality lives in the right layer and libraries. Perhaps the greatest advantage of the modular design is its lack of complexity from a developer's point of view. As a developer, you can quickly formulate that kind of “big picture†that allows you to pinpoint the location of certain pieces of functionality with relative ease.
Another benefit of modularity is the ability to replace a
given module with a whole new library that implements the same
API without affecting the rest of the code base. In some sense,
this happens within Subversion already. The
libsvn_ra_local
,
libsvn_ra_neon
,
libsvn_ra_serf
, and
libsvn_ra_svn
libraries each implement the
same interface, all working as plug-ins to
libsvn_ra
. And all four communicate with
the Repository layer—libsvn_ra_local
connects to the
repository directly; the other three do so over a network. The
libsvn_fs_base
and
libsvn_fs_fs
libraries are another pair of
libraries that implement the same functionality in different
ways—both are plug-ins to the common
libsvn_fs
library.
The client itself also highlights the benefits of modularity
in the Subversion design. Subversion's
libsvn_client
library is a one-stop shop
for most of the functionality necessary for designing a working
Subversion client (see the section called “Client Layerâ€). So while the
Subversion distribution provides only the svn
command-line client program, several third-party
programs provide various forms of graphical client UIs.
These GUIs use the same APIs that the stock command-line client
does. This type of modularity has played a large role in the
proliferation of available Subversion clients and IDE
integrations and, by extension, to the tremendous adoption rate
of Subversion itself.
When referring to Subversion's Repository layer, we're
generally talking about two basic concepts—the versioned
filesystem implementation (accessed via
libsvn_fs
, and supported by its
libsvn_fs_base
and
libsvn_fs_fs
plug-ins), and the repository
logic that wraps it (as implemented in
libsvn_repos
). These libraries provide
the storage and reporting mechanisms for the various revisions
of your version-controlled data. This layer is connected to
the Client layer via the Repository Access layer, and is, from
the perspective of the Subversion user, the stuff at the
“other end of the line.â€
The Subversion filesystem is not a kernel-level filesystem that one would install in an operating system (such as the Linux ext2 or NTFS), but instead is a virtual filesystem. Rather than storing “files†and “directories†as real files and directories (the kind you can navigate through using your favorite shell program), it uses one of two available abstract storage backends—either a Berkeley DB database environment or a flat-file representation. (To learn more about the two repository backends, see the section called “Choosing a Data Storeâ€.) There has even been considerable interest by the development community in giving future releases of Subversion the ability to use other backend database systems, perhaps through a mechanism such as Open Database Connectivity (ODBC). In fact, Google did something similar to this before launching the Google Code Project Hosting service: they announced in mid-2006 that members of its open source team had written a new proprietary Subversion filesystem plug-in that used Google's ultra-scalable Bigtable database for its storage.
The filesystem API exported by
libsvn_fs
contains the kinds of
functionality you would expect from any other filesystem
API—you can create and remove files and directories,
copy and move them around, modify file contents, and so on.
It also has features that are not quite as common, such as the
ability to add, modify, and remove metadata
(“propertiesâ€) on each file or directory.
Furthermore, the Subversion filesystem is a versioning
filesystem, which means that as you make changes to your
directory tree, Subversion remembers what your tree looked
like before those changes. And before the previous changes.
And the previous ones. And so on, all the way back through
versioning time to (and just beyond) the moment you first
started adding things to the filesystem.
All the modifications you make to your tree are done within the context of a Subversion commit transaction. The following is a simplified general routine for modifying your filesystem:
Begin a Subversion commit transaction.
Make your changes (adds, deletes, property modifications, etc.).
Commit your transaction.
Once you have committed your transaction, your filesystem modifications are permanently stored as historical artifacts. Each of these cycles generates a single new revision of your tree, and each revision is forever accessible as an immutable snapshot of “the way things were.â€
Most of the functionality the filesystem
interface provides deals with actions that occur on individual
filesystem paths. That is, from outside the filesystem, the
primary mechanism for describing and accessing the individual
revisions of files and directories comes through the use of
path strings such as /foo/bar
, just as though
you were addressing files and directories through your
favorite shell program. You add new files and directories by
passing their paths-to-be to the right API functions. You
query for information about them by the same mechanism.
Unlike most filesystems, though, a path alone is not enough information to identify a file or directory in Subversion. Think of a directory tree as a two-dimensional system, where a node's siblings represent a sort of left-and-right motion, and navigating into the node's subdirectories represents a downward motion. Figure 8.1, “Files and directories in two dimensions†shows a typical representation of a tree as exactly that.
The difference here is that the Subversion filesystem has a
nifty third dimension that most filesystems do not
have—Time!
[53]
In the filesystem interface, nearly every function that has a
path
argument also expects a
root
argument. This
svn_fs_root_t
argument describes
either a revision or a Subversion transaction (which is simply
a revision in the making) and provides that third dimension
of context needed to understand the difference between
/foo/bar
in revision 32, and the same
path as it exists in revision 98. Figure 8.2, “Versioning time—the third dimension!†shows revision
history as an added dimension to the Subversion filesystem
universe.
As we mentioned earlier, the
libsvn_fs
API looks and feels like any
other filesystem, except that it has this wonderful versioning
capability. It was designed to be usable by any program
interested in a versioning filesystem. Not coincidentally,
Subversion itself is interested in that functionality. But
while the filesystem API should be sufficient for basic file
and directory versioning support, Subversion wants
more—and that is where libsvn_repos
comes in.
The Subversion repository library
(libsvn_repos
) sits (logically speaking)
atop the libsvn_fs
API, providing
additional functionality beyond that of the underlying
versioned filesystem logic. It does not completely wrap each
and every filesystem function—only certain major steps
in the general cycle of filesystem activity are wrapped by the
repository interface. Some of these include the creation and
commit of Subversion transactions and the modification of
revision properties. These particular events are wrapped by
the repository layer because they have hooks associated with
them. A repository hook system is not strictly related to
implementing a versioning filesystem, so it lives in the
repository wrapper library.
The hooks mechanism is but one of the reasons for the
abstraction of a separate repository library from the rest of
the filesystem code. The libsvn_repos
API provides several other important utilities to Subversion.
These include the abilities to:
Create, open, destroy, and perform recovery steps on a Subversion repository and the filesystem included in that repository.
Describe the differences between two filesystem trees.
Query for the commit log messages associated with all (or some) of the revisions in which a set of files was modified in the filesystem.
Generate a human-readable “dump†of the filesystem—a complete representation of the revisions in the filesystem.
Parse that dump format, loading the dumped revisions into a different Subversion repository.
As Subversion continues to evolve, the repository library will grow with the filesystem library to offer increased functionality and configurable option support.
If the Subversion Repository layer is at “the other
end of the line,†the Repository Access (RA) layer is
the line itself. Charged with marshaling data between the
client libraries and the repository, this layer includes the
libsvn_ra
module loader library, the RA
modules themselves (which currently includes
libsvn_ra_neon
,
libsvn_ra_local
,
libsvn_ra_serf
, and
libsvn_ra_svn
), and any additional
libraries needed by one or more of those RA modules (such as
the mod_dav_svn
Apache module or
libsvn_ra_svn
's server,
svnserve).
Since Subversion uses URLs to identify its repository
resources, the protocol portion of the URL scheme (usually
file://
, http://
,
https://
, svn://
, or
svn+ssh://
) is used to determine which RA
module will handle the communications. Each module registers
a list of the protocols it knows how to “speakâ€
so that the RA loader can, at runtime, determine which module
to use for the task at hand. You can determine which RA
modules are available to the Subversion command-line client,
and what protocols they claim to support, by running
svn --version
:
$ svn --version svn, version 1.5.0 (r31699) compiled Jun 18 2008, 09:57:36 Copyright (C) 2000-2008 CollabNet. Subversion is open source software, see http://subversion.tigris.org/ This product includes software developed by CollabNet (http://www.Collab.Net/). The following repository access (RA) modules are available: * ra_neon : Module for accessing a repository via WebDAV protocol using Neon. - handles 'http' scheme - handles 'https' scheme * ra_svn : Module for accessing a repository using the svn network protocol. - handles 'svn' scheme * ra_local : Module for accessing a repository on local disk. - handles 'file' scheme * ra_serf : Module for accessing a repository via WebDAV protocol using serf. - handles 'http' scheme - handles 'https' scheme $
The public API exported by the RA layer contains
functionality necessary for sending and receiving versioned
data to and from the repository. And each of the available RA
plug-ins is able to perform that task using a specific
protocol—libsvn_ra_dav
speaks
HTTP/WebDAV (optionally using SSL encryption) with an Apache
HTTP Server that is running the
mod_dav_svn
Subversion server module;
libsvn_ra_svn
speaks a custom network
protocol with the svnserve program; and so
on.
For those who wish to access a Subversion repository using still another protocol, that is precisely why the Repository Access layer is modularized! Developers can simply write a new library that implements the RA interface on one side and communicates with the repository on the other. Your new library can use existing network protocols or you can invent your own. You could use interprocess communication (IPC) calls, or—let's get crazy, shall we?—you could even implement an email-based protocol. Subversion supplies the APIs; you supply the creativity.
On the client side, the Subversion working copy is where all the action takes place. The bulk of functionality implemented by the client-side libraries exists for the sole purpose of managing working copies—directories full of files and other subdirectories that serve as a sort of local, editable “reflection†of one or more repository locations—and propagating changes to and from the Repository Access layer.
Subversion's working copy library,
libsvn_wc
, is directly responsible for
managing the data in the working copies. To accomplish this,
the library stores administrative information about each
working copy directory within a special subdirectory. This
subdirectory, named .svn
, is present in
each working copy directory and contains various other files
and directories that record state and provide a private
workspace for administrative action. For those familiar with
CVS, this .svn
subdirectory is similar in
purpose to the CVS
administrative
directories found in CVS working copies. For more information
about the .svn
administrative area, see
the section called “Inside the Working Copy Administration Area†later in this
chapter.
The Subversion client library,
libsvn_client
, has the broadest
responsibility; its job is to mingle the functionality of the
working copy library with that of the Repository Access layer,
and then to provide the highest-level API to any application
that wishes to perform general revision control actions. For
example, the function
svn_client_checkout()
takes a URL as an
argument. It passes this URL to the RA layer and opens an
authenticated session with a particular repository. It then
asks the repository for a certain tree, and sends this tree
into the working copy library, which then writes a full
working copy to disk (.svn
directories
and all).
The client library is designed to be used by any
application. While the Subversion source code includes a
standard command-line client, it should be very easy to write
any number of GUI clients on top of the client library. New
GUIs (or any new client, really) for Subversion need not be
clunky wrappers around the included command-line
client—they have full access via the
libsvn_client
API to the same functionality,
data, and callback mechanisms that the command-line client
uses. In fact, the Subversion source code tree contains a
small C program (which you can find at
tools/examples/minimal_client.c
) that
exemplifies how to wield the Subversion API to create a simple
client program.
[53] We understand that this may come as a shock to sci-fi fans who have long been under the impression that Time was actually the fourth dimension, and we apologize for any emotional trauma induced by our assertion of a different theory.
Due largely to the simplicity of the overall design of the Subversion repository and the technologies on which it relies, creating and configuring a repository are fairly straightforward tasks. There are a few preliminary decisions you'll want to make, but the actual work involved in any given setup of a Subversion repository is pretty basic, tending toward mindless repetition if you find yourself setting up multiples of these things.
Some things you'll want to consider beforehand, though, are:
What data do you expect to live in your repository (or repositories), and how will that data be organized?
Where will your repository live, and how will it be accessed?
What types of access control and repository event reporting do you need?
Which of the available types of data store do you want to use?
In this section, we'll try to help you answer those questions.
While Subversion allows you to move around versioned files and directories without any loss of information, and even provides ways of moving whole sets of versioned history from one repository to another, doing so can greatly disrupt the workflow of those who access the repository often and come to expect things to be at certain locations. So before creating a new repository, try to peer into the future a bit; plan ahead before placing your data under version control. By conscientiously “laying out†your repository or repositories and their versioned contents ahead of time, you can prevent many future headaches.
Let's assume that as repository administrator, you will be responsible for supporting the version control system for several projects. Your first decision is whether to use a single repository for multiple projects, or to give each project its own repository, or some compromise of these two.
There are benefits to using a single repository for multiple projects, most obviously the lack of duplicated maintenance. A single repository means that there is one set of hook programs, one thing to routinely back up, one thing to dump and load if Subversion releases an incompatible new version, and so on. Also, you can move data between projects easily, without losing any historical versioning information.
The downside of using a single repository is that different projects may have different requirements in terms of the repository event triggers, such as needing to send commit notification emails to different mailing lists, or having different definitions about what does and does not constitute a legitimate commit. These aren't insurmountable problems, of course—it just means that all of your hook scripts have to be sensitive to the layout of your repository rather than assuming that the whole repository is associated with a single group of people. Also, remember that Subversion uses repository-global revision numbers. While those numbers don't have any particular magical powers, some folks still don't like the fact that even though no changes have been made to their project lately, the youngest revision number for the repository keeps climbing because other projects are actively adding new revisions. [28]
A middle-ground approach can be taken, too. For example, projects can be grouped by how well they relate to each other. You might have a few repositories with a handful of projects in each repository. That way, projects that are likely to want to share data can do so easily, and as new revisions are added to the repository, at least the developers know that those new revisions are at least remotely related to everyone who uses that repository.
After deciding how to organize your projects with respect
to repositories, you'll probably want to think about directory
hierarchies within the repositories themselves. Because
Subversion uses regular directory copies for branching and
tagging (see Chapter 4, Branching and Merging), the
Subversion community recommends that you choose a repository
location for each project
root—the “topmost†directory
that contains data related to that project—and then
create three subdirectories beneath that root:
trunk
, meaning the directory under which
the main project development occurs;
branches
, which is a directory in which
to create various named branches of the main development line;
and tags
, which is a collection of tree
snapshots that are created, and perhaps destroyed, but never
changed.
[29]
For example, your repository might look like this:
/ calc/ trunk/ tags/ branches/ calendar/ trunk/ tags/ branches/ spreadsheet/ trunk/ tags/ branches/ …
Note that it doesn't matter where in your repository each project root is. If you have only one project per repository, the logical place to put each project root is at the root of that project's respective repository. If you have multiple projects, you might want to arrange them in groups inside the repository, perhaps putting projects with similar goals or shared code in the same subdirectory, or maybe just grouping them alphabetically. Such an arrangement might look like this:
/ utils/ calc/ trunk/ tags/ branches/ calendar/ trunk/ tags/ branches/ … office/ spreadsheet/ trunk/ tags/ branches/ …
Lay out your repository in whatever way you see fit. Subversion does not expect or enforce a particular layout—in its eyes, a directory is a directory is a directory. Ultimately, you should choose the repository arrangement that meets the needs of the people who work on the projects that live there.
In the name of full disclosure, though, we'll mention
another very common layout. In this layout, the
trunk
, tags
, and
branches
directories live in the root
directory of your repository, and your projects are in
subdirectories beneath those, like so:
/ trunk/ calc/ calendar/ spreadsheet/ … tags/ calc/ calendar/ spreadsheet/ … branches/ calc/ calendar/ spreadsheet/ …
There's nothing particularly incorrect about such a layout, but it may or may not seem as intuitive for your users. Especially in large, multiproject situations with many users, those users may tend to be familiar with only one or two of the projects in the repository. But the projects-as-branch-siblings approach tends to deemphasize project individuality and focus on the entire set of projects as a single entity. That's a social issue, though. We like our originally suggested arrangement for purely practical reasons—it's easier to ask about (or modify, or migrate elsewhere) the entire history of a single project when there's a single repository path that holds the entire history—past, present, tagged, and branched—for that project and that project alone.
Before creating your Subversion repository, an obvious question you'll need to answer is where the thing is going to live. This is strongly connected to myriad other questions involving how the repository will be accessed (via a Subversion server or directly), by whom (users behind your corporate firewall or the whole world out on the open Internet), what other services you'll be providing around Subversion (repository browsing interfaces, email-based commit notification, etc.), your data backup strategy, and so on.
We cover server choice and configuration in Chapter 6, Server Configuration, but the point we'd like to briefly make here is simply that the answers to some of these other questions might have implications that force your hand when deciding where your repository will live. For example, certain deployment scenarios might require accessing the repository via a remote filesystem from multiple computers, in which case (as you'll read in the next section) your choice of a repository backend data store turns out not to be a choice at all because only one of the available backends will work in this scenario.
Addressing each possible way to deploy Subversion is both impossible and outside the scope of this book. We simply encourage you to evaluate your options using these pages and other sources as your reference material and to plan ahead.
Subversion provides two options for the type of underlying data store—often referred to as “the backend†or, somewhat confusingly, “the (versioned) filesystemâ€â€”that each repository uses. One type of data store keeps everything in a Berkeley DB (or BDB) database environment; repositories that use this type are often referred to as being “BDB-backed.†The other type stores data in ordinary flat files, using a custom format. Subversion developers have adopted the habit of referring to this latter data storage mechanism as FSFS [30] —a versioned filesystem implementation that uses the native OS filesystem directly—rather than via a database library or some other abstraction layer—to store data.
Table 5.1, “Repository data store comparison†gives a comparative overview of Berkeley DB and FSFS repositories.
Table 5.1. Repository data store comparison
Category | Feature | Berkeley DB | FSFS |
---|---|---|---|
Reliability | Data integrity | When properly deployed, extremely reliable; Berkeley DB 4.4 brings auto-recovery | Older versions had some rarely demonstrated, but data-destroying bugs |
Sensitivity to interruptions | Very; crashes and permission problems can leave the database “wedged,†requiring journaled recovery procedures | Quite insensitive | |
Accessibility | Usable from a read-only mount | No | Yes |
Platform-independent storage | No | Yes | |
Usable over network filesystems | Generally, no | Yes | |
Group permissions handling | Sensitive to user umask problems; best if accessed by only one user | Works around umask problems | |
Scalability | Repository disk usage | Larger (especially if logfiles aren't purged) | Smaller |
Number of revision trees | Database; no problems | Some older native filesystems don't scale well with thousands of entries in a single directory | |
Directories with many files | Slower | Faster | |
Performance | Checking out latest revision | No meaningful difference | No meaningful difference |
Large commits | Slower overall, but cost is amortized across the lifetime of the commit | Faster overall, but finalization delay may cause client timeouts |
There are advantages and disadvantages to each of these two backend types. Neither of them is more “official†than the other, though the newer FSFS is the default data store as of Subversion 1.2. Both are reliable enough to trust with your versioned data. But as you can see in Table 5.1, “Repository data store comparisonâ€, the FSFS backend provides quite a bit more flexibility in terms of its supported deployment scenarios. More flexibility means you have to work a little harder to find ways to deploy it incorrectly. Those reasons—plus the fact that not using Berkeley DB means there's one fewer component in the system—largely explain why today almost everyone uses the FSFS backend when creating new repositories.
Fortunately, most programs that access Subversion repositories are blissfully ignorant of which backend data store is in use. And you aren't even necessarily stuck with your first choice of a data store—in the event that you change your mind later, Subversion provides ways of migrating your repository's data into another repository that uses a different backend data store. We talk more about that later in this chapter.
The following subsections provide a more detailed look at the available backend data store types.
When the initial design phase of Subversion was in progress, the developers decided to use Berkeley DB for a variety of reasons, including its open source license, transaction support, reliability, performance, API simplicity, thread safety, support for cursors, and so on.
Berkeley DB provides real transaction support—perhaps its most powerful feature. Multiple processes accessing your Subversion repositories don't have to worry about accidentally clobbering each other's data. The isolation provided by the transaction system is such that for any given operation, the Subversion repository code sees a static view of the database—not a database that is constantly changing at the hand of some other process—and can make decisions based on that view. If the decision made happens to conflict with what another process is doing, the entire operation is rolled back as though it never happened, and Subversion gracefully retries the operation against a new, updated (and yet still static) view of the database.
Another great feature of Berkeley DB is hot backups—the ability to back up the database environment without taking it “offline.†We'll discuss how to back up your repository later in this chapter (in the section called “Repository Backupâ€), but the benefits of being able to make fully functional copies of your repositories without any downtime should be obvious.
Berkeley DB is also a very reliable database system when properly used. Subversion uses Berkeley DB's logging facilities, which means that the database first writes to on-disk logfiles a description of any modifications it is about to make, and then makes the modification itself. This is to ensure that if anything goes wrong, the database system can back up to a previous checkpoint—a location in the logfiles known not to be corrupt—and replay transactions until the data is restored to a usable state. See the section called “Managing Disk Space†later in this chapter for more about Berkeley DB logfiles.
But every rose has its thorn, and so we must note some known limitations of Berkeley DB. First, Berkeley DB environments are not portable. You cannot simply copy a Subversion repository that was created on a Unix system onto a Windows system and expect it to work. While much of the Berkeley DB database format is architecture-independent, other aspects of the environment are not. Second, Subversion uses Berkeley DB in a way that will not operate on Windows 95/98 systems—if you need to house a BDB-backed repository on a Windows machine, stick with Windows 2000 or later.
While Berkeley DB promises to behave correctly on network shares that meet a particular set of specifications, [31] most networked filesystem types and appliances do not actually meet those requirements. And in no case can you allow a BDB-backed repository that resides on a network share to be accessed by multiple clients of that share at once (which quite often is the whole point of having the repository live on a network share in the first place).
Warning | |
---|---|
If you attempt to use Berkeley DB on a noncompliant remote filesystem, the results are unpredictable—you may see mysterious errors right away, or it may be months before you discover that your repository database is subtly corrupted. You should strongly consider using the FSFS data store for repositories that need to live on a network share. |
Finally, because Berkeley DB is a library linked directly into Subversion, it's more sensitive to interruptions than a typical relational database system. Most SQL systems, for example, have a dedicated server process that mediates all access to tables. If a program accessing the database crashes for some reason, the database daemon notices the lost connection and cleans up any mess left behind. And because the database daemon is the only process accessing the tables, applications don't need to worry about permission conflicts. These things are not the case with Berkeley DB, however. Subversion (and programs using Subversion libraries) access the database tables directly, which means that a program crash can leave the database in a temporarily inconsistent, inaccessible state. When this happens, an administrator needs to ask Berkeley DB to restore to a checkpoint, which is a bit of an annoyance. Other things can cause a repository to “wedge†besides crashed processes, such as programs conflicting over ownership and permissions on the database files.
Note | |
---|---|
Berkeley DB 4.4 brings (to Subversion 1.4 and later) the ability for Subversion to automatically and transparently recover Berkeley DB environments in need of such recovery. When a Subversion process attaches to a repository's Berkeley DB environment, it uses some process accounting mechanisms to detect any unclean disconnections by previous processes, performs any necessary recovery, and then continues on as though nothing happened. This doesn't completely eliminate instances of repository wedging, but it does drastically reduce the amount of human interaction required to recover from them. |
So while a Berkeley DB repository is quite fast and
scalable, it's best used by a single server process running
as one user—such as Apache's httpd
or svnserve (see Chapter 6, Server Configuration)—rather than accessing it
as many different users via file://
or
svn+ssh://
URLs. If you're accessing a Berkeley
DB repository directly as multiple users, be sure to read
the section called “Supporting Multiple Repository Access Methods†later in this
chapter.
In mid-2004, a second type of repository storage system—one that doesn't use a database at all—came into being. An FSFS repository stores the changes associated with a revision in a single file, and so all of a repository's revisions can be found in a single subdirectory full of numbered files. Transactions are created in separate subdirectories as individual files. When complete, the transaction file is renamed and moved into the revisions directory, thus guaranteeing that commits are atomic. And because a revision file is permanent and unchanging, the repository also can be backed up while “hot,†just like a BDB-backed repository.
The FSFS revision files describe a revision's directory structure, file contents, and deltas against files in other revision trees. Unlike a Berkeley DB database, this storage format is portable across different operating systems and isn't sensitive to CPU architecture. Because no journaling or shared-memory files are being used, the repository can be safely accessed over a network filesystem and examined in a read-only environment. The lack of database overhead also means the overall repository size is a bit smaller.
FSFS has different performance characteristics, too. When committing a directory with a huge number of files, FSFS is able to more quickly append directory entries. On the other hand, FSFS writes the latest version of a file as a delta against an earlier version, which means that checking out the latest tree is a bit slower than fetching the full-texts stored in a Berkeley DB HEAD revision. FSFS also has a longer delay when finalizing a commit, which could in extreme cases cause clients to time out while waiting for a response.
The most important distinction, however, is FSFS's imperviousness to wedging when something goes wrong. If a process using a Berkeley DB database runs into a permissions problem or suddenly crashes, the database can be left in an unusable state until an administrator recovers it. If the same scenarios happen to a process using an FSFS repository, the repository isn't affected at all. At worst, some transaction data is left behind.
The only real argument against FSFS is its relative immaturity compared to Berkeley DB. Unlike Berkeley DB, which has years of history, its own dedicated development team, and, now, Oracle's mighty name attached to it, [32] FSFS is a newer bit of engineering. Prior to Subversion 1.4, it was still shaking out some pretty serious data integrity bugs, which, while triggered in only very rare cases, nonetheless did occur. That said, FSFS has quickly become the backend of choice for some of the largest public and private Subversion repositories, and it promises a lower barrier to entry for Subversion across the board.
[28] Whether founded in ignorance or in poorly considered concepts about how to derive legitimate software development metrics, global revision numbers are a silly thing to fear, and not the kind of thing you should weigh when deciding how to arrange your projects and repositories.
[29] The trunk
, tags
,
and branches
trio is sometimes referred
to as “the TTB directories.â€
[30] Often pronounced “fuzz-fuzz,†if Jack Repenning has anything to say about it. (This book, however, assumes that the reader is thinking “eff-ess-eff-ess.â€)
[31] Berkeley DB requires that the underlying filesystem implement strict POSIX locking semantics, and more importantly, the ability to map files directly into process memory.
[32] Oracle bought Sleepycat and its flagship software, Berkeley DB, on Valentine's Day in 2006.
There are many different uses for branching and svn merge, and this section describes the most common.
Version control is most often used for software development, so here's a quick peek at two of the most common branching/merging patterns used by teams of programmers. If you're not using Subversion for software development, feel free to skip this section. If you're a software developer using version control for the first time, pay close attention, as these patterns are often considered best practices by experienced folk. These processes aren't specific to Subversion; they're applicable to any version control system. Still, it may help to see them described in Subversion terms.
Most software has a typical life cycle: code, test, release, repeat. There are two problems with this process. First, developers need to keep writing new features while quality assurance teams take time to test supposedly stable versions of the software. New work cannot halt while the software is tested. Second, the team almost always needs to support older, released versions of software; if a bug is discovered in the latest code, it most likely exists in released versions as well, and customers will want to get that bug fix without having to wait for a major new release.
Here's where version control can help. The typical procedure looks like this:
Developers commit all new work to the
trunk.
Day-to-day changes are committed to
/trunk
: new features, bug fixes, and
so on.
The trunk is copied to a
“release†branch.
When the team thinks the software is ready for release
(say, a 1.0 release), /trunk
might be copied to
/branches/1.0
.
Teams continue to work in parallel.
One team begins rigorous testing of the release branch,
while another team continues new work (say, for version
2.0) on /trunk
. If bugs are
discovered in either location, fixes are ported back and
forth as necessary. At some point, however, even that
process stops. The branch is “frozen†for
final testing right before a release.
The branch is tagged and released.
When testing is complete,
/branches/1.0
is copied to
/tags/1.0.0
as a reference
snapshot. The tag is packaged and released to
customers.
The branch is maintained over time.
While work continues on /trunk
for
version 2.0, bug fixes continue to be ported from
/trunk
to
/branches/1.0
. When enough
bug fixes have accumulated, management may decide to do a
1.0.1 release: /branches/1.0
is
copied to /tags/1.0.1
, and the tag
is packaged and released.
This entire process repeats as the software matures: when the 2.0 work is complete, a new 2.0 release branch is created, tested, tagged, and eventually released. After some years, the repository ends up with a number of release branches in “maintenance†mode, and a number of tags representing final shipped versions.
A feature branch is the sort of
branch that's been the dominant example in this chapter (the
one you've been working on while Sally continues to work on
/trunk
). It's a temporary branch created
to work on a complex change without interfering with the
stability of /trunk
. Unlike release
branches (which may need to be supported forever), feature
branches are born, used for a while, merged back to the trunk,
and then ultimately deleted. They have a finite span of
usefulness.
Again, project policies vary widely concerning exactly
when it's appropriate to create a feature branch. Some
projects never use feature branches at all: commits to
/trunk
are a free-for-all. The
advantage to this system is that it's simple—nobody
needs to learn about branching or merging. The disadvantage
is that the trunk code is often unstable or unusable. Other
projects use branches to an extreme: no change is
ever committed to the trunk directly.
Even the most trivial changes are created on a short-lived
branch, carefully reviewed, and merged to the trunk. Then
the branch is deleted. This system guarantees an
exceptionally stable and usable trunk at all times, but at
the cost of tremendous process overhead.
Most projects take a middle-of-the-road approach. They
commonly insist that /trunk
compile and
pass regression tests at all times. A feature branch is
required only when a change requires a large number of
destabilizing commits. A good rule of thumb is to ask this
question: if the developer worked for days in isolation and
then committed the large change all at once (so that
/trunk
were never destabilized), would it
be too large a change to review? If the answer to that
question is “yes,†the change should be
developed on a feature branch. As the developer commits
incremental changes to the branch, they can be easily reviewed
by peers.
Finally, there's the issue of how to best keep a feature branch in “sync†with the trunk as work progresses. As we mentioned earlier, there's a great risk to working on a branch for weeks or months; trunk changes may continue to pour in, to the point where the two lines of development differ so greatly that it may become a nightmare trying to merge the branch back to the trunk.
This situation is best avoided by regularly merging trunk changes to the branch. Make up a policy: once a week, merge the last week's worth of trunk changes to the branch.
At some point, you'll be ready to merge the
“synchronized†feature branch back to the trunk.
To do this, begin by doing a final merge of the latest trunk
changes to the branch. When that's done, the latest versions
of branch and trunk will be absolutely identical except for
your branch changes. You would then merge back with
the --reintegrate
option:
$ cd trunk-working-copy $ svn update At revision 1910. $ svn merge --reintegrate ^/branches/mybranch --- Merging differences between repository URLs into '.': U real.c U integer.c A newdirectory A newdirectory/newfile U . …
Another way of thinking about this pattern is that your weekly sync of trunk to branch is analogous to running svn update in a working copy, while the final merge step is analogous to running svn commit from a working copy. After all, what else is a working copy but a very shallow private branch? It's a branch that's capable of storing only one change at a time.
svn delete — Delete an item from a working copy or the repository.
Items specified by PATH
are
scheduled for deletion upon the next commit. Files (and
directories that have not been committed) are immediately
removed from the working copy unless the
--keep-local
option is given. The
command will not remove any unversioned or modified items;
use the --force
option to override this
behavior.
Items specified by URL are deleted from the repository via an immediate commit. Multiple URLs are committed atomically.
--editor-cmd CMD --encoding ENC --file (-F) FILENAME --force --force-log --keep-local --message (-m) MESSAGE --quiet (-q) --targets FILENAME --with-revprop ARG
Using svn to delete a file from your working copy deletes your local copy of the file, but it merely schedules the file to be deleted from the repository. When you commit, the file is deleted in the repository.
$ svn delete myfile D myfile $ svn commit -m "Deleted file 'myfile'." Deleting myfile Transmitting file data . Committed revision 14.
Deleting a URL, however, is immediate, so you have to supply a log message:
$ svn delete -m "Deleting file 'yourfile'" \ file:///var/svn/repos/test/yourfile Committed revision 15.
Here's an example of how to force deletion of a file that has local mods:
$ svn delete over-there svn: Attempting restricted operation for modified resource svn: Use --force to override this restriction svn: 'over-there' has local modifications $ svn delete --force over-there D over-there
Unlike CVS, a Subversion working copy is aware that it has checked out a module. That means if somebody changes the definition of a module (e.g., adds or removes components), a call to svn update will update the working copy appropriately, adding and removing components.
Subversion defines modules as a list of directories within a directory property; see the section called “Externals Definitionsâ€.
svn import — Commit an unversioned file or tree into the repository.
Recursively commit a copy of
PATH
to
URL
. If
PATH
is omitted,
“.
†is assumed. Parent
directories are created in the repository as necessary.
Unversionable items such as device files and pipes are
ignored even if --force
is
specified.
--auto-props --depth ARG --editor-cmd CMD --encoding ENC --file (-F) FILENAME --force --force-log --message (-m) MESSAGE --no-auto-props --no-ignore --quiet (-q) --with-revprop ARG
This imports the local directory
myproj
into
trunk/misc
in your repository. The
directory trunk/misc
need not exist
before you import into it—svn
import will recursively create directories for
you.
$ svn import -m "New import" myproj \ http://svn.red-bean.com/repos/trunk/misc Adding myproj/sample.txt … Transmitting file data ......... Committed revision 16.
Be aware that this will not
create a directory named myproj
in
the repository. If that's what you want, simply add
myproj
to the end of the URL:
$ svn import -m "New import" myproj \ http://svn.red-bean.com/repos/trunk/misc/myproj Adding myproj/sample.txt … Transmitting file data ......... Committed revision 16.
After importing data, note that the original tree is not under version control. To start working, you still need to svn checkout a fresh working copy of the tree.
Maintaining a Subversion repository can be daunting, mostly due to the complexities inherent in systems that have a database backend. Doing the task well is all about knowing the tools—what they are, when to use them, and how. This section will introduce you to the repository administration tools provided by Subversion and discuss how to wield them to accomplish tasks such as repository data migration, upgrades, backups, and cleanups.
Subversion provides a handful of utilities useful for creating, inspecting, modifying, and repairing your repository. Let's look more closely at each of those tools. Afterward, we'll briefly examine some of the utilities included in the Berkeley DB distribution that provide functionality specific to your repository's database backend not otherwise provided by Subversion's own tools.
The svnadmin program is the repository administrator's best friend. Besides providing the ability to create Subversion repositories, this program allows you to perform several maintenance operations on those repositories. The syntax of svnadmin is similar to that of other Subversion command-line programs:
$ svnadmin help general usage: svnadmin SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...] Type 'svnadmin help <subcommand>' for help on a specific subcommand. Type 'svnadmin --version' to see the program version and FS modules. Available subcommands: crashtest create deltify …
Previously in this chapter (in the section called “Creating the Repositoryâ€), we were introduced to the svnadmin create subcommand. Most of the other svnadmin subcommands we will cover later in this chapter. And you can consult the section called “svnadmin†for a full rundown of subcommands and what each of them offers.
svnlook is a tool provided by Subversion for examining the various revisions and transactions (which are revisions in the making) in a repository. No part of this program attempts to change the repository. svnlook is typically used by the repository hooks for reporting the changes that are about to be committed (in the case of the pre-commit hook) or that were just committed (in the case of the post-commit hook) to the repository. A repository administrator may use this tool for diagnostic purposes.
svnlook has a straightforward syntax:
$ svnlook help general usage: svnlook SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...] Note: any subcommand which takes the '--revision' and '--transaction' options will, if invoked without one of those options, act on the repository's youngest revision. Type 'svnlook help <subcommand>' for help on a specific subcommand. Type 'svnlook --version' to see the program version and FS modules. …
Most of svnlook's
subcommands can operate on either a revision or a
transaction tree, printing information about the tree
itself, or how it differs from the previous revision of the
repository. You use the --revision
(-r
) and --transaction
(-t
) options to specify which revision or
transaction, respectively, to examine. In the absence of
both the --revision
(-r
)
and --transaction
(-t
)
options, svnlook will examine the
youngest (or HEAD
) revision in the
repository. So the following two commands do exactly the
same thing when 19 is the youngest revision in the
repository located at
/var/svn/repos
:
$ svnlook info /var/svn/repos $ svnlook info /var/svn/repos -r 19
One exception to these rules about subcommands is the svnlook youngest subcommand, which takes no options and simply prints out the repository's youngest revision number:
$ svnlook youngest /var/svn/repos 19 $
Note | |
---|---|
Keep in mind that the only transactions you can browse
are uncommitted ones. Most repositories will have no such
transactions because transactions are usually either
committed (in which case, you should access them as
revision with the |
Output from svnlook is designed to be both human- and machine-parsable. Take, as an example, the output of the svnlook info subcommand:
$ svnlook info /var/svn/repos sally 2002-11-04 09:29:13 -0600 (Mon, 04 Nov 2002) 27 Added the usual Greek tree. $
The output of svnlook info consists of the following, in the order given:
The author, followed by a newline
The date, followed by a newline
The number of characters in the log message, followed by a newline
The log message itself, followed by a newline
This output is human-readable, meaning items such as the datestamp are displayed using a textual representation instead of something more obscure (such as the number of nanoseconds since the Tastee Freez guy drove by). But the output is also machine-parsable—because the log message can contain multiple lines and be unbounded in length, svnlook provides the length of that message before the message itself. This allows scripts and other wrappers around this command to make intelligent decisions about the log message, such as how much memory to allocate for the message, or at least how many bytes to skip in the event that this output is not the last bit of data in the stream.
svnlook can perform a variety of other queries: displaying subsets of bits of information we've mentioned previously, recursively listing versioned directory trees, reporting which paths were modified in a given revision or transaction, showing textual and property differences made to files and directories, and so on. See the section called “svnlook†for a full reference of svnlook's features.
While it won't be the most commonly used tool at the administrator's disposal, svndumpfilter provides a very particular brand of useful functionality—the ability to quickly and easily modify streams of Subversion repository history data by acting as a path-based filter.
The syntax of svndumpfilter is as follows:
$ svndumpfilter help general usage: svndumpfilter SUBCOMMAND [ARGS & OPTIONS ...] Type 'svndumpfilter help <subcommand>' for help on a specific subcommand. Type 'svndumpfilter --version' to see the program version. Available subcommands: exclude include help (?, h)
There are only two interesting subcommands: svndumpfilter exclude and svndumpfilter include. They allow you to make the choice between implicit or explicit inclusion of paths in the stream. You can learn more about these subcommands and svndumpfilter's unique purpose later in this chapter, in the section called “Filtering Repository Historyâ€.
The svnsync program, which was new to the 1.4 release of Subversion, provides all the functionality required for maintaining a read-only mirror of a Subversion repository. The program really has one job—to transfer one repository's versioned history into another repository. And while there are few ways to do that, its primary strength is that it can operate remotely—the “source†and “sink†[33] repositories may be on different computers from each other and from svnsync itself.
As you might expect, svnsync has a syntax that looks very much like every other program we've mentioned in this chapter:
$ svnsync help general usage: svnsync SUBCOMMAND DEST_URL [ARGS & OPTIONS ...] Type 'svnsync help <subcommand>' for help on a specific subcommand. Type 'svnsync --version' to see the program version and RA modules. Available subcommands: initialize (init) synchronize (sync) copy-revprops info help (?, h) $
We talk more about replicating repositories with svnsync later in this chapter (see the section called “Repository Replicationâ€).
While not an official member of the Subversion
toolchain, the fsfs-reshard.py script
(found in the tools/server-side
directory of the Subversion source distribution) is a useful
performance tuning tool for administrators of FSFS-backed
Subversion repositories. As described in the sidebar
Revision files and shards,
FSFS repositories use individual files to house information
about each revision. Sometimes these files all live in a
single directory; sometimes they are sharded across many
directories. But the neat thing is that the number of
directories used to house these files is
configurable. That's where
fsfs-reshard.py comes in.
fsfs-reshard.py reshuffles the repository's file structure into a new arrangement that reflects the requested number of sharding subdirectories and updates the repository configuration to preserve this change. This is especially useful for converting an older Subversion repository into the new Subversion 1.5 sharded layout (which Subversion will not automatically do for you) or for fine-tuning an already sharded repository.
If you're using a Berkeley DB repository, all of
your versioned filesystem's structure and data live in a set
of database tables within the db/
subdirectory of your repository. This subdirectory is a
regular Berkeley DB environment directory and can therefore
be used in conjunction with any of the Berkeley database
tools, typically provided as part of the Berkeley DB
distribution.
For day-to-day Subversion use, these tools are unnecessary. Most of the functionality typically needed for Subversion repositories has been duplicated in the svnadmin tool. For example, svnadmin list-unused-dblogs and svnadmin list-dblogs perform a subset of what is provided by the Berkeley db_archive utility, and svnadmin recover reflects the common use cases of the db_recover utility.
However, there are still a few Berkeley DB utilities that you might find useful. The db_dump and db_load programs write and read, respectively, a custom file format that describes the keys and values in a Berkeley DB database. Since Berkeley databases are not portable across machine architectures, this format is a useful way to transfer those databases from machine to machine, irrespective of architecture or operating system. As we describe later in this chapter, you can also use svnadmin dump and svnadmin load for similar purposes, but db_dump and db_load can do certain jobs just as well and much faster. They can also be useful if the experienced Berkeley DB hacker needs to do in-place tweaking of the data in a BDB-backed repository for some reason, which is something Subversion's utilities won't allow. Also, the db_stat utility can provide useful information about the status of your Berkeley DB environment, including detailed statistics about the locking and storage subsystems.
For more information on the Berkeley DB tool chain, visit the documentation section of the Berkeley DB section of Oracle's web site, located at http://www.oracle.com/technology/documentation/berkeley-db/db/.
Sometimes a user will have an error in her log message (a
misspelling or some misinformation, perhaps). If the
repository is configured (using the
pre-revprop-change
hook; see the section called “Implementing Repository Hooksâ€) to accept changes to
this log message after the commit is finished, the user
can “fix†her log message remotely using
svn propset (see svn propset). However, because of the
potential to lose information forever, Subversion repositories
are not, by default, configured to allow changes to
unversioned properties—except by an
administrator.
If a log message needs to be changed by an administrator,
this can be done using svnadmin setlog.
This command changes the log message (the
svn:log
property) on a given revision of a
repository, reading the new value from a provided file.
$ echo "Here is the new, correct log message" > newlog.txt $ svnadmin setlog myrepos newlog.txt -r 388
The svnadmin setlog command, by
default, is
still bound by the same protections against modifying
unversioned properties as a remote client is—the
pre-
and
post-revprop-change
hooks are still
triggered, and therefore must be set up to accept changes of
this nature. But an administrator can get around these
protections by passing the --bypass-hooks
option to the svnadmin setlog command.
Warning | |
---|---|
Remember, though, that by bypassing the hooks, you are likely avoiding such things as email notifications of property changes, backup systems that track unversioned property changes, and so on. In other words, be very careful about what you are changing, and how you change it. |
While the cost of storage has dropped incredibly in the past few years, disk usage is still a valid concern for administrators seeking to version large amounts of data. Every bit of version history information stored in the live repository needs to be backed up elsewhere, perhaps multiple times as part of rotating backup schedules. It is useful to know what pieces of Subversion's repository data need to remain on the live site, which need to be backed up, and which can be safely removed.
To keep the repository small, Subversion uses deltification (or deltified storage) within the repository itself. Deltification involves encoding the representation of a chunk of data as a collection of differences against some other chunk of data. If the two pieces of data are very similar, this deltification results in storage savings for the deltified chunk—rather than taking up space equal to the size of the original data, it takes up only enough space to say, “I look just like this other piece of data over here, except for the following couple of changes.†The result is that most of the repository data that tends to be bulky—namely, the contents of versioned files—is stored at a much smaller size than the original full-text representation of that data. And for repositories created with Subversion 1.4 or later, the space savings are even better—now those full-text representations of file contents are themselves compressed.
Note | |
---|---|
Because all of the data that is subject to deltification in a BDB-backed repository is stored in a single Berkeley DB database file, reducing the size of the stored values will not immediately reduce the size of the database file itself. Berkeley DB will, however, keep internal records of unused areas of the database file and consume those areas first before growing the size of the database file. So while deltification doesn't produce immediate space savings, it can drastically slow future growth of the database. |
Though they are uncommon, there are circumstances in which a Subversion commit process might fail, leaving behind in the repository the remnants of the revision-to-be that wasn't—an uncommitted transaction and all the file and directory changes associated with it. This could happen for several reasons: perhaps the client operation was inelegantly terminated by the user, or a network failure occurred in the middle of an operation. Regardless of the reason, dead transactions can happen. They don't do any real harm, other than consuming disk space. A fastidious administrator may nonetheless wish to remove them.
You can use the svnadmin lstxns command to list the names of the currently outstanding transactions:
$ svnadmin lstxns myrepos 19 3a1 a45 $
Each item in the resultant output can then be used with
svnlook (and its
--transaction
(-t
) option)
to determine who created the transaction, when it was
created, what types of changes were made in the
transaction—information that is helpful in determining
whether the transaction is a safe candidate for
removal! If you do indeed want to remove a transaction, its
name can be passed to svnadmin rmtxns,
which will perform the cleanup of the transaction. In fact,
svnadmin rmtxns can take its input
directly from the output of
svnadmin lstxns!
$ svnadmin rmtxns myrepos `svnadmin lstxns myrepos` $
If you use these two subcommands like this, you should consider making your repository temporarily inaccessible to clients. That way, no one can begin a legitimate transaction before you start your cleanup. Example 5.1, “txn-info.sh (reporting outstanding transactions)†contains a bit of shell-scripting that can quickly generate information about each outstanding transaction in your repository.
Example 5.1. txn-info.sh (reporting outstanding transactions)
#!/bin/sh ### Generate informational output for all outstanding transactions in ### a Subversion repository. REPOS="${1}" if [ "x$REPOS" = x ] ; then echo "usage: $0 REPOS_PATH" exit fi for TXN in `svnadmin lstxns ${REPOS}`; do echo "---[ Transaction ${TXN} ]-------------------------------------------" svnlook info "${REPOS}" -t "${TXN}" done
The output of the script is basically a concatenation of several chunks of svnlook info output (see the section called “svnlookâ€) and will look something like this:
$ txn-info.sh myrepos ---[ Transaction 19 ]------------------------------------------- sally 2001-09-04 11:57:19 -0500 (Tue, 04 Sep 2001) 0 ---[ Transaction 3a1 ]------------------------------------------- harry 2001-09-10 16:50:30 -0500 (Mon, 10 Sep 2001) 39 Trying to commit over a faulty network. ---[ Transaction a45 ]------------------------------------------- sally 2001-09-12 11:09:28 -0500 (Wed, 12 Sep 2001) 0 $
A long-abandoned transaction usually represents some sort of failed or interrupted commit. A transaction's datestamp can provide interesting information—for example, how likely is it that an operation begun nine months ago is still active?
In short, transaction cleanup decisions need not be made unwisely. Various sources of information—including Apache's error and access logs, Subversion's operational logs, Subversion revision history, and so on—can be employed in the decision-making process. And of course, an administrator can often simply communicate with a seemingly dead transaction's owner (via email, e.g.) to verify that the transaction is, in fact, in a zombie state.
Until recently, the largest offender of disk space usage with respect to BDB-backed Subversion repositories were the logfiles in which Berkeley DB performs its prewrites before modifying the actual database files. These files capture all the actions taken along the route of changing the database from one state to another—while the database files, at any given time, reflect a particular state, the logfiles contain all of the many changes along the way between states. Thus, they can grow and accumulate quite rapidly.
Fortunately, beginning with the 4.2 release of Berkeley
DB, the database environment has the ability to remove its
own unused logfiles automatically. Any
repositories created using svnadmin
when compiled against Berkeley DB version 4.2 or later
will be configured for this automatic logfile removal. If
you don't want this feature enabled, simply pass the
--bdb-log-keep
option to the
svnadmin create command. If you forget
to do this or change your mind at a later time, simply edit
the DB_CONFIG
file found in your
repository's db
directory, comment out
the line that contains the set_flags
DB_LOG_AUTOREMOVE
directive, and then run
svnadmin recover on your repository to
force the configuration changes to take effect. See the section called “Berkeley DB Configuration†for more information about
database configuration.
Without some sort of automatic logfile removal in place, logfiles will accumulate as you use your repository. This is actually somewhat of a feature of the database system—you should be able to recreate your entire database using nothing but the logfiles, so these files can be useful for catastrophic database recovery. But typically, you'll want to archive the logfiles that are no longer in use by Berkeley DB, and then remove them from disk to conserve space. Use the svnadmin list-unused-dblogs command to list the unused logfiles:
$ svnadmin list-unused-dblogs /var/svn/repos /var/svn/repos/log.0000000031 /var/svn/repos/log.0000000032 /var/svn/repos/log.0000000033 … $ rm `svnadmin list-unused-dblogs /var/svn/repos` ## disk space reclaimed!
Warning | |
---|---|
BDB-backed repositories whose logfiles are used as part of a backup or disaster recovery plan should not make use of the logfile autoremoval feature. Reconstruction of a repository's data from logfiles can only be accomplished only when all the logfiles are available. If some of the logfiles are removed from disk before the backup system has a chance to copy them elsewhere, the incomplete set of backed-up logfiles is essentially useless. |
As described in the sidebar Revision files and shards, FSFS-backed Subversion repositories create, by default, a new on-disk file for each revision added to the repository. Having thousands of these files present on your Subversion server—even when housed in separate shard directories—can lead to inefficiencies.
The first problem is that the operating system has to reference many different files over a short period of time. This leads to inefficient use of disk caches and, as a result, more time spent seeking across large disks. Because of this, Subversion pays a performance penalty when accessing your versioned data.
The second problem is a bit more subtle. Because of the ways that most filesystems allocate disk space, each file claims more space on the disk than it actually uses. The amount of extra space required to house a single file can average anywhere from 2 to 16 kilobytes per file, depending on the underlying filesystem in use. This translates directly into a per-revision disk usage penalty for FSFS-backed repositories. The effect is most pronounced in repositories which have many small revisions, since the overhead involved in storing the revision file quickly outgrows the size of the actual data being stored.
To solve these problems, Subversion 1.6 introduced the svnadmin pack command. By concatenating all the files of a completed shard into a single “pack†file and then removing the original per-revision files, svnadmin pack reduces the file count within a given shard down to just a single file. In doing so, it aids filesystem caches and reduces (to one) the number of times a file storage overhead penalty is paid.
Subversion can pack existing sharded repositories which have been upgraded to the 1.6 filesystem format (see svnadmin upgrade). To do so, just run svnadmin pack on the repository:
$ svnadmin pack /var/svn/repos Packing shard 0...done. Packing shard 1...done. Packing shard 2...done. … Packing shard 34...done. Packing shard 35...done. Packing shard 36...done. $
Because the packing process obtains the required locks before doing its work, you can run it on live repositories, or even as part of a post-commit hook. Repacking packed shards is legal, but will have no effect on the disk usage of the repository.
svnadmin pack has no effect on BDB-backed Subversion repositories.
As mentioned in the section called “Berkeley DBâ€, a Berkeley DB repository can sometimes be left in a frozen state if not closed properly. When this happens, an administrator needs to rewind the database back into a consistent state. This is unique to BDB-backed repositories, though—if you are using FSFS-backed ones instead, this won't apply to you. And for those of you using Subversion 1.4 with Berkeley DB 4.4 or later, you should find that Subversion has become much more resilient in these types of situations. Still, wedged Berkeley DB repositories do occur, and an administrator needs to know how to safely deal with this circumstance.
To protect the data in your repository, Berkeley DB uses a locking mechanism. This mechanism ensures that portions of the database are not simultaneously modified by multiple database accessors, and that each process sees the data in the correct state when that data is being read from the database. When a process needs to change something in the database, it first checks for the existence of a lock on the target data. If the data is not locked, the process locks the data, makes the change it wants to make, and then unlocks the data. Other processes are forced to wait until that lock is removed before they are permitted to continue accessing that section of the database. (This has nothing to do with the locks that you, as a user, can apply to versioned files within the repository; we try to clear up the confusion caused by this terminology collision in the sidebar The Three Meanings of “Lockâ€.)
In the course of using your Subversion repository, fatal errors or interruptions can prevent a process from having the chance to remove the locks it has placed in the database. The result is that the backend database system gets “wedged.†When this happens, any attempts to access the repository hang indefinitely (since each new accessor is waiting for a lock to go away—which isn't going to happen).
If this happens to your repository, don't panic. The Berkeley DB filesystem takes advantage of database transactions, checkpoints, and prewrite journaling to ensure that only the most catastrophic of events [34] can permanently destroy a database environment. A sufficiently paranoid repository administrator will have made off-site backups of the repository data in some fashion, but don't head off to the tape backup storage closet just yet.
Instead, use the following recipe to attempt to “unwedge†your repository:
Make sure no processes are accessing (or attempting to access) the repository. For networked repositories, this also means shutting down the Apache HTTP Server or svnserve daemon.
Become the user who owns and manages the repository. This is important, as recovering a repository while running as the wrong user can tweak the permissions of the repository's files in such a way that your repository will still be inaccessible even after it is “unwedged.â€
Run the command svnadmin recover
/var/svn/repos
. You should see output such as
this:
Repository lock acquired. Please wait; recovering the repository may take some time... Recovery completed. The latest repos revision is 19.
This command may take many minutes to complete.
Restart the server process.
This procedure fixes almost every case of repository
wedging. Make sure that you run this command as the user that
owns and manages the database, not just as
root
. Part of the recovery process might
involve re-creating from scratch various database files (shared
memory regions, e.g.). Recovering as
root
will create those files such that they
are owned by root
, which means that even
after you restore connectivity to your repository, regular
users will be unable to access it.
If the previous procedure, for some reason, does not
successfully unwedge your repository, you should do two
things. First, move your broken repository directory aside
(perhaps by renaming it to something like
repos.BROKEN
) and then restore your
latest backup of it. Then, send an email to the Subversion
users mailing list (at <users@subversion.tigris.org>
)
describing your problem in detail. Data integrity is an
extremely high priority to the Subversion developers.
A Subversion filesystem has its data spread throughout files in the repository, in a fashion generally understood by (and of interest to) only the Subversion developers themselves. However, circumstances may arise that call for all, or some subset, of that data to be copied or moved into another repository.
Subversion provides such functionality by way of repository dump streams. A repository dump stream (often referred to as a “dump file†when stored as a file on disk) is a portable, flat file format that describes the various revisions in your repository—what was changed, by whom, when, and so on. This dump stream is the primary mechanism used to marshal versioned history—in whole or in part, with or without modification—between repositories. And Subversion provides the tools necessary for creating and loading these dump streams: the svnadmin dump and svnadmin load subcommands, respectively.
Warning | |
---|---|
While the Subversion repository dump format contains human-readable portions and a familiar structure (it resembles an RFC 822 format, the same type of format used for most email), it is not a plain-text file format. It is a binary file format, highly sensitive to meddling. For example, many text editors will corrupt the file by automatically converting line endings. |
There are many reasons for dumping and loading Subversion repository data. Early in Subversion's life, the most common reason was due to the evolution of Subversion itself. As Subversion matured, there were times when changes made to the backend database schema caused compatibility issues with previous versions of the repository, so users had to dump their repository data using the previous version of Subversion and load it into a freshly created repository with the new version of Subversion. Now, these types of schema changes haven't occurred since Subversion's 1.0 release, and the Subversion developers promise not to force users to dump and load their repositories when upgrading between minor versions (such as from 1.3 to 1.4) of Subversion. But there are still other reasons for dumping and loading, including re-deploying a Berkeley DB repository on a new OS or CPU architecture, switching between the Berkeley DB and FSFS backends, or (as we'll cover later in this chapter in the section called “Filtering Repository Historyâ€) purging versioned data from repository history.
Note | |
---|---|
The Subversion repository dump format describes versioned repository changes only. It will not carry any information about uncommitted transactions, user locks on filesystem paths, repository or server configuration customizations (including hook scripts), and so on. |
Whatever your reason for migrating repository history, using the svnadmin dump and svnadmin load subcommands is straightforward. svnadmin dump will output a range of repository revisions that are formatted using Subversion's custom filesystem dump format. The dump format is printed to the standard output stream, while informative messages are printed to the standard error stream. This allows you to redirect the output stream to a file while watching the status output in your terminal window. For example:
$ svnlook youngest myrepos 26 $ svnadmin dump myrepos > dumpfile * Dumped revision 0. * Dumped revision 1. * Dumped revision 2. … * Dumped revision 25. * Dumped revision 26.
At the end of the process, you will have a single file
(dumpfile
in the previous example) that
contains all the data stored in your repository in the
requested range of revisions. Note that svnadmin
dump is reading revision trees from the repository
just like any other “reader†process would
(e.g., svn checkout), so it's safe
to run this command at any time.
The other subcommand in the pair, svnadmin load, parses the standard input stream as a Subversion repository dump file and effectively replays those dumped revisions into the target repository for that operation. It also gives informative feedback, this time using the standard output stream:
$ svnadmin load newrepos < dumpfile <<< Started new txn, based on original revision 1 * adding path : A ... done. * adding path : A/B ... done. … ------- Committed new rev 1 (loaded from original rev 1) >>> <<< Started new txn, based on original revision 2 * editing path : A/mu ... done. * editing path : A/D/G/rho ... done. ------- Committed new rev 2 (loaded from original rev 2) >>> … <<< Started new txn, based on original revision 25 * editing path : A/D/gamma ... done. ------- Committed new rev 25 (loaded from original rev 25) >>> <<< Started new txn, based on original revision 26 * adding path : A/Z/zeta ... done. * editing path : A/mu ... done. ------- Committed new rev 26 (loaded from original rev 26) >>>
The result of a load is new revisions added to a
repository—the same thing you get by making commits
against that repository from a regular Subversion client.
Just as in a commit, you can use hook programs to perform
actions before and after each of the commits made during a
load process. By passing the
--use-pre-commit-hook
and
--use-post-commit-hook
options to
svnadmin load, you can instruct Subversion
to execute the pre-commit and post-commit hook programs,
respectively, for each loaded revision. You might use these,
for example, to ensure that loaded revisions pass through the
same validation steps that regular commits pass through. Of
course, you should use these options with care—if your
post-commit hook sends emails to a mailing list for each new
commit, you might not want to spew hundreds or thousands of
commit emails in rapid succession at that list! You can read more about the use of hook
scripts in the section called “Implementing Repository Hooksâ€.
Note that because svnadmin uses standard input and output streams for the repository dump and load processes, people who are feeling especially saucy can try things such as this (perhaps even using different versions of svnadmin on each side of the pipe):
$ svnadmin create newrepos $ svnadmin dump oldrepos | svnadmin load newrepos
By default, the dump file will be quite large—much
larger than the repository itself. That's because by default
every version of every file is expressed as a full text in the
dump file. This is the fastest and simplest behavior, and
it's nice if you're piping the dump data directly into some other
process (such as a compression program, filtering program, or
loading process). But if you're creating a dump file
for longer-term storage, you'll likely want to save disk space
by using the --deltas
option. With this
option, successive revisions of files will be output as
compressed, binary differences—just as file revisions
are stored in a repository. This option is slower, but it
results in a dump file much closer in size to the original
repository.
We mentioned previously that svnadmin
dump outputs a range of revisions. Use the
--revision
(-r
) option to
specify a single revision, or a range of revisions, to dump.
If you omit this option, all the existing repository revisions
will be dumped.
$ svnadmin dump myrepos -r 23 > rev-23.dumpfile $ svnadmin dump myrepos -r 100:200 > revs-100-200.dumpfile
As Subversion dumps each new revision, it outputs only enough information to allow a future loader to re-create that revision based on the previous one. In other words, for any given revision in the dump file, only the items that were changed in that revision will appear in the dump. The only exception to this rule is the first revision that is dumped with the current svnadmin dump command.
By default, Subversion will not express the first dumped revision as merely differences to be applied to the previous revision. For one thing, there is no previous revision in the dump file! And second, Subversion cannot know the state of the repository into which the dump data will be loaded (if it ever is). To ensure that the output of each execution of svnadmin dump is self-sufficient, the first dumped revision is, by default, a full representation of every directory, file, and property in that revision of the repository.
However, you can change this default behavior. If you add
the --incremental
option when you dump your
repository, svnadmin will compare the first
dumped revision against the previous revision in the
repository—the same way it treats every other revision that
gets dumped. It will then output the first revision exactly
as it does the rest of the revisions in the dump
range—mentioning only the changes that occurred in that
revision. The benefit of this is that you can create several
small dump files that can be loaded in succession, instead of
one large one, like so:
$ svnadmin dump myrepos -r 0:1000 > dumpfile1 $ svnadmin dump myrepos -r 1001:2000 --incremental > dumpfile2 $ svnadmin dump myrepos -r 2001:3000 --incremental > dumpfile3
These dump files could be loaded into a new repository with the following command sequence:
$ svnadmin load newrepos < dumpfile1 $ svnadmin load newrepos < dumpfile2 $ svnadmin load newrepos < dumpfile3
Another neat trick you can perform with this
--incremental
option involves appending to an
existing dump file a new range of dumped revisions. For
example, you might have a post-commit
hook
that simply appends the repository dump of the single revision
that triggered the hook. Or you might have a script that runs
nightly to append dump file data for all the revisions that
were added to the repository since the last time the script
ran. Used like this, svnadmin dump can be
one way to back up changes to your repository over time in case
of a system crash or some other catastrophic event.
The dump format can also be used to merge the contents of
several different repositories into a single repository. By
using the --parent-dir
option of
svnadmin load, you can specify a new
virtual root directory for the load process. That means if
you have dump files for three repositories—say
calc-dumpfile
,
cal-dumpfile
, and
ss-dumpfile
—you can first create a new
repository to hold them all:
$ svnadmin create /var/svn/projects $
Then, make new directories in the repository that will encapsulate the contents of each of the three previous repositories:
$ svn mkdir -m "Initial project roots" \ file:///var/svn/projects/calc \ file:///var/svn/projects/calendar \ file:///var/svn/projects/spreadsheet Committed revision 1. $
Lastly, load the individual dump files into their respective locations in the new repository:
$ svnadmin load /var/svn/projects --parent-dir calc < calc-dumpfile … $ svnadmin load /var/svn/projects --parent-dir calendar < cal-dumpfile … $ svnadmin load /var/svn/projects --parent-dir spreadsheet < ss-dumpfile … $
We'll mention one final way to use the Subversion repository dump format—conversion from a different storage mechanism or version control system altogether. Because the dump file format is, for the most part, human-readable, it should be relatively easy to describe generic sets of changes—each of which should be treated as a new revision—using this file format. In fact, the cvs2svn utility (see the section called “Converting a Repository from CVS to Subversionâ€) uses the dump format to represent the contents of a CVS repository so that those contents can be copied into a Subversion repository.
Since Subversion stores your versioned history using, at the very least, binary differencing algorithms and data compression (optionally in a completely opaque database system), attempting manual tweaks is unwise if not quite difficult, and at any rate strongly discouraged. And once data has been stored in your repository, Subversion generally doesn't provide an easy way to remove that data. [35] But inevitably, there will be times when you would like to manipulate the history of your repository. You might need to strip out all instances of a file that was accidentally added to the repository (and shouldn't be there for whatever reason). [36] Or, perhaps you have multiple projects sharing a single repository, and you decide to split them up into their own repositories. To accomplish tasks such as these, administrators need a more manageable and malleable representation of the data in their repositories—the Subversion repository dump format.
As we described earlier in the section called “Migrating Repository Data Elsewhereâ€, the Subversion repository dump format is a human-readable representation of the changes that you've made to your versioned data over time. Use the svnadmin dump command to generate the dump data, and svnadmin load to populate a new repository with it. The great thing about the human-readability aspect of the dump format is that, if you aren't careless about it, you can manually inspect and modify it. Of course, the downside is that if you have three years' worth of repository activity encapsulated in what is likely to be a very large dump file, it could take you a long, long time to manually inspect and modify it.
That's where svndumpfilter becomes useful. This program acts as a path-based filter for repository dump streams. Simply give it either a list of paths you wish to keep or a list of paths you wish to not keep, and then pipe your repository dump data through this filter. The result will be a modified stream of dump data that contains only the versioned paths you (explicitly or implicitly) requested.
Let's look at a realistic example of how you might use this program. Earlier in this chapter (see the section called “Planning Your Repository Organizationâ€), we discussed the process of deciding how to choose a layout for the data in your repositories—using one repository per project or combining them, arranging stuff within your repository, and so on. But sometimes after new revisions start flying in, you rethink your layout and would like to make some changes. A common change is the decision to move multiple projects that are sharing a single repository into separate repositories for each project.
Our imaginary repository contains three projects:
calc
, calendar
, and
spreadsheet
. They have been living
side-by-side in a layout like this:
/ calc/ trunk/ branches/ tags/ calendar/ trunk/ branches/ tags/ spreadsheet/ trunk/ branches/ tags/
To get these three projects into their own repositories, we first dump the whole repository:
$ svnadmin dump /var/svn/repos > repos-dumpfile * Dumped revision 0. * Dumped revision 1. * Dumped revision 2. * Dumped revision 3. … $
Next, run that dump file through the filter, each time including only one of our top-level directories. This results in three new dump files:
$ svndumpfilter include calc < repos-dumpfile > calc-dumpfile … $ svndumpfilter include calendar < repos-dumpfile > cal-dumpfile … $ svndumpfilter include spreadsheet < repos-dumpfile > ss-dumpfile … $
At this point, you have to make a decision. Each of your
dump files will create a valid repository, but will preserve
the paths exactly as they were in the original repository.
This means that even though you would have a repository solely
for your calc
project, that repository
would still have a top-level directory named
calc
. If you want your
trunk
, tags
, and
branches
directories to live in the root
of your repository, you might wish to edit your dump files,
tweaking the Node-path
and
Node-copyfrom-path
headers so that they no
longer have that first calc/
path
component. Also, you'll want to remove the section of dump
data that creates the calc
directory. It
will look something like the following:
Node-path: calc Node-action: add Node-kind: dir Content-length: 0
Warning | |
---|---|
If you do plan on manually editing the dump file to
remove a top-level directory, make sure your editor is
not set to automatically convert end-of-line characters to
the native format (e.g., |
All that remains now is to create your three new repositories, and load each dump file into the right repository, ignoring the UUID found in the dump stream:
$ svnadmin create calc $ svnadmin load --ignore-uuid calc < calc-dumpfile <<< Started new transaction, based on original revision 1 * adding path : Makefile ... done. * adding path : button.c ... done. … $ svnadmin create calendar $ svnadmin load --ignore-uuid calendar < cal-dumpfile <<< Started new transaction, based on original revision 1 * adding path : Makefile ... done. * adding path : cal.c ... done. … $ svnadmin create spreadsheet $ svnadmin load --ignore-uuid spreadsheet < ss-dumpfile <<< Started new transaction, based on original revision 1 * adding path : Makefile ... done. * adding path : ss.c ... done. … $
Both of svndumpfilter's subcommands accept options for deciding how to deal with “empty†revisions. If a given revision contains only changes to paths that were filtered out, that now-empty revision could be considered uninteresting or even unwanted. So to give the user control over what to do with those revisions, svndumpfilter provides the following command-line options:
--drop-empty-revs
Do not generate empty revisions at all—just omit them.
--renumber-revs
If empty revisions are dropped (using the
--drop-empty-revs
option), change the
revision numbers of the remaining revisions so that
there are no gaps in the numeric sequence.
--preserve-revprops
If empty revisions are not dropped, preserve the revision properties (log message, author, date, custom properties, etc.) for those empty revisions. Otherwise, empty revisions will contain only the original datestamp, and a generated log message that indicates that this revision was emptied by svndumpfilter.
While svndumpfilter can be very
useful and a huge timesaver, there are unfortunately a
couple of gotchas. First, this utility is overly sensitive
to path semantics. Pay attention to whether paths in your
dump file are specified with or without leading slashes.
You'll want to look at the Node-path
and
Node-copyfrom-path
headers.
… Node-path: spreadsheet/Makefile …
If the paths have leading slashes, you should include leading slashes in the paths you pass to svndumpfilter include and svndumpfilter exclude (and if they don't, you shouldn't). Further, if your dump file has an inconsistent usage of leading slashes for some reason, [37] you should probably normalize those paths so that they all have, or all lack, leading slashes.
Also, copied paths can give you some trouble. Subversion supports copy operations in the repository, where a new path is created by copying some already existing path. It is possible that at some point in the lifetime of your repository, you might have copied a file or directory from some location that svndumpfilter is excluding, to a location that it is including. To make the dump data self-sufficient, svndumpfilter needs to still show the addition of the new path—including the contents of any files created by the copy—and not represent that addition as a copy from a source that won't exist in your filtered dump data stream. But because the Subversion repository dump format shows only what was changed in each revision, the contents of the copy source might not be readily available. If you suspect that you have any copies of this sort in your repository, you might want to rethink your set of included/excluded paths, perhaps including the paths that served as sources of your troublesome copy operations, too.
Finally, svndumpfilter takes path
filtering quite literally. If you are trying to copy the
history of a project rooted at
trunk/my-project
and move it into a
repository of its own, you would, of course, use the
svndumpfilter include command to keep all
the changes in and under
trunk/my-project
. But the resultant
dump file makes no assumptions about the repository into
which you plan to load this data. Specifically, the dump
data might begin with the revision that added the
trunk/my-project
directory, but it will
not contain directives that would
create the trunk
directory itself
(because trunk
doesn't match the
include filter). You'll need to make sure that any
directories that the new dump stream expects to exist
actually do exist in the target repository before trying to
load the stream into that repository.
There are several scenarios in which it is quite handy to have a Subversion repository whose version history is exactly the same as some other repository's. Perhaps the most obvious one is the maintenance of a simple backup repository, used when the primary repository has become inaccessible due to a hardware failure, network outage, or other such annoyance. Other scenarios include deploying mirror repositories to distribute heavy Subversion load across multiple servers, use as a soft-upgrade mechanism, and so on.
As of version 1.4, Subversion provides a program for managing scenarios such as these—svnsync. This works by essentially asking the Subversion server to “replay†revisions, one at a time. It then uses that revision information to mimic a commit of the same to another repository. Neither repository needs to be locally accessible to the machine on which svnsync is running—its parameters are repository URLs, and it does all its work through Subversion's Repository Access (RA) interfaces. All it requires is read access to the source repository and read/write access to the destination repository.
Note | |
---|---|
When using svnsync against a remote source repository, the Subversion server for that repository must be running Subversion version 1.4 or later. |
Assuming you already have a source repository that you'd like to mirror, the next thing you need is an empty target repository that will actually serve as that mirror. This target repository can use either of the available filesystem data-store backends (see the section called “Choosing a Data Storeâ€), but it must not yet have any version history in it. The protocol that svnsync uses to communicate revision information is highly sensitive to mismatches between the versioned histories contained in the source and target repositories. For this reason, while svnsync cannot demand that the target repository be read-only, [38] allowing the revision history in the target repository to change by any mechanism other than the mirroring process is a recipe for disaster.
Warning | |
---|---|
Do not modify a mirror repository in such a way as to cause its version history to deviate from that of the repository it mirrors. The only commits and revision property modifications that ever occur on that mirror repository should be those performed by the svnsync tool. |
Another requirement of the target repository is that the svnsync process be allowed to modify revision properties. Because svnsync works within the framework of that repository's hook system, the default state of the repository (which is to disallow revision property changes; see pre-revprop-change) is insufficient. You'll need to explicitly implement the pre-revprop-change hook, and your script must allow svnsync to set and change revision properties. With those provisions in place, you are ready to start mirroring repository revisions.
Tip | |
---|---|
It's a good idea to implement authorization measures that allow your repository replication process to perform its tasks while preventing other users from modifying the contents of your mirror repository at all. |
Let's walk through the use of svnsync in a somewhat typical mirroring scenario. We'll pepper this discourse with practical recommendations, which you are free to disregard if they aren't required by or suitable for your environment.
As a service to the fine developers of our favorite version control system, we will be mirroring the public Subversion source code repository and exposing that mirror publicly on the Internet, hosted on a different machine than the one on which the original Subversion source code repository lives. This remote host has a global configuration that permits anonymous users to read the contents of repositories on the host, but requires users to authenticate to modify those repositories. (Please forgive us for glossing over the details of Subversion server configuration for the moment—those are covered thoroughly in Chapter 6, Server Configuration.) And for no other reason than that it makes for a more interesting example, we'll be driving the replication process from a third machine—the one that we currently find ourselves using.
First, we'll create the repository which will be our mirror. This and the next couple of steps do require shell access to the machine on which the mirror repository will live. Once the repository is all configured, though, we shouldn't need to touch it directly again.
$ ssh admin@svn.example.com \ "svnadmin create /var/svn/svn-mirror" admin@svn.example.com's password: ******** $
At this point, we have our repository, and due to our
server's configuration, that repository is now
“live†on the Internet. Now, because we don't
want anything modifying the repository except our replication
process, we need a way to distinguish that process from other
would-be committers. To do so, we use a dedicated username
for our process. Only commits and revision property
modifications performed by the special username
syncuser
will be allowed.
We'll use the repository's hook system both to allow the
replication process to do what it needs to do and to enforce
that only it is doing those things. We accomplish this by
implementing two of the repository event
hooks—pre-revprop-change and start-commit. Our
pre-revprop-change
hook script is found
in Example 5.2, “Mirror repository's pre-revprop-change hook scriptâ€, and basically verifies that the user attempting the
property changes is our syncuser
user. If
so, the change is allowed; otherwise, it is denied.
Example 5.2. Mirror repository's pre-revprop-change hook script
#!/bin/sh USER="$3" if [ "$USER" = "syncuser" ]; then exit 0; fi echo "Only the syncuser user may change revision properties" >&2 exit 1
That covers revision property changes. Now we need to
ensure that only the syncuser
user is
permitted to commit new revisions to the repository. We do
this using a start-commit
hook scripts
such as the one in Example 5.3, “Mirror repository's start-commit hook scriptâ€.
Example 5.3. Mirror repository's start-commit hook script
#!/bin/sh USER="$2" if [ "$USER" = "syncuser" ]; then exit 0; fi echo "Only the syncuser user may commit new revisions" >&2 exit 1
After installing our hook scripts and ensuring that they are executable by the Subversion server, we're finished with the setup of the mirror repository. Now, we get to actually do the mirroring.
The first thing we need to do with svnsync is to register in our target repository the fact that it will be a mirror of the source repository. We do this using the svnsync initialize subcommand. The URLs we provide point to the root directories of the target and source repositories, respectively. In Subversion 1.4, this is required—only full mirroring of repositories is permitted. In Subversion 1.5, though, you can use svnsync to mirror only some subtree of the repository, too.
$ svnsync help init initialize (init): usage: svnsync initialize DEST_URL SOURCE_URL Initialize a destination repository for synchronization from another repository. … $ svnsync initialize http://svn.example.com/svn-mirror \ http://svn.collab.net/repos/svn \ --sync-username syncuser --sync-password syncpass Copied properties for revision 0. $
Our target repository will now remember that it is a mirror of the public Subversion source code repository. Notice that we provided a username and password as arguments to svnsync—that was required by the pre-revprop-change hook on our mirror repository.
Note | |
---|---|
In Subversion 1.4, the values given to
svnsync's This has been fixed in Subversion 1.5 with the
introduction of two new pairs of options. Use
|
And now comes the fun part. With a single subcommand, we can tell svnsync to copy all the as-yet-unmirrored revisions from the source repository to the target. [39] The svnsync synchronize subcommand will peek into the special revision properties previously stored on the target repository, and determine both what repository it is mirroring as well as that the most recently mirrored revision was revision 0. Then it will query the source repository and determine what the latest revision in that repository is. Finally, it asks the source repository's server to start replaying all the revisions between 0 and that latest revision. As svnsync get the resultant response from the source repository's server, it begins forwarding those revisions to the target repository's server as new commits.
$ svnsync help synchronize synchronize (sync): usage: svnsync synchronize DEST_URL Transfer all pending revisions to the destination from the source with which it was initialized. … $ svnsync synchronize http://svn.example.com/svn-mirror Transmitting file data ........................................ Committed revision 1. Copied properties for revision 1. Transmitting file data .. Committed revision 2. Copied properties for revision 2. Transmitting file data ..... Committed revision 3. Copied properties for revision 3. … Transmitting file data .. Committed revision 23406. Copied properties for revision 23406. Transmitting file data . Committed revision 23407. Copied properties for revision 23407. Transmitting file data .... Committed revision 23408. Copied properties for revision 23408. $
Of particular interest here is that for each mirrored
revision, there is first a commit of that revision to the
target repository, and then property changes follow. This is
because the initial commit is performed by (and attributed to)
the user syncuser
, and it is datestamped
with the time as of that revision's creation. Also,
Subversion's underlying repository access interfaces don't
provide a mechanism for setting arbitrary revision properties
as part of a commit. So svnsync follows up
with an immediate series of property modifications that copy
into the target repository all the revision properties found
for that revision in the source repository. This also has the
effect of fixing the author and datestamp of the revision to
match that of the source repository.
Also noteworthy is that svnsync performs careful bookkeeping that allows it to be safely interrupted and restarted without ruining the integrity of the mirrored data. If a network glitch occurs while mirroring a repository, simply repeat the svnsync synchronize command, and it will happily pick up right where it left off. In fact, as new revisions appear in the source repository, this is exactly what you do to keep your mirror up to date.
There is, however, one bit of inelegance in the process. Because Subversion revision properties can be changed at any time throughout the lifetime of the repository, and because they don't leave an audit trail that indicates when they were changed, replication processes have to pay special attention to them. If you've already mirrored the first 15 revisions of a repository and someone then changes a revision property on revision 12, svnsync won't know to go back and patch up its copy of revision 12. You'll need to tell it to do so manually by using (or with some additional tooling around) the svnsync copy-revprops subcommand, which simply rereplicates all the revision properties for a particular revision or range thereof.
$ svnsync help copy-revprops copy-revprops: usage: svnsync copy-revprops DEST_URL [REV[:REV2]] Copy the revision properties in a given range of revisions to the destination from the source with which it was initialized. … $ svnsync copy-revprops http://svn.example.com/svn-mirror 12 Copied properties for revision 12. $
That's repository replication in a nutshell. You'll likely want some automation around such a process. For example, while our example was a pull-and-push setup, you might wish to have your primary repository push changes to one or more blessed mirrors as part of its post-commit and post-revprop-change hook implementations. This would enable the mirror to be up to date in as near to real time as is likely possible.
Also, while it isn't very commonplace to do so, svnsync does gracefully mirror repositories in which the user as whom it authenticates has only partial read access. It simply copies only the bits of the repository that it is permitted to see. Obviously, such a mirror is not useful as a backup solution.
In Subversion 1.5, svnsync grew the ability to also mirror a subset of a repository rather than the whole thing. The process of setting up and maintaining such a mirror is exactly the same as when mirroring a whole repository, except that instead of specifying the source repository's root URL when running svnsync init, you specify the URL of some subdirectory within that repository. Synchronization to that mirror will now copy only the bits that changed under that source repository subdirectory. There are some limitations to this support, though. First, you can't mirror multiple disjoint subdirectories of the source repository into a single mirror repository—you'd need to instead mirror some parent directory that is common to both. Second, the filtering logic is entirely path-based, so if the subdirectory you are mirroring was renamed at some point in the past, your mirror would contain only the revisions since the directory appeared at the URL you specified. And likewise, if the source subdirectory is renamed in the future, your synchronization processes will stop mirroring data at the point that the source URL you specified is no longer valid.
As far as user interaction with repositories and mirrors goes, it is possible to have a single working copy that interacts with both, but you'll have to jump through some hoops to make it happen. First, you need to ensure that both the primary and mirror repositories have the same repository UUID (which is not the case by default). See the section called “Managing Repository UUIDs†later in this chapter for more about this.
Once the two repositories have the same UUID, you can use
svn switch with the --relocate
option to point your working
copy to whichever of the repositories you wish to operate
against, a process that is described in svn switch. There is a possible danger
here, though, in that if the primary and mirror repositories
aren't in close synchronization, a working copy up to date
with, and pointing to, the primary repository will, if
relocated to point to an out-of-date mirror, become confused
about the apparent sudden loss of revisions it fully expects
to be present, and it will throw errors to that effect. If
this occurs, you can relocate your working copy back to the
primary repository and then either wait until the mirror
repository is up to date, or backdate your working copy to a
revision you know is present in the sync repository, and then
retry the relocation.
Finally, be aware that the revision-based replication provided by svnsync is only that—replication of revisions. Only information carried by the Subversion repository dump file format is available for replication. As such, svnsync has the same sorts of limitations that the repository dump stream has, and does not include such things as the hook implementations, repository or server configuration data, uncommitted transactions, or information about user locks on repository paths.
Despite numerous advances in technology since the birth of the modern computer, one thing unfortunately rings true with crystalline clarity—sometimes things go very, very awry. Power outages, network connectivity dropouts, corrupt RAM, and crashed hard drives are but a taste of the evil that Fate is poised to unleash on even the most conscientious administrator. And so we arrive at a very important topic—how to make backup copies of your repository data.
There are two types of backup methods available for Subversion repository administrators—full and incremental. A full backup of the repository involves squirreling away in one sweeping action all the information required to fully reconstruct that repository in the event of a catastrophe. Usually, it means, quite literally, the duplication of the entire repository directory (which includes either a Berkeley DB or FSFS environment). Incremental backups are lesser things: backups of only the portion of the repository data that has changed since the previous backup.
As far as full backups go, the naïve approach might seem like a sane one, but unless you temporarily disable all other access to your repository, simply doing a recursive directory copy runs the risk of generating a faulty backup. In the case of Berkeley DB, the documentation describes a certain order in which database files can be copied that will guarantee a valid backup copy. A similar ordering exists for FSFS data. But you don't have to implement these algorithms yourself, because the Subversion development team has already done so. The svnadmin hotcopy command takes care of the minutia involved in making a hot backup of your repository. And its invocation is as trivial as the Unix cp or Windows copy operations:
$ svnadmin hotcopy /var/svn/repos /var/svn/repos-backup
The resultant backup is a fully functional Subversion repository, able to be dropped in as a replacement for your live repository should something go horribly wrong.
When making copies of a Berkeley DB repository, you can
even instruct svnadmin hotcopy to purge any
unused Berkeley DB logfiles (see the section called “Purging unused Berkeley DB logfilesâ€) from the
original repository upon completion of the copy. Simply
provide the --clean-logs
option on the
command line.
$ svnadmin hotcopy --clean-logs /var/svn/bdb-repos /var/svn/bdb-repos-backup
Additional tooling around this command is available, too.
The tools/backup/
directory of the
Subversion source distribution holds the
hot-backup.py script. This script adds a
bit of backup management atop svnadmin
hotcopy, allowing you to keep only the most recent
configured number of backups of each repository. It will
automatically manage the names of the backed-up repository
directories to avoid collisions with previous backups and
will “rotate off†older backups, deleting them so
that only the most recent ones remain. Even if you also have an
incremental backup, you might want to run this program on a
regular basis. For example, you might consider using
hot-backup.py from a program scheduler
(such as cron on Unix systems), which can
cause it to run nightly (or at whatever granularity of time
you deem safe).
Some administrators use a different backup mechanism built
around generating and storing repository dump data. We
described in the section called “Migrating Repository Data Elsewhereâ€
how to use svnadmin dump with the --incremental
option to
perform an incremental backup of a given revision or range of
revisions. And of course, you can achieve a full backup variation of
this by omitting the --incremental
option to that command. There is some value in these methods,
in that the format of your backed-up information is
flexible—it's not tied to a particular platform,
versioned filesystem type, or release of Subversion or
Berkeley DB. But that flexibility comes at a cost, namely
that restoring that data can take a long time—longer
with each new revision committed to your repository. Also, as
is the case with so many of the various backup methods,
revision property changes that are made to already backed-up
revisions won't get picked up by a nonoverlapping,
incremental dump generation. For these reasons, we recommend
against relying solely on dump-based backup approaches.
As you can see, each of the various backup types and methods has its advantages and disadvantages. The easiest is by far the full hot backup, which will always result in a perfect working replica of your repository. Should something bad happen to your live repository, you can restore from the backup with a simple recursive directory copy. Unfortunately, if you are maintaining multiple backups of your repository, these full copies will each eat up just as much disk space as your live repository. Incremental backups, by contrast, tend to be quicker to generate and smaller to store. But the restoration process can be a pain, often involving applying multiple incremental backups. And other methods have their own peculiarities. Administrators need to find the balance between the cost of making the backup and the cost of restoring it.
The svnsync program (see the section called “Repository Replicationâ€) actually provides a rather handy middle-ground approach. If you are regularly synchronizing a read-only mirror with your main repository, in a pinch your read-only mirror is probably a good candidate for replacing that main repository if it falls over. The primary disadvantage of this method is that only the versioned repository data gets synchronized—repository configuration files, user-specified repository path locks, and other items that might live in the physical repository directory but not inside the repository's virtual versioned filesystem are not handled by svnsync.
In any backup scenario, repository administrators need to be aware of how modifications to unversioned revision properties affect their backups. Since these changes do not themselves generate new revisions, they will not trigger post-commit hooks, and may not even trigger the pre-revprop-change and post-revprop-change hooks. [40] And since you can change revision properties without respect to chronological order—you can change any revision's properties at any time—an incremental backup of the latest few revisions might not catch a property modification to a revision that was included as part of a previous backup.
Generally speaking, only the truly paranoid would need to back up their entire repository, say, every time a commit occurred. However, assuming that a given repository has some other redundancy mechanism in place with relatively fine granularity (such as per-commit emails or incremental dumps), a hot backup of the database might be something that a repository administrator would want to include as part of a system-wide nightly backup. It's your data—protect it as much as you'd like.
Often, the best approach to repository backups is a diversified one that leverages combinations of the methods described here. The Subversion developers, for example, back up the Subversion source code repository nightly using hot-backup.py and an off-site rsync of those full backups; keep multiple archives of all the commit and property change notification emails; and have repository mirrors maintained by various volunteers using svnsync. Your solution might be similar, but should be catered to your needs and that delicate balance of convenience with paranoia. And whatever you do, validate your backups from time to time—what good is a spare tire that has a hole in it? While all of this might not save your hardware from the iron fist of Fate, [41] it should certainly help you recover from those trying times.
Subversion repositories have a universally unique identifier (UUID) associated with them. This is used by Subversion clients to verify the identity of a repository when other forms of verification aren't good enough (such as checking the repository URL, which can change over time). Most Subversion repository administrators rarely, if ever, need to think about repository UUIDs as anything more than a trivial implementation detail of Subversion. Sometimes, however, there is cause for attention to this detail.
As a general rule, you want the UUIDs of your live repositories to be unique. That is, after all, the point of having UUIDs. But there are times when you want the repository UUIDs of two repositories to be exactly the same. For example, if you make a copy of a repository for backup purposes, you want the backup to be a perfect replica of the original so that, in the event that you have to restore that backup and replace the live repository, users don't suddenly see what looks like a different repository. When dumping and loading repository history (as described earlier in the section called “Migrating Repository Data Elsewhereâ€), you get to decide whether to apply the UUID encapsulated in the data dump stream to the repository in which you are loading the data. The particular circumstance will dictate the correct behavior.
There are a couple of ways to set (or reset) a repository's UUID, should you need to. As of Subversion 1.5, this is as simple as using the svnadmin setuuid command. If you provide this subcommand with an explicit UUID, it will validate that the UUID is well-formed and then set the repository UUID to that value. If you omit the UUID, a brand-new UUID will be generated for your repository.
$ svnlook uuid /var/svn/repos cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec $ svnadmin setuuid /var/svn/repos # generate a new UUID $ svnlook uuid /var/svn/repos 3c3c38fe-acc0-11dc-acbc-1b37ff1c8e7c $ svnadmin setuuid /var/svn/repos \ cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec # restore the old UUID $ svnlook uuid /var/svn/repos cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec $
For folks using versions of Subversion earlier than 1.5,
these tasks are a little more complicated. You can explicitly
set a repository's UUID by piping a repository dump file stub
that carries the new UUID specification through
svnadmin load --force-uuid
.REPOS-PATH
$ svnadmin load --force-uuid /var/svn/repos <<EOF SVN-fs-dump-format-version: 2 UUID: cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec EOF $ svnlook uuid /var/svn/repos cf2b9d22-acb5-11dc-bc8c-05e83ce5dbec $
Having older versions of Subversion generate a brand-new UUID is not quite as simple to do, though. Your best bet here is to find some other way to generate a UUID, and then explicitly set the repository's UUID to that value.
[33] Or is that, the “sync�
[34] For example, hard drive + huge electromagnet = disaster.
[35] That's rather the reason you use version control at all, right?
[36] Conscious, cautious removal of certain bits of versioned data is actually supported by real use cases. That's why an “obliterate†feature has been one of the most highly requested Subversion features, and one which the Subversion developers hope to soon provide.
[37] While svnadmin dump has a consistent leading slash policy (to not include them), other programs that generate dump data might not be so consistent.
[38] In fact, it can't truly be read-only, or svnsync itself would have a tough time copying revision history into it.
[39] Be forewarned that while it will take only a few seconds for the average reader to parse this paragraph and the sample output that follows it, the actual time required to complete such a mirroring operation is, shall we say, quite a bit longer.
[40] svnadmin setlog can be called in a way that bypasses the hook interface altogether.
[41] You know—the collective term for all of her “fickle fingers.â€
svnserve allows access to Subversion repositories using Subversion's custom network protocol.
You can run svnserve as a standalone
server process (for clients that are using the
svn://
access method); you can have a daemon
such as inetd or xinetd
launch it for you on demand (also for
svn://
), or you can have
sshd launch it on demand for the
svn+ssh://
access method.
Regardless of the access method, once the client has
selected a repository by transmitting its URL,
svnserve reads a file named
conf/svnserve.conf
in the repository
directory to determine repository-specific settings such as
what authentication database to use and what authorization
policies to apply. See the section called “svnserve, a Custom Server†for details of the
svnserve.conf
file.
Unlike the previous commands we've described, svnserve has no subcommands—it is controlled exclusively by options.
--daemon
(-d
)
Causes svnserve to run in daemon
mode. svnserve backgrounds itself
and accepts and serves TCP/IP connections on
the svn
port (3690, by
default).
--foreground
When used together with -d
,
causes svnserve to stay in the
foreground. This is mainly useful for debugging.
--inetd
(-i
)
Causes svnserve to use the
stdin
and stdout
file descriptors, as is appropriate for a
daemon running out of inetd.
--help
(-h
)
Displays a usage summary and exits.
--listen-host
HOST
Causes svnserve to listen on the
interface specified by HOST
,
which may be either a hostname or an IP address.
--listen-once
(-X
)
Causes svnserve to accept one
connection on the svn
port, serve it,
and exit. This option is mainly useful for
debugging.
--listen-port
PORT
Causes svnserve to listen on
PORT
when run in daemon mode.
(FreeBSD daemons listen only on tcp6 by default—this
option tells them to also listen on tcp4.)
--pid-file
FILENAME
Causes svnserve to write its
process ID to FILENAME
, which
must be writable by the user under
which svnserve is running.
--root
(-r
)
ROOT
Sets the virtual root for repositories served by svnserve. The pathname in URLs provided by the client will be interpreted relative to this root and will not be allowed to escape this root.
--threads
(-T
)
When running in daemon mode, causes svnserve to spawn a thread instead of a process for each connection (e.g., for when running on Windows). The svnserve process still backgrounds itself at startup time.
--tunnel
(-t
)
Causes svnserve to run in tunnel
mode, which is just like the inetd
mode of operation (both modes serve one connection over
stdin
/stdout
, and then exit), except that the connection
is considered to be preauthenticated with the username
of the current UID. This flag is automatically passed
for you by the client when running over a tunnel agent
such as ssh. That means there's
rarely any need for you to pass
this option to svnserve. So, if you
find yourself
typing svnserve --tunnel
on the
command line and wondering what to do next, see
the section called “Tunneling over SSHâ€.
--tunnel-user NAME
Used in conjunction with the --tunnel
option, tells svnserve to assume that
NAME
is the authenticated
user, rather than the UID of the svnserve
process. This is useful for users wishing to share a single
system account over SSH, but to maintain separate commit
identities.
--version
Displays version information and a list of repository backend modules available, and then exits.
Most of the time, you will start using a Subversion
repository by doing a checkout of your
project. Checking out a repository creates a “working
copy†of it on your local machine. This copy contains
the HEAD
(latest revision) of the Subversion
repository that you specify on the command line:
$ svn checkout http://svn.collab.net/repos/svn/trunk A trunk/Makefile.in A trunk/ac-helpers A trunk/ac-helpers/install.sh A trunk/ac-helpers/install-sh A trunk/build.conf … Checked out revision 8810.
Although the preceding example checks out the trunk directory, you can just as easily check out any deep subdirectory of a repository by specifying the subdirectory in the checkout URL:
$ svn checkout \ http://svn.collab.net/repos/svn/trunk/subversion/tests/cmdline/ A cmdline/revert_tests.py A cmdline/diff_tests.py A cmdline/autoprop_tests.py A cmdline/xmltests A cmdline/xmltests/svn-test.sh … Checked out revision 8810.
Since Subversion uses a copy-modify-merge model instead of lock-modify-unlock (see the section called “Versioning Modelsâ€), you can immediately make changes to the files and directories in your working copy. Your working copy is just like any other collection of files and directories on your system. You can edit and change it, move it around, even delete the entire working copy and forget about it.
Warning | |
---|---|
While your working copy is “just like any other collection of files and directories on your system,†you can edit files at will, but you must tell Subversion about everything else that you do. For example, if you want to copy or move an item in a working copy, you should use svn copy or svn move instead of the copy and move commands provided by your operating system. We'll talk more about them later in this chapter. |
Unless you're ready to commit the addition of a new file or directory or changes to existing ones, there's no need to further notify the Subversion server that you've done anything.
While you can certainly check out a working copy with the URL of the repository as the only argument, you can also specify a directory after your repository URL. This places your working copy in the new directory that you name. For example:
$ svn checkout http://svn.collab.net/repos/svn/trunk subv A subv/Makefile.in A subv/ac-helpers A subv/ac-helpers/install.sh A subv/ac-helpers/install-sh A subv/build.conf … Checked out revision 8810.
That will place your working copy in a directory named
subv
instead of a directory named
trunk
as we did previously. The directory
subv
will be created if it doesn't already
exist.
When you perform a Subversion operation that requires you to authenticate, by default Subversion tries to cache your authentication credentials on disk in encrypted form. On some systems, Subversion may be unable to encrypt your authentication data. You will then be asked whether you want to cache your credentials to disk in plaintext. You can choose to do so for convenience so that you don't have to continually reenter your password for future operations. If you're concerned about caching your Subversion passwords in plaintext and do not want to be asked about it again and again, you can disable caching of plaintext passwords either permanently, or on a server-per-server basis.
To permanently disable caching of passwords in plaintext,
you can add the line
store-plaintext-passwords = no
to the global section in the servers
configuration file on the local machine. To disable caching
of plaintext passwords for a particular server, use the same
setting in the appropriate group section in the
servers
configuration file.
See the section called “Configuration Optionsâ€
in Chapter 7, Customizing Your Subversion Experience for details.
You can also disable caching of authentication credentials entirely, regardless of whether the credentials are stored in encrypted form or not.
To disable password caching entirely for a particular one-time
command, pass the --no-auth-cache
option on
the command line. To permanently disable caching entirely,
you can add the line store-passwords = no
to your local machine's Subversion configuration file. See the section called “Client Credentials Caching†for
details.
Since Subversion caches auth credentials by default (both
username and password), it conveniently remembers who you were
acting as the last time you modified your working copy. But
sometimes that's not helpful—particularly if you're
working in a shared working copy such as a system
configuration directory or a web server document root. In this
case, just pass the --username
option on the
command line, and Subversion will attempt to authenticate as
that user, prompting you for a password if necessary.
svn update — Update your working copy.
svn update brings changes from the
repository into your working copy. If no revision is
given, it brings your working copy up to date with the
HEAD
revision. Otherwise, it
synchronizes the working copy to the revision given by the
--revision
(-r
) option.
As part of the synchronization, svn
update also removes any stale locks (see
the section called “Sometimes You Just Need to Clean Upâ€) found in the working
copy.
For each updated item, it prints a line that starts with a character reporting the action taken. These characters have the following meaning:
A
Added
B
Broken lock (third column only)
D
Deleted
U
Updated
C
Conflicted
G
Merged
E
Existed
A character in the first column signifies an update to the actual file, whereas updates to the file's properties are shown in the second column. Lock information is printed in the third column.
As with most subcommands, you can limit the scope of
the update operation to a particular tree depth using the
--depth
option. Alternatively, you can
use the --set-depth
option to set a new
“sticky†working copy depth on the update
target. Currently, the depth of a working copy directory
can only be increased (telescoped more deeply); you cannot
make a directory more shallow.
--accept ACTION --changelist --depth ARG --diff3-cmd CMD --editor-cmd CMD --force --ignore-externals --quiet (-q) --revision (-r) REV --set-depth ARG
Pick up repository changes that have happened since your last update:
$ svn update A newdir/toggle.c A newdir/disclose.c A newdir/launch.c D newdir/README Updated to revision 32.
You can also “update†your working copy to an older revision (Subversion doesn't have the concept of “sticky†files like CVS does; see Appendix B, Subversion for CVS Users):
$ svn update -r30 A newdir/README D newdir/toggle.c D newdir/disclose.c D newdir/launch.c U foo.c Updated to revision 30.
Tip | |
---|---|
If you want to examine an older revision of a single file, you may want to use svn cat instead—it won't change your working copy. |
Fortunately for Subversion users who routinely find themselves on different computers with different operating systems, Subversion's command-line program behaves almost identically on all those systems. If you know how to wield svn on one platform, you know how to wield it everywhere.
However, the same is not always true of other general classes of software or of the actual files you keep in Subversion. For example, on a Windows machine, the definition of a “text file†would be similar to that used on a Linux box, but with a key difference—the character sequences used to mark the ends of the lines of those files. There are other differences, too. Unix platforms have (and Subversion supports) symbolic links; Windows does not. Unix platforms use filesystem permission to determine executability; Windows uses filename extensions.
Because Subversion is in no position to unite the whole world in common definitions and implementations of all of these things, the best it can do is to try to help make your life simpler when you need to work with your versioned files and directories on multiple computers and operating systems. This section describes some of the ways Subversion does this.
Subversion joins the ranks of the many applications that
recognize and make use of Multipurpose Internet Mail
Extensions (MIME) content types. Besides being a
general-purpose storage location for a file's content type,
the value of the svn:mime-type
file
property determines some behavioral characteristics of
Subversion itself.
For example, one of the benefits that Subversion typically
provides is contextual, line-based merging of changes received
from the server during an update into your working file. But
for files containing nontextual data, there is often no
concept of a “line.†So, for versioned files
whose svn:mime-type
property is set to a
nontextual MIME type (generally, something that doesn't begin
with text/
, though there are exceptions),
Subversion does not attempt to perform contextual merges
during updates. Instead, any time you have locally modified a
binary working copy file that is also being updated, your file
is left untouched and Subversion creates two new files. One
file has a .oldrev
extension and contains
the BASE revision of the file. The other file has a
.newrev
extension and contains the
contents of the updated revision of the file. This behavior
is really for the protection of the user against failed
attempts at performing contextual merges on files that simply
cannot be contextually merged.
Warning | |
---|---|
The |
Beginning in Subversion 1.5, users can configure a new
mime-types-file
runtime configuration
parameter, which identifies the location of a MIME types
mapping file. Subversion will consult this mapping file to
determine the MIME type of newly added and imported
files.
Also, if the svn:mime-type
property is
set, then the Subversion Apache module will use its value to
populate the Content-type:
HTTP header when
responding to GET requests. This gives your web browser a
crucial clue about how to display a file when you use it to
peruse your Subversion repository's contents.
On many operating systems, the ability to execute a file
as a command is governed by the presence of an execute
permission bit. This bit usually defaults to being disabled,
and must be explicitly enabled by the user for each file that
needs it. But it would be a monumental hassle to have to
remember exactly which files in a freshly checked-out working
copy were supposed to have their executable bits toggled on,
and then to have to do that toggling. So, Subversion provides
the svn:executable
property as a way to
specify that the executable bit for the file on which that
property is set should be enabled, and Subversion honors that
request when populating working copies with such files.
This property has no effect on filesystems that have no
concept of an executable permission bit, such as FAT32 and
NTFS.
[11]
Also, although it has no defined values, Subversion will force
its value to *
when setting this property.
Finally, this property is valid only on files, not on
directories.
Unless otherwise noted using a versioned file's
svn:mime-type
property, Subversion
assumes the file contains human-readable data. Generally
speaking, Subversion uses this knowledge only to determine
whether contextual difference reports for that file are
possible. Otherwise, to Subversion, bytes are bytes.
This means that by default, Subversion doesn't pay any
attention to the type of end-of-line (EOL)
markers used in your files. Unfortunately,
different operating systems have different conventions about
which character sequences represent the end of a line of text
in a file. For example, the usual line-ending token used by
software on the Windows platform is a pair of ASCII control
characters—a carriage return (CR
)
followed by a line feed (LF
). Unix
software, however, just uses the LF
character to denote the end of a line.
Not all of the various tools on these operating systems
understand files that contain line endings in a format that
differs from the native line-ending
style of the operating system on which they are
running. So, typically, Unix programs treat the
CR
character present in Windows files as a
regular character (usually rendered as ^M
),
and Windows programs combine all of the lines of a Unix file
into one giant line because no carriage return-linefeed (or
CRLF
) character combination was found to
denote the ends of the lines.
This sensitivity to foreign EOL markers can be frustrating for folks who share a file across different operating systems. For example, consider a source code file, and developers that edit this file on both Windows and Unix systems. If all the developers always use tools that preserve the line-ending style of the file, no problems occur.
But in practice, many common tools either fail to properly read a file with foreign EOL markers, or convert the file's line endings to the native style when the file is saved. If the former is true for a developer, he has to use an external conversion utility (such as dos2unix or its companion, unix2dos) to prepare the file for editing. The latter case requires no extra preparation. But both cases result in a file that differs from the original quite literally on every line! Prior to committing his changes, the user has two choices. Either he can use a conversion utility to restore the modified file to the same line-ending style that it was in before his edits were made, or he can simply commit the file—new EOL markers and all.
The result of scenarios like these include wasted time and unnecessary modifications to committed files. Wasted time is painful enough. But when commits change every line in a file, this complicates the job of determining which of those lines were changed in a nontrivial way. Where was that bug really fixed? On what line was a syntax error introduced?
The solution to this problem is the
svn:eol-style
property. When this
property is set to a valid value, Subversion uses it to
determine what special processing to perform on the file so
that the file's line-ending style isn't flip-flopping with
every commit that comes from a different operating
system. The valid values are:
native
This causes the file to contain the EOL markers
that are native to the operating system on which
Subversion was run. In other words, if a user on a
Windows machine checks out a working copy that
contains a file with an
svn:eol-style
property set to
native
, that file will contain
CRLF
EOL markers. A Unix user
checking out a working copy that contains the same
file will see LF
EOL markers in his
copy of the file.
Note that Subversion will actually store the file
in the repository using normalized
LF
EOL markers regardless of the
operating system. This is basically transparent to
the user, though.
CRLF
This causes the file to contain
CRLF
sequences for EOL markers,
regardless of the operating system in use.
LF
This causes the file to contain
LF
characters for EOL markers,
regardless of the operating system in use.
CR
This causes the file to contain
CR
characters for EOL markers,
regardless of the operating system in use. This
line-ending style is not very common.
svn move — Move a file or directory.
This command moves files or directories in your working copy or in the repository.
Tip | |
---|---|
This command is equivalent to an svn copy followed by svn delete. |
When moving multiple sources, they will be added as
children of DST
, which must be
a directory.
Note | |
---|---|
Subversion does not support moving between working copies and URLs. In addition, you can only move files within a single repository—Subversion does not support cross-repository moving. Subversion supports the following types of moves within a single repository: |
Move and schedule a file or directory for addition (with history).
Complete server-side rename.
--editor-cmd CMD --encoding ENC --file (-F) FILENAME --force --force-log --message (-m) MESSAGE --parents --quiet (-q) --revision (-r) REV --with-revprop ARG
Move a file in your working copy:
$ svn move foo.c bar.c A bar.c D foo.c
Move several files in your working copy into a subdirectory:
$ svn move baz.c bat.c qux.c src A src/baz.c D baz.c A src/bat.c D bat.c A src/qux.c D qux.c
Move a file in the repository (this is an immediate commit, so it requires a commit message):
$ svn move -m "Move a file" http://svn.red-bean.com/repos/foo.c \ http://svn.red-bean.com/repos/bar.c Committed revision 27.
You've seen how a repository can be accessed in many different ways. But is it possible—or safe—for your repository to be accessed by multiple methods simultaneously? The answer is yes, provided you use a bit of foresight.
At any given time, these processes may require read and write access to your repository:
Regular system users using a Subversion client (as
themselves) to access the repository directly via
file://
URLs
Regular system users connecting to SSH-spawned private svnserve processes (running as themselves), which access the repository
An svnserve process—either a daemon or one launched by inetd—running as a particular fixed user
An Apache httpd process, running as a particular fixed user
The most common problem administrators run into is
repository ownership and permissions. Does every process (or
user) in the preceding list have the rights to read and write the
repository's underlying data files? Assuming you have a
Unix-like operating system, a straightforward approach might be
to place every potential repository user into a
new svn
group, and make the repository wholly
owned by that group. But even that's not enough, because a
process may write to the database files using an unfriendly
umask—one that prevents access by other users.
So the next step beyond setting up a common group for
repository users is to force every repository-accessing process
to use a sane umask. For users accessing the repository
directly, you can make the svn program into a
wrapper script that first runs umask 002
and
then runs the real svn client program. You
can write a similar wrapper script for the
svnserve program, and add a umask
002
command to Apache's own startup script,
apachectl
. For example:
$ cat /usr/bin/svn #!/bin/sh umask 002 /usr/bin/svn-real "$@"
Another common problem is often encountered on Unix-like
systems. If your repository is backed by Berkeley DB, for
example, it occasionally creates new log files to journal its
actions. Even if the Berkeley DB repository is wholly owned by
the svn group, these newly created log files
won't necessarily be owned by that same group, which then
creates more permissions problems for your users. A good
workaround is to set the group SUID bit on the
repository's db
directory. This causes all
newly created log files to have the same group owner as the
parent directory.
Once you've jumped through these hoops, your repository should be accessible by all the necessary processes. It may seem a bit messy and complicated, but the problems of having multiple users sharing write access to common files are classic ones that are not often elegantly solved.
Fortunately, most repository administrators will never
need to have such a complex configuration.
Users who wish to access repositories that live on the same
machine are not limited to using file://
access URLs—they can typically contact the Apache HTTP
server or svnserve using
localhost
for the server name in their
http://
or svn://
URL.
And maintaining multiple server processes for your Subversion
repositories is likely to be more of a headache than necessary.
We recommend that you choose a single server that best meets your
needs and stick with it!
svn propdel — Remove a property from an item.
While the Subversion client is not a full DeltaV client, and the Subversion server is not a full DeltaV server, there's still a glimmer of WebDAV interoperability to be happy about: autoversioning.
Autoversioning is an optional feature defined in the DeltaV
standard. A typical DeltaV server will reject an ignorant
WebDAV client attempting to do a PUT
to a
file that's under version control. To change a
version-controlled file, the server expects a series of proper
versioning requests: something like
MKACTIVITY
, CHECKOUT
,
PUT
, CHECKIN
. But if the
DeltaV server supports autoversioning, write requests from
basic WebDAV clients are accepted. The server behaves as though the
client had issued the proper series of
versioning requests, performing a commit under the hood. In
other words, it allows a DeltaV server to interoperate with
ordinary WebDAV clients that don't understand versioning.
Because so many operating systems already have integrated WebDAV clients, the use case for this feature can be incredibly appealing to administrators working with non-technical users. Imagine an office of ordinary users running Microsoft Windows or Mac OS. Each user “mounts†the Subversion repository, which appears to be an ordinary network folder. They use the shared folder as they always do: open files, edit them, and save them. Meanwhile, the server is automatically versioning everything. Any administrator (or knowledgeable user) can still use a Subversion client to search history and retrieve older versions of data.
This scenario isn't fiction—it's real and it works, as
of Subversion 1.2 and later. To activate autoversioning in
mod_dav_svn, use the
SVNAutoversioning
directive within the
httpd.conf
Location
block, like so:
<Location /repos> DAV svn SVNPath /var/svn/repository SVNAutoversioning on </Location>
When Subversion autoversioning is active, write requests from WebDAV clients result in automatic commits. A generic log message is automatically generated and attached to each revision.
Before activating this feature, however, understand what
you're getting into. WebDAV clients tend to do
many write requests, resulting in a huge
number of automatically committed revisions. For example, when
saving data, many clients will do a PUT
of a
0-byte file (as a way of reserving a name) followed by another
PUT
with the real file data. The single
file-write results in two separate commits. Also consider that
many applications auto-save every few minutes, resulting in even
more commits.
If you have a post-commit hook program that sends email, you
may want to disable email generation either altogether or on
certain sections of the repository; it depends on whether you
think the influx of emails will still prove to be valuable
notifications or not. Also, a smart post-commit hook program
can distinguish between a transaction created via autoversioning
and one created through a normal Subversion commit operation.
The trick is to look for a revision property
named svn:autoversioned
. If present, the
commit was made by a generic WebDAV client.
Another feature that may be a useful complement for
Subversion's autoversioning comes from Apache's
mod_mime
module. If a WebDAV client adds a
new file to the repository, there's no opportunity for the user
to set the the svn:mime-type
property. This
might cause the file to appear as a generic icon when viewed
within a WebDAV shared folder, not having an association with
any application. One remedy is to have a sysadmin (or other
Subversion-knowledgeable person) check out a working copy and
manually set the svn:mime-type
property on
necessary files. But there's potentially no end to such cleanup
tasks. Instead, you can use the
ModMimeUsePathInfo
directive in your
Subversion <Location>
block:
<Location /repos> DAV svn SVNPath /var/svn/repository SVNAutoversioning on ModMimeUsePathInfo on </Location>
This directive allows mod_mime
to attempt
automatic deduction of the MIME type on new files that enter the
repository via autoversioning. The module looks at the file's
named extension and possibly the contents as well; if the file
matches some common patterns, the
file's svn:mime-type
property will be set
automatically.
Table of Contents
The Subversion repository is the central storehouse of all your versioned data. As such, it becomes an obvious candidate for all the love and attention an administrator can offer. While the repository is generally a low-maintenance item, it is important to understand how to properly configure and care for it so that potential problems are avoided, and so actual problems are safely resolved.
In this chapter, we'll discuss how to create and configure a Subversion repository. We'll also talk about repository maintenance, providing examples of how and when to use the svnlook and svnadmin tools provided with Subversion. We'll address some common questions and mistakes and give some suggestions on how to arrange the data in the repository.
If you plan to access a Subversion repository only in the role of a user whose data is under version control (i.e., via a Subversion client), you can skip this chapter altogether. However, if you are, or wish to become, a Subversion repository administrator, [27] this chapter is for you.
[27] This may sound really prestigious and lofty, but we're just talking about anyone who is interested in that mysterious realm beyond the working copy where everyone's data hangs out.
Localization is the act of making programs behave in a region-specific way. When a program formats numbers or dates in a way specific to your part of the world or prints messages (or accepts input) in your native language, the program is said to be localized. This section describes steps Subversion has made toward localization.
Most modern operating systems have a notion of the “current localeâ€â€”that is, the region or country whose localization conventions are honored. These conventions—typically chosen by some runtime configuration mechanism on the computer—affect the way in which programs present data to the user, as well as the way in which they accept user input.
On most Unix-like systems, you can check the values of the locale-related runtime configuration options by running the locale command:
$ locale LANG= LC_COLLATE="C" LC_CTYPE="C" LC_MESSAGES="C" LC_MONETARY="C" LC_NUMERIC="C" LC_TIME="C" LC_ALL="C" $
The output is a list of locale-related environment
variables and their current values. In this example, the
variables are all set to the default C
locale, but users can set these variables to specific
country/language code combinations. For example, if one were
to set the LC_TIME
variable to
fr_CA
, programs would know to present
time and date information formatted according to a
French-speaking Canadian's expectations. And if one were to
set the LC_MESSAGES
variable to
zh_TW
, programs would know to present
human-readable messages in Traditional Chinese. Setting the
LC_ALL
variable has the effect of changing
every locale variable to the same value. The value of
LANG
is used as a default value for any
locale variable that is unset. To see the list of available
locales on a Unix system, run the command locale
-a
.
On Windows, locale configuration is done via the “Regional and Language Options†control panel item. There you can view and select the values of individual settings from the available locales, and even customize (at a sickening level of detail) several of the display formatting conventions.
The Subversion client, svn, honors the
current locale configuration in two ways. First, it notices
the value of the LC_MESSAGES
variable and
attempts to print all messages in the specified language. For
example:
$ export LC_MESSAGES=de_DE $ svn help cat cat: Gibt den Inhalt der angegebenen Dateien oder URLs aus. Aufruf: cat ZIEL[@REV]... …
This behavior works identically on both Unix and Windows
systems. Note, though, that while your operating system might
have support for a certain locale, the Subversion client still
may not be able to speak the particular language. In order to
produce localized messages, human volunteers must provide
translations for each language. The translations are written
using the GNU gettext package, which results in translation
modules that end with the .mo
filename
extension. For example, the German translation file is named
de.mo
. These translation files are
installed somewhere on your system. On Unix, they typically
live in /usr/share/locale/
, while
on Windows they're often found in the
share\locale\
folder in Subversion's
installation area. Once installed, a module is named after
the program for which it provides translations. For example, the
de.mo
file may ultimately end up
installed as
/usr/share/locale/de/LC_MESSAGES/subversion.mo
.
By browsing the installed .mo
files, you
can see which languages the Subversion client is able to
speak.
The second way in which the locale is honored involves how svn interprets your input. The repository stores all paths, filenames, and log messages in Unicode, encoded as UTF-8. In that sense, the repository is internationalized—that is, the repository is ready to accept input in any human language. This means, however, that the Subversion client is responsible for sending only UTF-8 filenames and log messages into the repository. To do this, it must convert the data from the native locale into UTF-8.
For example, suppose you create a file named
caffè.txt
, and then when committing the
file, you write the log message as “Adesso il caffè è
più forte.†Both the filename and the log message contain
non-ASCII characters, but because your locale is set to
it_IT
, the Subversion client knows to
interpret them as Italian. It uses an Italian character set
to convert the data to UTF-8 before sending it off to the
repository.
Note that while the repository demands UTF-8 filenames and log messages, it does not pay attention to file contents. Subversion treats file contents as opaque strings of bytes, and neither client nor server makes an attempt to understand the character set or encoding of the contents.
Table of Contents
 |
“It is important not to let the perfect become the enemy of the good, even when you can agree on what perfect is. Doubly so when you can't. As unpleasant as it is to be trapped by past mistakes, you can't make any progress by being afraid of your own shadow during design.†|
 |
 | --Greg Hudson, Subversion developer |
In the world of open source software, the Concurrent Versions System (CVS) was the tool of choice for version control for many years. And rightly so. CVS was open source software itself, and its nonrestrictive modus operandi and support for networked operation allowed dozens of geographically dispersed programmers to share their work. It fit the collaborative nature of the open source world very well. CVS and its semi-chaotic development model have since become cornerstones of open source culture.
But CVS was not without its flaws, and simply fixing those flaws promised to be an enormous effort. Enter Subversion. Subversion was designed to be a successor to CVS, and its originators set out to win the hearts of CVS users in two ways—by creating an open source system with a design (and “look and feelâ€) similar to CVS, and by attempting to avoid most of CVS's noticeable flaws. While the result isn't necessarily the next great evolution in version control design, Subversion is very powerful, very usable, and very flexible. And for the most part, almost all newly started open source projects now choose Subversion instead of CVS.
This book is written to document the 1.6 series of the Subversion version control system. We have made every attempt to be thorough in our coverage. However, Subversion has a thriving and energetic development community, so already a number of features and improvements are planned for future versions that may change some of the commands and specific notes in this book.
The core mission of a version control system is to enable collaborative editing and sharing of data. But different systems use different strategies to achieve this. It's important to understand these different strategies, for a couple of reasons. First, it will help you compare and contrast existing version control systems, in case you encounter other systems similar to Subversion. Beyond that, it will also help you make more effective use of Subversion, since Subversion itself supports a couple of different ways of working.
All version control systems have to solve the same fundamental problem: how will the system allow users to share information, but prevent them from accidentally stepping on each other's feet? It's all too easy for users to accidentally overwrite each other's changes in the repository.
Consider the scenario shown in Figure 1.2, “The problem to avoidâ€. Suppose we have two coworkers, Harry and Sally. They each decide to edit the same repository file at the same time. If Harry saves his changes to the repository first, it's possible that (a few moments later) Sally could accidentally overwrite them with her own new version of the file. While Harry's version of the file won't be lost forever (because the system remembers every change), any changes Harry made won't be present in Sally's newer version of the file, because she never saw Harry's changes to begin with. Harry's work is still effectively lost—or at least missing from the latest version of the file—and probably by accident. This is definitely a situation we want to avoid!
Many version control systems use a lock-modify-unlock model to address the problem of many authors clobbering each other's work. In this model, the repository allows only one person to change a file at a time. This exclusivity policy is managed using locks. Harry must “lock†a file before he can begin making changes to it. If Harry has locked a file, Sally cannot also lock it, and therefore cannot make any changes to that file. All she can do is read the file and wait for Harry to finish his changes and release his lock. After Harry unlocks the file, Sally can take her turn by locking and editing the file. Figure 1.3, “The lock-modify-unlock solution†demonstrates this simple solution.
The problem with the lock-modify-unlock model is that it's a bit restrictive and often becomes a roadblock for users:
Locking may cause administrative problems. Sometimes Harry will lock a file and then forget about it. Meanwhile, because Sally is still waiting to edit the file, her hands are tied. And then Harry goes on vacation. Now Sally has to get an administrator to release Harry's lock. The situation ends up causing a lot of unnecessary delay and wasted time.
Locking may cause unnecessary serialization. What if Harry is editing the beginning of a text file, and Sally simply wants to edit the end of the same file? These changes don't overlap at all. They could easily edit the file simultaneously, and no great harm would come, assuming the changes were properly merged together. There's no need for them to take turns in this situation.
Locking may create a false sense of security. Suppose Harry locks and edits file A, while Sally simultaneously locks and edits file B. But what if A and B depend on one another, and the changes made to each are semantically incompatible? Suddenly A and B don't work together anymore. The locking system was powerless to prevent the problem—yet it somehow provided a false sense of security. It's easy for Harry and Sally to imagine that by locking files, each is beginning a safe, insulated task, and thus they need not bother discussing their incompatible changes early on. Locking often becomes a substitute for real communication.
Subversion, CVS, and many other version control systems use a copy-modify-merge model as an alternative to locking. In this model, each user's client contacts the project repository and creates a personal working copy—a local reflection of the repository's files and directories. Users then work simultaneously and independently, modifying their private copies. Finally, the private copies are merged together into a new, final version. The version control system often assists with the merging, but ultimately, a human being is responsible for making it happen correctly.
Here's an example. Say that Harry and Sally each create working copies of the same project, copied from the repository. They work concurrently and make changes to the same file A within their copies. Sally saves her changes to the repository first. When Harry attempts to save his changes later, the repository informs him that his file A is out of date. In other words, file A in the repository has somehow changed since he last copied it. So Harry asks his client to merge any new changes from the repository into his working copy of file A. Chances are that Sally's changes don't overlap with his own; once he has both sets of changes integrated, he saves his working copy back to the repository. Figure 1.4, “The copy-modify-merge solution†and Figure 1.5, “The copy-modify-merge solution (continued)†show this process.
But what if Sally's changes do overlap with Harry's changes? What then? This situation is called a conflict, and it's usually not much of a problem. When Harry asks his client to merge the latest repository changes into his working copy, his copy of file A is somehow flagged as being in a state of conflict: he'll be able to see both sets of conflicting changes and manually choose between them. Note that software can't automatically resolve conflicts; only humans are capable of understanding and making the necessary intelligent choices. Once Harry has manually resolved the overlapping changes—perhaps after a discussion with Sally—he can safely save the merged file back to the repository.
The copy-modify-merge model may sound a bit chaotic, but in practice, it runs extremely smoothly. Users can work in parallel, never waiting for one another. When they work on the same files, it turns out that most of their concurrent changes don't overlap at all; conflicts are infrequent. And the amount of time it takes to resolve conflicts is usually far less than the time lost by a locking system.
In the end, it all comes down to one critical factor: user communication. When users communicate poorly, both syntactic and semantic conflicts increase. No system can force users to communicate perfectly, and no system can detect semantic conflicts. So there's no point in being lulled into a false sense of security that a locking system will somehow prevent conflicts; in practice, locking seems to inhibit productivity more than anything else.
It's time to move from the abstract to the concrete. In this section, we'll show real examples of Subversion being used.
Throughout this book, Subversion uses URLs to identify versioned files and directories in Subversion repositories. For the most part, these URLs use the standard syntax, allowing for server names and port numbers to be specified as part of the URL:
$ svn checkout http://svn.example.com:9834/repos …
But there are some nuances in Subversion's handling of URLs
that are notable. For example, URLs containing the
file://
access method (used for local
repositories) must, in accordance with convention, have either a
server name of localhost
or no server name at
all:
$ svn checkout file:///var/svn/repos … $ svn checkout file://localhost/var/svn/repos …
Also, users of the file://
scheme on
Windows platforms will need to use an unofficially
“standard†syntax for accessing repositories
that are on the same machine, but on a different drive than
the client's current working drive. Either of the two
following URL path syntaxes will work, where
X
is the drive on which the repository
resides:
C:\> svn checkout file:///X:/var/svn/repos … C:\> svn checkout "file:///X|/var/svn/repos" …
In the second syntax, you need to quote the URL so that the vertical bar character is not interpreted as a pipe. Also, note that a URL uses forward slashes even though the native (non-URL) form of a path on Windows uses backslashes.
Note | |
---|---|
You cannot use Subversion's |
The Subversion client will automatically encode URLs as necessary, just like a web browser does. For example, if a URL contains a space or upper-ASCII character as in the following:
$ svn checkout "http://host/path with space/project/españa"
then Subversion will escape the unsafe characters and behave as though you had typed:
$ svn checkout http://host/path%20with%20space/project/espa%C3%B1a
If the URL contains spaces, be sure to place it within quotation marks so that your shell treats the whole thing as a single argument to the svn program.
In Subversion 1.6, a new caret (^
)
notation was introduced as a shorthand for “the URL of
the repository's root directoryâ€. For example:
$ svn list ^/tags/bigsandwich/
In this example, we're specifying a URL for
the /tags/bigsandwich
directory in the
root of the repository. Note that this URL
syntax only works when your current
working directory is a working copy—the commandline
client knows the repository's root URL by looking at the
working copy's metadata.
You've already read about working copies; now we'll demonstrate how the Subversion client creates and uses them.
A Subversion working copy is an ordinary directory tree on your local system, containing a collection of files. You can edit these files however you wish, and if they're source code files, you can compile your program from them in the usual way. Your working copy is your own private work area: Subversion will never incorporate other people's changes, nor make your own changes available to others, until you explicitly tell it to do so. You can even have multiple working copies of the same project.
After you've made some changes to the files in your working copy and verified that they work properly, Subversion provides you with commands to “publish†your changes to the other people working with you on your project (by writing to the repository). If other people publish their own changes, Subversion provides you with commands to merge those changes into your working copy (by reading from the repository).
A working copy also contains some extra files, created and
maintained by Subversion, to help it carry out these commands.
In particular, each directory in your working copy contains a
subdirectory named .svn
, also known as
the working copy's administrative
directory. The files in each administrative
directory help Subversion recognize which files contain
unpublished changes, and which files are out of date with
respect to others' work.
A typical Subversion repository often holds the files (or source code) for several projects; usually, each project is a subdirectory in the repository's filesystem tree. In this arrangement, a user's working copy will usually correspond to a particular subtree of the repository.
For example, suppose you have a repository that contains
two software projects, paint
and
calc
. Each project lives in its own
top-level subdirectory, as shown in Figure 1.6, “The repository's filesystemâ€.
To get a working copy, you must check
out some subtree of the repository. (The term
check out may sound like it has something to do
with locking or reserving resources, but it doesn't; it simply
creates a private copy of the project for you.) For example,
if you check out /calc
, you will get a
working copy like this:
$ svn checkout http://svn.example.com/repos/calc A calc/Makefile A calc/integer.c A calc/button.c Checked out revision 56. $ ls -A calc Makefile button.c integer.c .svn/
The list of letter A
s in the left
margin indicates that Subversion is adding a number of items
to your working copy. You now have a personal copy of the
repository's /calc
directory, with one
additional entry—.svn
—which
holds the extra information needed by Subversion, as mentioned
earlier.
Suppose you make changes to button.c
.
Since the .svn
directory remembers the
file's original modification date and contents, Subversion can
tell that you've changed the file. However, Subversion does
not make your changes public until you explicitly tell it to.
The act of publishing your changes is more commonly known as
committing (or checking
in) changes to the repository.
To publish your changes to others, you can use Subversion's svn commit command:
$ svn commit button.c -m "Fixed a typo in button.c." Sending button.c Transmitting file data . Committed revision 57.
Now your changes to button.c
have
been committed to the repository, with a note describing your
change (namely, that you fixed a typo). If another user
checks out a working copy of /calc
, she
will see your changes in the latest version of the
file.
Suppose you have a collaborator, Sally, who checked out a
working copy of /calc
at the same time
you did. When you commit your change to
button.c
, Sally's working copy is left
unchanged; Subversion modifies working copies only at the
user's request.
To bring her project up to date, Sally can ask Subversion to update her working copy, by using the svn update command. This will incorporate your changes into her working copy, as well as any others that have been committed since she checked it out.
$ pwd /home/sally/calc $ ls -A Makefile button.c integer.c .svn/ $ svn update U button.c Updated to revision 57.
The output from the svn update command
indicates that Subversion updated the contents of
button.c
. Note that Sally didn't need to
specify which files to update; Subversion uses the information
in the .svn
directory as well as further
information in the repository, to decide which files need to
be brought up to date.
An svn commit operation publishes changes to any number of files and directories as a single atomic transaction. In your working copy, you can change files' contents; create, delete, rename, and copy files and directories; and then commit a complete set of changes as an atomic transaction.
By atomic transaction, we mean simply this: either all of the changes happen in the repository, or none of them happens. Subversion tries to retain this atomicity in the face of program crashes, system crashes, network problems, and other users' actions.
Each time the repository accepts a commit, this creates a new state of the filesystem tree, called a revision. Each revision is assigned a unique natural number, one greater than the number of the previous revision. The initial revision of a freshly created repository is numbered 0 and consists of nothing but an empty root directory.
Figure 1.7, “The repository†illustrates a nice way to visualize the repository. Imagine an array of revision numbers, starting at 0, stretching from left to right. Each revision number has a filesystem tree hanging below it, and each tree is a “snapshot†of the way the repository looked after a commit.
It's important to note that working copies do not always correspond to any single revision in the repository; they may contain files from several different revisions. For example, suppose you check out a working copy from a repository whose most recent revision is 4:
calc/Makefile:4 integer.c:4 button.c:4
At the moment, this working directory corresponds exactly
to revision 4 in the repository. However, suppose you make a
change to button.c
, and commit that
change. Assuming no other commits have taken place, your
commit will create revision 5 of the repository, and your
working copy will now look like this:
calc/Makefile:4 integer.c:4 button.c:5
Suppose that, at this point, Sally commits a change to
integer.c
, creating revision 6. If you
use svn update to bring your working copy
up to date, it will look like this:
calc/Makefile:6 integer.c:6 button.c:6
Sally's change to integer.c
will
appear in your working copy, and your change will still be
present in button.c
. In this example,
the text of Makefile
is identical in
revisions 4, 5, and 6, but Subversion will mark your working
copy of Makefile
with revision 6 to
indicate that it is still current. So, after you do a clean
update at the top of your working copy, it will generally
correspond to exactly one revision in the repository.
For each file in a working directory, Subversion records
two essential pieces of information in the
.svn/
administrative area:
What revision your working file is based on (this is called the file's working revision)
A timestamp recording when the local copy was last updated by the repository
Given this information, by talking to the repository, Subversion can tell which of the following four states a working file is in:
The file is unchanged in the working directory, and no changes to that file have been committed to the repository since its working revision. An svn commit of the file will do nothing, and an svn update of the file will do nothing.
The file has been changed in the working directory, and no changes to that file have been committed to the repository since you last updated. There are local changes that have not been committed to the repository; thus an svn commit of the file will succeed in publishing your changes, and an svn update of the file will do nothing.
The file has not been changed in the working directory, but it has been changed in the repository. The file should eventually be updated in order to make it current with the latest public revision. An svn commit of the file will do nothing, and an svn update of the file will fold the latest changes into your working copy.
The file has been changed both in the working directory and in the repository. An svn commit of the file will fail with an “out-of-date†error. The file should be updated first; an svn update command will attempt to merge the public changes with the local changes. If Subversion can't complete the merge in a plausible way automatically, it leaves it to the user to resolve the conflict.
This may sound like a lot to keep track of, but the svn status command will show you the state of any item in your working copy. For more information on that command, see the section called “See an overview of your changesâ€.
As a general principle, Subversion tries to be as flexible as possible. One special kind of flexibility is the ability to have a working copy containing files and directories with a mix of different working revision numbers. Unfortunately, this flexibility tends to confuse a number of new users. If the earlier example showing mixed revisions perplexed you, here's a primer on why the feature exists and how to make use of it.
One of the fundamental rules of Subversion is that a “push†action does not cause a “pull,†nor vice versa. Just because you're ready to submit new changes to the repository doesn't mean you're ready to receive changes from other people. And if you have new changes still in progress, svn update should gracefully merge repository changes into your own, rather than forcing you to publish them.
The main side effect of this rule is that it means a working copy has to do extra bookkeeping to track mixed revisions as well as be tolerant of the mixture. It's made more complicated by the fact that directories themselves are versioned.
For example, suppose you have a working copy entirely at
revision 10. You edit the
file foo.html
and then perform
an svn commit, which creates revision 15
in the repository. After the commit succeeds, many new
users would expect the working copy to be entirely at
revision 15, but that's not the case! Any number of changes
might have happened in the repository between revisions 10
and 15. The client knows nothing of those changes in the
repository, since you haven't yet run svn
update, and svn commit doesn't
pull down new changes. If, on the other hand,
svn commit were to automatically download
the newest changes, it would be possible to set the
entire working copy to revision 15—but then we'd be
breaking the fundamental rule of “pushâ€
and “pull†remaining separate actions.
Therefore, the only safe thing the Subversion client can do
is mark the one
file—foo.html
—as being at
revision 15. The rest of the working copy remains at
revision 10. Only by running svn update
can the latest changes be downloaded and the whole working
copy be marked as revision 15.
The fact is, every time you run
svn commit your working copy ends up
with some mixture of revisions. The things you just
committed are marked as having larger working revisions than
everything else. After several commits (with no updates
in between), your working copy will contain a whole mixture
of revisions. Even if you're the only person using the
repository, you will still see this phenomenon. To examine
your mixture of working revisions, use the svn
status command with the --verbose
(-v
) option (see
the section called “See an overview of your changes†for more
information).
Often, new users are completely unaware that their working copy contains mixed revisions. This can be confusing, because many client commands are sensitive to the working revision of the item they're examining. For example, the svn log command is used to display the history of changes to a file or directory (see the section called “Generating a List of Historical Changesâ€). When the user invokes this command on a working copy object, he expects to see the entire history of the object. But if the object's working revision is quite old (often because svn update hasn't been run in a long time), the history of the older version of the object is shown.
If your project is sufficiently complex, you'll discover that it's sometimes nice to forcibly backdate (or update to a revision older than the one you already have) portions of your working copy to an earlier revision; you'll learn how to do that in Chapter 2, Basic Usage. Perhaps you'd like to test an earlier version of a submodule contained in a subdirectory, or perhaps you'd like to figure out when a bug first came into existence in a specific file. This is the “time machine†aspect of a version control system—the feature that allows you to move any portion of your working copy forward and backward in history.
However you make use of mixed revisions in your working copy, there are limitations to this flexibility.
First, you cannot commit the deletion of a file or directory that isn't fully up to date. If a newer version of the item exists in the repository, your attempt to delete will be rejected to prevent you from accidentally destroying changes you've not yet seen.
Second, you cannot commit a metadata change to a directory unless it's fully up to date. You'll learn about attaching “properties†to items in Chapter 3, Advanced Topics. A directory's working revision defines a specific set of entries and properties, and thus committing a property change to an out-of-date directory may destroy properties you've not yet seen.
svn status — Print the status of working copy files and directories.
Print the status of working copy files and
directories. With no arguments, it prints only locally
modified items (no repository access). With
--show-updates
(-u
), it
adds working revision and server out-of-date information.
With --verbose
(-v
), it
prints full revision information on every item.
With --quiet
(-q
), it
prints only summary information about locally modified
items.
The first seven columns in the output are each one character wide, and each column gives you information about a different aspect of each working copy item.
The first column indicates that an item was added, deleted, or otherwise changed:
' '
No modifications.
'A'
Item is scheduled for addition.
'D'
Item is scheduled for deletion.
'M'
Item has been modified.
'R'
Item has been replaced in your working copy. This means the file was scheduled for deletion, and then a new file with the same name was scheduled for addition in its place.
'C'
The contents (as opposed to the properties) of the item conflict with updates received from the repository.
'X'
Item is present because of an externals definition.
'I'
Item is being ignored (e.g., with the
svn:ignore
property).
'?'
Item is not under version control.
'!'
Item is missing (e.g., you moved or deleted it without using svn). This also indicates that a directory is incomplete (a checkout or update was interrupted).
'~'
Item is versioned as one kind of object (file, directory, link), but has been replaced by a different kind of object.
The second column tells the status of a file's or directory's properties:
' '
No modifications.
'M'
Properties for this item have been modified.
'C'
Properties for this item are in conflict with property updates received from the repository.
The third column is populated only if the working copy directory is locked (see the section called “Sometimes You Just Need to Clean Upâ€):
' '
Item is not locked.
'L'
Item is locked.
The fourth column is populated only if the item is scheduled for addition-with-history:
' '
No history scheduled with commit.
'+'
History scheduled with commit.
The fifth column is populated only if the item is switched relative to its parent (see the section called “Traversing Branchesâ€):
' '
Item is a child of its parent directory.
'S'
Item is switched.
The sixth column is populated with lock information:
' '
When --show-updates
(-u
) is used, the file is not
locked. If --show-updates
(-u
) is not
used, this merely means that the file is not locked
in this working copy.
File is locked in this working copy.
File is locked either by another user or in
another working copy. This appears only when
--show-updates
(-u
) is used.
File was locked in this working copy, but the
lock has been “stolen†and is invalid.
The file is currently locked in the repository. This
appears only when --show-updates
(-u
) is used.
File was locked in this working copy, but the
lock has been “broken†and is invalid.
The file is no longer locked. This appears only
when --show-updates
(-u
) is used.
The seventh column is populated only if the item is the victim of a tree conflict:
' '
Item is not the victim of a tree conflict.
'C'
Item is the victim of a tree conflict.
The eighth column is always blank.
The out-of-date information appears in the ninth
column (only if you pass the
--show-updates
(-u
)
option):
' '
The item in your working copy is up to date.
'*'
A newer revision of the item exists on the server.
The remaining fields are variable width and delimited
by spaces. The working revision is the next field if
the --show-updates
(-u
)
or --verbose
(-v
) option
is passed.
If the --verbose
(-v
) option is passed, the last committed
revision and last committed author are displayed
next.
The working copy path is always the final field, so it can include spaces.
--changelist ARG --depth ARG --ignore-externals --incremental --no-ignore --quiet (-q) --show-updates (-u) --verbose (-v) --xml
This is the easiest way to find out what changes you have made to your working copy:
$ svn status wc M wc/bar.c A + wc/qax.c
If you want to find out what files in your working
copy are out of date, pass
the --show-updates
(-u
)
option (this will not make any
changes to your working copy). Here you can see that
wc/foo.c
has changed in the
repository since we last updated our working
copy:
$ svn status -u wc M 965 wc/bar.c * 965 wc/foo.c A + 965 wc/qax.c Status against revision: 981
Note | |
---|---|
|
The most information you can get out of the status subcommand is as follows:
$ svn status -u -v wc M 965 938 sally wc/bar.c * 965 922 harry wc/foo.c A + 965 687 harry wc/qax.c 965 687 harry wc/zig.c Status against revision: 981
Lastly, you can get svn status
output in XML format with the --xml
option:
$ svn status --xml wc <?xml version="1.0"?> <status> <target path="wc"> <entry path="qax.c"> <wc-status props="none" item="added" revision="0"> </wc-status> </entry> <entry path="bar.c"> <wc-status props="normal" item="modified" revision="965"> <commit revision="965"> <author>sally</author> <date>2008-05-28T06:35:53.048870Z</date> </commit> </wc-status> </entry> </target> </status>
For many more examples of svn status, see the section called “See an overview of your changesâ€.
svn cleanup — Recursively clean up the working copy
Recursively clean up the working copy, removing
working copy locks and resuming unfinished operations. If
you ever get a working copy locked
error, run this command to remove stale locks and get your
working copy into a usable state again.
If, for some reason, an svn update
fails due to a problem running an external diff program
(e.g., user input or network failure), pass the
--diff3-cmd
to allow cleanup to complete
any merging with your external diff program. You can also
specify any configuration directory with the
--config-dir
option, but you should need
these options extremely infrequently.
post-lock — Notification of a successful path lock.
The post-lock
hook runs after one or
more paths have been locked. It is typically used to send
email notification of the lock event.
If the post-lock
hook returns a
nonzero exit status, the lock will
not be aborted since it has already
completed. However, anything that the hook printed
to stderr
will be marshalled back to the
client, making it easier to diagnose hook failures.
svnadmin dump — Dump the contents of the filesystem to stdout
.
Dump the contents of the filesystem to stdout
in a
“dump file†portable format, sending feedback
to stderr
. Dump revisions
LOWER
rev through
UPPER
rev. If no revisions are
given, dump all revision trees. If only
LOWER
is given, dump that one
revision tree. See the section called “Migrating Repository Data Elsewhereâ€
for a practical use.
By default, the Subversion dump stream contains a single revision (the first revision in the requested revision range) in which every file and directory in the repository in that revision is presented as though that whole tree was added at once, followed by other revisions (the remainder of the revisions in the requested range), which contain only the files and directories that were modified in those revisions. For a modified file, the complete full-text representation of its contents, as well as all of its properties, are presented in the dump file; for a directory, all of its properties are presented.
Two useful options modify the dump file
generator's behavior. The first is the
--incremental
option, which simply causes
that first revision in the dump stream to contain only
the files and directories modified in that revision,
instead of being presented as the addition of a new tree,
and in exactly the same way that every other revision in
the dump file is presented. This is useful for generating
a relatively small dump file to be loaded into another
repository that already has the files and directories
that exist in the original repository.
The second useful option is --deltas
.
This option causes svnadmin dump to,
instead of emitting full-text representations of file
contents and property lists, emit only deltas of those
items against their previous versions. This reduces (in
some cases, drastically) the size of the dump file that
svnadmin dump creates. There are, however,
disadvantages to using this option—deltified
dump files are more CPU-intensive to create, cannot be
operated on by svndumpfilter, and tend
not to compress as well as their nondeltified counterparts
when using third-party tools such as gzip
and bzip2.
Table of Contents
A Subversion repository can be accessed simultaneously by
clients running on the same machine on which the repository
resides using the file://
method. But the
typical Subversion setup involves a single server machine being
accessed from clients on computers all over the office—or,
perhaps, all over the world.
This chapter describes how to get your Subversion repository exposed outside its host machine for use by remote clients. We will cover Subversion's currently available server mechanisms, discussing the configuration and use of each. After reading this chapter, you should be able to decide which networking setup is right for your needs, as well as understand how to enable such a setup on your host computer.
Copyright (c) 2002-2009 Ben Collins-Sussman, Brian W. Fitzpatrick, C. Michael Pilato. This work is licensed under the Creative Commons Attribution License. To view a copy of this license, visit http://creativecommons.org/licenses/by/2.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA. A summary of the license is given below, followed by the full legal text. -------------------------------------------------------------------- You are free: * to copy, distribute, display, and perform the work * to make derivative works * to make commercial use of the work Under the following conditions: Attribution. You must give the original author credit. * For any reuse or distribution, you must make clear to others the license terms of this work. * Any of these conditions can be waived if you get permission from the author. Your fair use and other rights are in no way affected by the above. The above is a summary of the full license below. ==================================================================== Creative Commons Legal Code Attribution 2.0 CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. License THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS. 1. Definitions a. "Collective Work" means a work, such as a periodical issue, anthology or encyclopedia, in which the Work in its entirety in unmodified form, along with a number of other contributions, constituting separate and independent works in themselves, are assembled into a collective whole. A work that constitutes a Collective Work will not be considered a Derivative Work (as defined below) for the purposes of this License. b. "Derivative Work" means a work based upon the Work or upon the Work and other pre-existing works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which the Work may be recast, transformed, or adapted, except that a work that constitutes a Collective Work will not be considered a Derivative Work for the purpose of this License. For the avoidance of doubt, where the Work is a musical composition or sound recording, the synchronization of the Work in timed-relation with a moving image ("synching") will be considered a Derivative Work for the purpose of this License. c. "Licensor" means the individual or entity that offers the Work under the terms of this License. d. "Original Author" means the individual or entity who created the Work. e. "Work" means the copyrightable work of authorship offered under the terms of this License. f. "You" means an individual or entity exercising rights under this License who has not previously violated the terms of this License with respect to the Work, or who has received express permission from the Licensor to exercise rights under this License despite a previous violation. 2. Fair Use Rights. Nothing in this license is intended to reduce, limit, or restrict any rights arising from fair use, first sale or other limitations on the exclusive rights of the copyright owner under copyright law or other applicable laws. 3. License Grant. Subject to the terms and conditions of this License, Licensor hereby grants You a worldwide, royalty-free, non-exclusive, perpetual (for the duration of the applicable copyright) license to exercise the rights in the Work as stated below: a. to reproduce the Work, to incorporate the Work into one or more Collective Works, and to reproduce the Work as incorporated in the Collective Works; b. to create and reproduce Derivative Works; c. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission the Work including as incorporated in Collective Works; d. to distribute copies or phonorecords of, display publicly, perform publicly, and perform publicly by means of a digital audio transmission Derivative Works. e. For the avoidance of doubt, where the work is a musical composition: i. Performance Royalties Under Blanket Licenses. Licensor waives the exclusive right to collect, whether individually or via a performance rights society (e.g. ASCAP, BMI, SESAC), royalties for the public performance or public digital performance (e.g. webcast) of the Work. ii. Mechanical Rights and Statutory Royalties. Licensor waives the exclusive right to collect, whether individually or via a music rights agency or designated agent (e.g. Harry Fox Agency), royalties for any phonorecord You create from the Work ("cover version") and distribute, subject to the compulsory license created by 17 USC Section 115 of the US Copyright Act (or the equivalent in other jurisdictions). f. Webcasting Rights and Statutory Royalties. For the avoidance of doubt, where the Work is a sound recording, Licensor waives the exclusive right to collect, whether individually or via a performance-rights society (e.g. SoundExchange), royalties for the public digital performance (e.g. webcast) of the Work, subject to the compulsory license created by 17 USC Section 114 of the US Copyright Act (or the equivalent in other jurisdictions). The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by Licensor are hereby reserved. 4. Restrictions.The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: a. You may distribute, publicly display, publicly perform, or publicly digitally perform the Work only under the terms of this License, and You must include a copy of, or the Uniform Resource Identifier for, this License with every copy or phonorecord of the Work You distribute, publicly display, publicly perform, or publicly digitally perform. You may not offer or impose any terms on the Work that alter or restrict the terms of this License or the recipients' exercise of the rights granted hereunder. You may not sublicense the Work. You must keep intact all notices that refer to this License and to the disclaimer of warranties. You may not distribute, publicly display, publicly perform, or publicly digitally perform the Work with any technological measures that control access or use of the Work in a manner inconsistent with the terms of this License Agreement. The above applies to the Work as incorporated in a Collective Work, but this does not require the Collective Work apart from the Work itself to be made subject to the terms of this License. If You create a Collective Work, upon notice from any Licensor You must, to the extent practicable, remove from the Collective Work any reference to such Licensor or the Original Author, as requested. If You create a Derivative Work, upon notice from any Licensor You must, to the extent practicable, remove from the Derivative Work any reference to such Licensor or the Original Author, as requested. b. If you distribute, publicly display, publicly perform, or publicly digitally perform the Work or any Derivative Works or Collective Works, You must keep intact all copyright notices for the Work and give the Original Author credit reasonable to the medium or means You are utilizing by conveying the name (or pseudonym if applicable) of the Original Author if supplied; the title of the Work if supplied; to the extent reasonably practicable, the Uniform Resource Identifier, if any, that Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and in the case of a Derivative Work, a credit identifying the use of the Work in the Derivative Work (e.g., "French translation of the Work by Original Author," or "Screenplay based on original Work by Original Author"). Such credit may be implemented in any reasonable manner; provided, however, that in the case of a Derivative Work or Collective Work, at a minimum such credit will appear where any other comparable authorship credit appears and in a manner at least as prominent as such other comparable authorship credit. 5. Representations, Warranties and Disclaimer UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 7. Termination a. This License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Derivative Works or Collective Works from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. b. Subject to the above terms and conditions, the license granted here is perpetual (for the duration of the applicable copyright in the Work). Notwithstanding the above, Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated above. 8. Miscellaneous a. Each time You distribute or publicly digitally perform the Work or a Collective Work, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. b. Each time You distribute or publicly digitally perform a Derivative Work, Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. c. If any provision of this License is invalid or unenforceable under applicable law, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action by the parties to this agreement, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the party to be charged with such waiver or consent. e. This License constitutes the entire agreement between the parties with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of Licensor. Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, neither party will use the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. Creative Commons may be contacted at http://creativecommons.org/. ====================================================================
The svnserve program is a lightweight
server, capable of speaking to clients over TCP/IP using a
custom, stateful protocol. Clients contact an
svnserve server by using URLs that begin with
the svn://
or svn+ssh://
scheme. This section will explain the different ways of running
svnserve, how clients authenticate themselves
to the server, and how to configure appropriate access control
to your repositories.
There are a few different ways to run the svnserve program:
Run svnserve as a standalone daemon, listening for requests.
Have the Unix inetd daemon temporarily spawn svnserve whenever a request comes in on a certain port.
Have SSH invoke a temporary svnserve over an encrypted tunnel.
Run svnserve as a Microsoft Windows service.
The easiest option is to run svnserve
as a standalone “daemon†process. Use the
-d
option for this:
$ svnserve -d $ # svnserve is now running, listening on port 3690
When running svnserve in daemon mode,
you can use the --listen-port
and
--listen-host
options to customize the
exact port and hostname to “bind†to.
Once we successfully start svnserve as
explained previously, it makes every repository on your system
available to the network. A client needs to specify an
absolute path in the repository URL. For
example, if a repository is located at
/var/svn/project1
, a client would
reach it via
svn://host.example.com/var/svn/project1
. To
increase security, you can pass the -r
option
to svnserve, which restricts it to
exporting only repositories below that path. For
example:
$ svnserve -d -r /var/svn …
Using the -r
option effectively
modifies the location that the program treats as the root of
the remote filesystem space. Clients then use URLs that
have that path portion removed from them, leaving much
shorter (and much less revealing) URLs:
$ svn checkout svn://host.example.com/project1 …
If you want inetd to launch the
process, you need to pass the -i
(--inetd
) option. In the following
example, we've shown the output from running
svnserve -i
at the command line, but note
that this isn't how you actually start the daemon; see the
paragraphs following the example for how to configure
inetd to start
svnserve.
$ svnserve -i ( success ( 1 2 ( ANONYMOUS ) ( edit-pipeline ) ) )
When invoked with the --inetd
option,
svnserve attempts to speak with a
Subversion client via stdin
and
stdout
using a custom protocol. This is
the standard behavior for a program being run via
inetd. The IANA has reserved port 3690 for
the Subversion protocol, so on a Unix-like system you can add
lines to /etc/services
such as these (if
they don't already exist):
svn 3690/tcp # Subversion svn 3690/udp # Subversion
If your system is using a classic Unix-like
inetd daemon, you can add this line to
/etc/inetd.conf
:
svn stream tcp nowait svnowner /usr/bin/svnserve svnserve -i
Make sure “svnowner†is a user that has
appropriate permissions to access your repositories. Now,
when a client connection comes into your server on port 3690,
inetd will spawn an
svnserve process to service it. Of course,
you may also want to add -r
to the
configuration line as well, to restrict which repositories are
exported.
A third way to invoke svnserve is in
tunnel mode, using the -t
option. This
mode assumes that a remote-service program such as
rsh or ssh has
successfully authenticated a user and is now invoking a
private svnserve process as
that user. (Note that you, the user, will
rarely, if ever, have reason to invoke
svnserve with the -t
at
the command line; instead, the SSH daemon
does so for you.) The svnserve program
behaves normally (communicating via
stdin
and stdout
)
and assumes that the traffic is being automatically
redirected over some sort of tunnel back to the client.
When svnserve is invoked by a tunnel
agent like this, be sure that the authenticated user has
full read and write access to the repository database files.
It's essentially the same as a local user accessing the
repository via file://
URLs.
This option is described in much more detail later in this chapter in the section called “Tunneling over SSHâ€.
If your Windows system is a descendant of Windows NT
(2000, 2003, XP, or Vista), you can
run svnserve as a standard Windows
service. This is typically a much nicer experience than
running it as a standalone daemon with
the --daemon
(-d
) option.
Using daemon mode requires launching a console, typing a
command, and then leaving the console window running
indefinitely. A Windows service, however, runs in the
background, can start at boot time automatically, and can be
started and stopped using the same consistent administration
interface as other Windows services.
You'll need to define the new service using the command-line tool SC.EXE. Much like the inetd configuration line, you must specify an exact invocation of svnserve for Windows to run at startup time:
C:\> sc create svn binpath= "C:\svn\bin\svnserve.exe --service -r C:\repos" displayname= "Subversion Server" depend= Tcpip start= auto
This defines a new Windows service named
“svn,†which executes a particular
svnserve.exe command when started (in
this case, rooted at C:\repos
). There
are a number of caveats in the prior example,
however.
First, notice that the svnserve.exe
program must always be invoked with the
--service
option. Any other options to
svnserve must then be specified on the
same line, but you cannot add conflicting options such as
--daemon
(-d
), --tunnel
,
or --inetd
(-i
). Options
such as -r
or --listen-port
are fine, though. Second,
be careful about spaces when invoking
the SC.EXE command: the key=
value
patterns must have no spaces between
key=
and must have exactly one space
before the value
. Lastly, be careful
about spaces in your command line to be invoked. If a
directory name contains spaces (or other characters that
need escaping), place the entire inner value of
binpath
in double quotes, by escaping
them:
C:\> sc create svn binpath= "\"C:\program files\svn\bin\svnserve.exe\" --service -r C:\repos" displayname= "Subversion Server" depend= Tcpip start= auto
Also note that the word binpath
is
misleading—its value is a command
line, not the path to an executable. That's why
you need to surround it with quotes if it contains
embedded spaces.
Once the service is defined, it can be stopped, started, or queried using standard GUI tools (the Services administrative control panel), or at the command line:
C:\> net stop svn C:\> net start svn
The service can also be uninstalled (i.e., undefined) by
deleting its definition: sc delete svn
.
Just be sure to stop the service first!
The SC.EXE program has many other
subcommands and options; run sc /?
to
learn more about it.
When a client connects to an svnserve process, the following things happen:
The client selects a specific repository.
The server processes the repository's
conf/svnserve.conf
file and begins to
enforce any authentication and authorization policies it
describes.
Depending on the defined policies, one of the following may occur:
The client may be allowed to make requests anonymously, without ever receiving an authentication challenge.
The client may be challenged for authentication at any time.
If operating in tunnel mode, the client will declare itself to be already externally authenticated (typically by SSH).
The svnserve server, by default, knows only how to send a CRAM-MD5 [42] authentication challenge. In essence, the server sends a small amount of data to the client. The client uses the MD5 hash algorithm to create a fingerprint of the data and password combined, and then sends the fingerprint as a response. The server performs the same computation with the stored password to verify that the result is identical. At no point does the actual password travel over the network.
If your svnserve server was built with SASL support, it not only knows how to send CRAM-MD5 challenges, but also likely knows a whole host of other authentication mechanisms. See the section called “Using svnserve with SASL†later in this chapter to learn how to configure SASL authentication and encryption.
It's also possible, of course, for the client to be externally authenticated via a tunnel agent, such as ssh. In that case, the server simply examines the user it's running as, and uses this name as the authenticated username. For more on this, see the later section, the section called “Tunneling over SSHâ€.
As you've already guessed, a repository's
svnserve.conf
file is the central
mechanism for controlling authentication and authorization
policies. The file has the same format as other configuration
files (see the section called “Runtime Configuration Areaâ€):
section names are marked by square brackets
([
and ]
), comments
begin with hashes (#
), and each section
contains specific variables that can be set (variable
= value
). Let's walk through these files and learn
how to use them.
For now, the [general]
section of
svnserve.conf
has all the variables you
need. Begin by changing the values of those variables:
choose a name for a file that will contain your usernames
and passwords and choose an authentication realm:
[general] password-db = userfile realm = example realm
The realm
is a name that you define.
It tells clients which sort of “authentication
namespace†they're connecting to; the Subversion
client displays it in the authentication prompt and uses it
as a key (along with the server's hostname and port) for
caching credentials on disk (see the section called “Client Credentials Cachingâ€). The
password-db
variable points to a separate
file that contains a list of usernames and passwords, using
the same familiar format. For example:
[users] harry = foopassword sally = barpassword
The value of password-db
can be an
absolute or relative path to the users file. For many
admins, it's easy to keep the file right in the
conf/
area of the repository, alongside
svnserve.conf
. On the other hand, it's
possible you may want to have two or more repositories share
the same users file; in that case, the file should probably
live in a more public place. The repositories sharing the
users file should also be configured to have the same realm,
since the list of users essentially defines an
authentication realm. Wherever the file lives, be sure to
set the file's read and write permissions appropriately. If
you know which user(s) svnserve will run
as, restrict read access to the users file as necessary.
There are two more variables to set in the
svnserve.conf
file: they determine what
unauthenticated (anonymous) and authenticated users are
allowed to do. The variables anon-access
and auth-access
can be set to the value
none
, read
, or
write
. Setting the value to
none
prohibits both reading and writing;
read
allows read-only access to the
repository, and write
allows complete
read/write access to the repository. For example:
[general] password-db = userfile realm = example realm # anonymous users can only read the repository anon-access = read # authenticated users can both read and write auth-access = write
The example settings are, in fact, the default values of the variables, should you forget to define them. If you want to be even more conservative, you can block anonymous access completely:
[general] password-db = userfile realm = example realm # anonymous users aren't allowed anon-access = none # authenticated users can both read and write auth-access = write
The server process understands not only
these “blanket†access controls to the
repository, but also finer-grained access restrictions placed
on specific files and directories within the repository. To
make use of this feature, you need to define a file containing
more detailed rules, and then set
the authz-db
variable to point to it:
[general] password-db = userfile realm = example realm # Specific access rules for specific locations authz-db = authzfile
We discuss the syntax of the authzfile
file
in detail later in this chapter, in
the section called “Path-Based Authorizationâ€. Note
that the authz-db
variable isn't mutually
exclusive with the anon-access
and auth-access
variables; if all the
variables are defined at once, all
of the rules must be satisfied before access is allowed.
For many teams, the built-in CRAM-MD5 authentication is all they need from svnserve. However, if your server (and your Subversion clients) were built with the Cyrus Simple Authentication and Security Layer (SASL) library, you have a number of authentication and encryption options available to you.
Normally, when a subversion client connects to svnserve, the server sends a greeting that advertises a list of the capabilities it supports, and the client responds with a similar list of capabilities. If the server is configured to require authentication, it then sends a challenge that lists the authentication mechanisms available; the client responds by choosing one of the mechanisms, and then authentication is carried out in some number of round-trip messages. Even when SASL capabilities aren't present, the client and server inherently know how to use the CRAM-MD5 and ANONYMOUS mechanisms (see the section called “Built-in Authentication and Authorizationâ€). If server and client were linked against SASL, a number of other authentication mechanisms may also be available. However, you'll need to explicitly configure SASL on the server side to advertise them.
To activate specific SASL mechanisms on the server,
you'll need to do two things. First, create
a [sasl]
section in your
repository's svnserve.conf
file with an
initial key-value pair:
[sasl] use-sasl = true
Second, create a main SASL configuration file
called svn.conf
in a place where the
SASL library can find it—typically in the directory
where SASL plug-ins are located. You'll have to locate the
plug-in directory on your particular system, such
as /usr/lib/sasl2/
or /etc/sasl2/
. (Note that this
is not
the svnserve.conf
file that lives
within a repository!)
On a Windows server, you'll also have to edit the system
registry (using a tool such as regedit)
to tell SASL where to find things. Create a registry key
named [HKEY_LOCAL_MACHINE\SOFTWARE\Carnegie
Mellon\Project Cyrus\SASL Library]
, and place two
keys inside it: a key called SearchPath
(whose value is a path to the directory containing the SASL
sasl*.dll
plug-in libraries), and a key
called
ConfFile
(whose value is a path to the
parent directory containing
the svn.conf
file you created).
Because SASL provides so many different kinds of
authentication mechanisms, it would be foolish (and far
beyond the scope of this book) to try to describe every
possible server-side configuration. Instead, we recommend
that you read the documentation supplied in the
doc/
subdirectory of the SASL source
code. It goes into great detail about every mechanism and
how to configure the server appropriately for each. For the
purposes of this discussion, we'll just demonstrate a simple
example of configuring the DIGEST-MD5 mechanism. For
example, if your subversion.conf
(or svn.conf
) file contains the
following:
pwcheck_method: auxprop auxprop_plugin: sasldb sasldb_path: /etc/my_sasldb mech_list: DIGEST-MD5
you've told SASL to advertise the DIGEST-MD5
mechanism to clients and to check user passwords against a
private password database located
at /etc/my_sasldb
. A system
administrator can then use
the saslpasswd2 program to add or modify
usernames and passwords in the database:
$ saslpasswd2 -c -f /etc/my_sasldb -u realm username
A few words of warning: first, make sure the
“realm†argument
to saslpasswd2 matches the same realm
you've defined in your
repository's svnserve.conf
file; if
they don't match, authentication will fail. Also, due to a
shortcoming in SASL, the common realm must be a string with
no space characters. Finally, if you decide to go with the
standard SASL password database, make sure
the svnserve program has read access to
the file (and possibly write access as well, if you're using
a mechanism such as OTP).
This is just one simple way of configuring SASL. Many other authentication mechanisms are available, and passwords can be stored in other places such as in LDAP or a SQL database. Consult the full SASL documentation for details.
Remember that if you configure your server to only allow certain SASL authentication mechanisms, this forces all connecting clients to have SASL support as well. Any Subversion client built without SASL support (which includes all pre-1.5 clients) will be unable to authenticate. On the one hand, this sort of restriction may be exactly what you want (“My clients must all use Kerberos!â€). However, if you still want non-SASL clients to be able to authenticate, be sure to advertise the CRAM-MD5 mechanism as an option. All clients are able to use CRAM-MD5, whether they have SASL capabilities or not.
SASL is also able to perform data encryption if a
particular mechanism supports it. The built-in CRAM-MD5
mechanism doesn't support encryption, but DIGEST-MD5 does,
and mechanisms such as SRP actually require use of the
OpenSSL library. To enable or disable different levels of
encryption, you can set two values in your repository's
svnserve.conf
file:
[sasl] use-sasl = true min-encryption = 128 max-encryption = 256
The min-encryption
and
max-encryption
variables control the
level of encryption demanded by the server. To disable
encryption completely, set both values to 0. To enable
simple checksumming of data (i.e., prevent tampering and
guarantee data integrity without encryption), set both
values to 1. If you wish to allow—but not
require—encryption, set the minimum value to 0, and
the maximum value to some bit length. To require encryption
unconditionally, set both values to numbers greater than 1.
In our previous example, we require clients to do at least
128-bit encryption, but no more than 256-bit
encryption.
svnserve's built-in authentication (and SASL support) can be very handy, because it avoids the need to create real system accounts. On the other hand, some administrators already have well-established SSH authentication frameworks in place. In these situations, all of the project's users already have system accounts and the ability to “SSH into†the server machine.
It's easy to use SSH in conjunction with
svnserve. The client simply uses the
svn+ssh://
URL scheme to connect:
$ whoami harry $ svn list svn+ssh://host.example.com/repos/project harryssh@host.example.com's password: ***** foo bar baz …
In this example, the Subversion client is invoking a local
ssh process, connecting to
host.example.com
, authenticating as the
user harryssh
(according to SSH user
configuration), then spawning a private
svnserve process on the remote machine
running as the user harryssh
. The
svnserve command is being invoked in tunnel
mode (-t
), and its network protocol is being
“tunneled†over the encrypted connection by
ssh, the tunnel agent.
If the client performs a commit, the authenticated username
harryssh
will be used as the author
of the new revision.
The important thing to understand here is that the Subversion client is not connecting to a running svnserve daemon. This method of access doesn't require a daemon, nor does it notice one if present. It relies wholly on the ability of ssh to spawn a temporary svnserve process, which then terminates when the network connection is closed.
When using svn+ssh://
URLs to access a
repository, remember that it's the ssh
program prompting for authentication, and
not the svn client
program. That means there's no automatic password-caching
going on (see the section called “Client Credentials Cachingâ€). The
Subversion client often makes multiple connections to the
repository, though users don't normally notice this due to the
password caching feature. When using
svn+ssh://
URLs, however, users may be
annoyed by ssh repeatedly asking for a
password for every outbound connection. The solution is to
use a separate SSH password-caching tool such as
ssh-agent on a Unix-like system, or
pageant on Windows.
When running over a tunnel, authorization is primarily
controlled by operating system permissions to the repository's
database files; it's very much the same as if Harry were
accessing the repository directly via a
file://
URL. If multiple system users are
going to be accessing the repository directly, you may want to
place them into a common group, and you'll need to be careful
about umasks (be sure to read the section called “Supporting Multiple Repository Access Methods†later in this
chapter). But even in the case of tunneling, you can still use the
svnserve.conf
file to block access, by
simply setting auth-access = read
or auth-access = none
.
[43]
You'd think that the story of SSH tunneling would end
here, but it doesn't. Subversion allows you to create custom
tunnel behaviors in your runtime config
file (see the section called “Runtime Configuration Areaâ€.) For
example, suppose you want to use RSH instead of SSH.
[44]
In the [tunnels]
section of your
config
file, simply define it like
this:
[tunnels] rsh = rsh
And now, you can use this new tunnel definition by using a
URL scheme that matches the name of your new variable:
svn+rsh://host/path
. When using the new
URL scheme, the Subversion client will actually be running the
command rsh host svnserve -t
behind the
scenes. If you include a username in the URL (e.g.,
svn+rsh://username@host/path
), the client
will also include that in its command (rsh
username@host svnserve -t
). But you can define new
tunneling schemes to be much more clever than that:
[tunnels] joessh = $JOESSH /opt/alternate/ssh -p 29934
This example demonstrates a couple of things. First, it
shows how to make the Subversion client launch a very specific
tunneling binary (the one located at
/opt/alternate/ssh
) with specific
options. In this case, accessing an
svn+joessh://
URL would invoke the
particular SSH binary with -p 29934
as
arguments—useful if you want the tunnel program to
connect to a nonstandard port.
Second, it shows how to define a custom environment
variable that can override the name of the tunneling program.
Setting the SVN_SSH
environment variable is
a convenient way to override the default SSH tunnel agent.
But if you need to have several different overrides for
different servers, each perhaps contacting a different port or
passing a different set of options to SSH, you can use the
mechanism demonstrated in this example. Now if we were to set
the JOESSH
environment variable, its value
would override the entire value of the tunnel
variable—$JOESSH would be executed
instead of /opt/alternate/ssh -p
29934
.
It's possible to control not only the way in which the client invokes ssh, but also to control the behavior of sshd on your server machine. In this section, we'll show how to control the exact svnserve command executed by sshd, as well as how to have multiple users share a single system account.
To begin, locate the home directory of the account
you'll be using to launch svnserve. Make
sure the account has an SSH public/private keypair
installed, and that the user can log in via public-key
authentication. Password authentication will not work,
since all of the following SSH tricks revolve around using
the SSH authorized_keys
file.
If it doesn't already exist, create the
authorized_keys
file (on Unix,
typically ~/.ssh/authorized_keys
).
Each line in this file describes a public key that is
allowed to connect. The lines are typically of the
form:
ssh-dsa AAAABtce9euch… user@example.com
The first field describes the type of key, the second
field is the base64-encoded key itself, and the third field
is a comment. However, it's a lesser known fact that the
entire line can be preceded by a command
field:
command="program" ssh-dsa AAAABtce9euch… user@example.com
When the command
field is set, the
SSH daemon will run the named program instead of the
typical tunnel-mode svnserve invocation that the
Subversion client asks for. This opens the door to a number
of server-side tricks. In the following examples, we
abbreviate the lines of the file as:
command="program" TYPE KEY COMMENT
Because we can specify the executed server-side command, it's easy to name a specific svnserve binary to run and to pass it extra arguments:
command="/path/to/svnserve -t -r /virtual/root" TYPE KEY COMMENT
In this example, /path/to/svnserve
might be a custom wrapper script
around svnserve which sets the umask (see
the section called “Supporting Multiple Repository Access Methodsâ€.) It also
shows how to anchor svnserve in a virtual
root directory, just as one often does when
running svnserve as a daemon process.
This might be done either to restrict access to parts of the
system, or simply to relieve the user of having to type an
absolute path in the svn+ssh://
URL.
It's also possible to have multiple users share a single
account. Instead of creating a separate system account for
each user, generate a public/private key pair for each
person. Then place each public key into
the authorized_users
file, one per
line, and use the --tunnel-user
option:
command="svnserve -t --tunnel-user=harry" TYPE1 KEY1 harry@example.com command="svnserve -t --tunnel-user=sally" TYPE2 KEY2 sally@example.com
This example allows both Harry and Sally to connect to
the same account via public key authentication. Each of
them has a custom command that will be executed;
the --tunnel-user
option
tells svnserve to assume that the named
argument is the authenticated user. Without
--tunnel-user
, it would appear as though
all commits were coming from the one shared system
account.
A final word of caution: giving a user access to the
server via public-key in a shared account might still allow
other forms of SSH access, even if you've set
the command
value
in authorized_keys
. For example, the
user may still get shell access through SSH or be able to
perform X11 or general port forwarding through your server.
To give the user as little permission as possible, you may
want to specify a number of restrictive options immediately
after the command
:
command="svnserve -t --tunnel-user=harry",no-port-forwarding,no-agent-forw arding,no-X11-forwarding,no-pty TYPE1 KEY1 harry@example.com
Note that this all must be on one line—truly on
one line—since SSH authorized_keys
files do not even allow the conventional backslash character
(\
) for line continuation. The only
reason we've shown it with a line break is to fit it on
the physical page of a book.
Another common version control concept is a tag. A tag is just a “snapshot†of a project in time. In Subversion, this idea already seems to be everywhere. Each repository revision is exactly that—a snapshot of the filesystem after each commit.
However, people often want to give more human-friendly names
to tags, such as release-1.0
. And they want
to make snapshots of smaller subdirectories of the filesystem.
After all, it's not so easy to remember that release 1.0 of a
piece of software is a particular subdirectory of revision
4822.
Once again, svn copy comes to the
rescue. If you want to create a snapshot of
/calc/trunk
exactly as it looks in the
HEAD
revision, make a copy of it:
$ svn copy http://svn.example.com/repos/calc/trunk \ http://svn.example.com/repos/calc/tags/release-1.0 \ -m "Tagging the 1.0 release of the 'calc' project." Committed revision 902.
This example assumes that a
/calc/tags
directory already exists. (If
it doesn't, you can create it using svn
mkdir.) After the copy completes, the new
release-1.0
directory is forever a
snapshot of how the /trunk
directory
looked in the HEAD
revision at the time you
made the copy. Of course, you might want to be more precise
about exactly which revision you copy, in case somebody else
may have committed changes to the project when you weren't
looking. So if you know that revision 901 of
/calc/trunk
is exactly the snapshot you
want, you can specify it by passing -r 901
to
the svn copy command.
But wait a moment: isn't this tag creation procedure the same procedure we used to create a branch? Yes, in fact, it is. In Subversion, there's no difference between a tag and a branch. Both are just ordinary directories that are created by copying. Just as with branches, the only reason a copied directory is a “tag†is because humans have decided to treat it that way: as long as nobody ever commits to the directory, it forever remains a snapshot. If people start committing to it, it becomes a branch.
If you are administering a repository, there are two approaches you can take to managing tags. The first approach is “hands offâ€: as a matter of project policy, decide where your tags will live, and make sure all users know how to treat the directories they copy. (That is, make sure they know not to commit to them.) The second approach is more paranoid: you can use one of the access control scripts provided with Subversion to prevent anyone from doing anything but creating new copies in the tags area (see Chapter 6, Server Configuration). The paranoid approach, however, isn't usually necessary. If a user accidentally commits a change to a tag directory, you can simply undo the change as discussed in the previous section. This is version control, after all!
Sometimes you may want your “snapshot†to be more complicated than a single directory at a single revision.
For example, pretend your project is much larger than our
calc
example: suppose it contains a
number of subdirectories and many more files. In the course
of your work, you may decide that you need to create a working
copy that is designed to have specific features and bug fixes.
You can accomplish this by selectively backdating files or
directories to particular revisions (using svn update
with the -r
option liberally), by switching files and directories to
particular branches (making use of svn
switch), or even just by making a bunch of local
changes. When you're done, your working copy is a hodgepodge
of repository locations from different revisions. But after
testing, you know it's the precise combination of data you
need to tag.
Time to make a snapshot. Copying one URL to another won't work here. In this case, you want to make a snapshot of your exact working copy arrangement and store it in the repository. Luckily, svn copy actually has four different uses (which you can read about in Chapter 9, Subversion Complete Reference), including the ability to copy a working copy tree to the repository:
$ ls my-working-copy/ $ svn copy my-working-copy \ http://svn.example.com/repos/calc/tags/mytag \ -m "Tag my existing working copy state." Committed revision 940.
Now there is a new directory in the repository,
/calc/tags/mytag
, which is an exact
snapshot of your working copy—mixed revisions, URLs,
local changes, and all.
Other users have found interesting uses for this feature. Sometimes there are situations where you have a bunch of local changes made to your working copy, and you'd like a collaborator to see them. Instead of running svn diff and sending a patch file (which won't capture directory, symlink, or property changes), you can use svn copy to “upload†your working copy to a private area of the repository. Your collaborator can then either check out a verbatim copy of your working copy or use svn merge to receive your exact changes.
While this is a nice method for uploading a quick snapshot of your working copy, note that this is not a good way to initially create a branch. Branch creation should be an event unto itself, and this method conflates the creation of a branch with extra changes to files, all within a single revision. This makes it very difficult (later on) to identify a single revision number as a branch point.
svn diff — This displays the differences between two revisions or paths.
diff [-c M | -r N[:M]] [TARGET[@REV]...]
diff [-r N[:M]] --old=OLD-TGT[@OLDREV] [--new=NEW-TGT[@NEWREV]] [PATH...]
diff OLD-URL[@OLDREV] NEW-URL[@NEWREV]
Display the differences between two paths. You can use svn diff in the following ways:
Use just svn diff to display local modifications in a working copy.
Display the changes made to
TARGET
s as they are seen in
REV
between two revisions.
TARGET
s may be all working copy
paths or all URL
s. If
TARGET
s are working copy paths,
N
defaults to
BASE
and M
to the working copy; if TARGET
s
are URL
s,
N
must be specified and
M
defaults to
HEAD
. The -c M
option
is equivalent to -r N:M
where N =
M-1
. Using -c -M
does the
reverse: -r M:N
where N =
M-1
.
Display the differences between
OLD-TGT
as it was seen in
OLDREV
and
NEW-TGT
as it was seen in
NEWREV
.
PATH
s, if given, are relative
to OLD-TGT
and
NEW-TGT
and restrict the output
to differences for those paths.
OLD-TGT
and
NEW-TGT
may be working copy
paths or URL[@REV]
.
NEW-TGT
defaults to
OLD-TGT
if not specified.
-r N
makes OLDREV
default to
N
; -r N:M
makes OLDREV
default to
N
and
NEWREV
default to
M
.
svn diff OLD-URL[@OLDREV]
NEW-URL[@NEWREV]
is shorthand for svn
diff --old=OLD-URL[@OLDREV]
--new=NEW-URL[@NEWREV].
svn diff -r N:M URL
is shorthand
for svn diff -r N:M --old=URL
--new=URL
.
svn diff [-r N[:M]] URL1[@N]
URL2[@M]
is shorthand for svn diff [-r
N[:M]] --old=URL1 --new=URL2
.
If TARGET
is a URL, then
revs N
and M
can be
given either via the
--revision
(-r
) option
or by using the
“@†notation as described earlier.
If TARGET
is a working copy
path, the default behavior (when no
--revision
(-r
) option
is provided) is to display the differences between the
base and working copies
of TARGET
. If a
--revision
(-r
) option is specified in this
scenario, though, it means:
--revision N:M
The server compares
TARGET@N
and
TARGET@M
.
--revision N
The client compares
TARGET@N
against the working copy.
If the alternate syntax is used, the server compares
URL1
and
URL2
at revisions
N
and
M
, respectively. If either
N
or
M
is omitted, a value of
HEAD
is assumed.
By default, svn diff ignores the
ancestry of files and merely compares the contents of the
two files being compared. If you use
--notice-ancestry
, the ancestry of the
paths in question will be taken into consideration when
comparing revisions (i.e., if you run svn
diff on two files with identical contents but
different ancestry, you will see the entire contents of
the file as having been removed and added again).
For obtaining differences against anything but
BASE
revision in your working copy
--change (-c) ARG --changelist ARG --depth ARG --diff-cmd CMD --extensions (-x) ARG --force --new ARG --no-diff-deleted --notice-ancestry --old ARG --revision (-r) ARG --summarize --xml
Compare BASE
and your working copy
(one of the most popular uses of svn
diff):
$ svn diff COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 4404) +++ COMMITTERS (working copy)
See what changed in the file
COMMITTERS
revision 9115:
$ svn diff -c 9115 COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3900) +++ COMMITTERS (working copy)
See how your working copy's modifications compare against an older revision:
$ svn diff -r 3900 COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3900) +++ COMMITTERS (working copy)
Compare revision 3000 to revision 3500 using “@†syntax:
$ svn diff http://svn.collab.net/repos/svn/trunk/COMMITTERS@3000 \ http://svn.collab.net/repos/svn/trunk/COMMITTERS@3500 Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3000) +++ COMMITTERS (revision 3500) …
Compare revision 3000 to revision 3500 using range notation (pass only the one URL in this case):
$ svn diff -r 3000:3500 http://svn.collab.net/repos/svn/trunk/COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3000) +++ COMMITTERS (revision 3500)
Compare revision 3000 to revision 3500 of all the files in
trunk
using range notation:
$ svn diff -r 3000:3500 http://svn.collab.net/repos/svn/trunk
Compare revision 3000 to revision 3500 of only three
files in trunk
using range
notation:
$ svn diff -r 3000:3500 --old http://svn.collab.net/repos/svn/trunk \ COMMITTERS README HACKING
If you have a working copy, you can obtain the differences without typing in the long URLs:
$ svn diff -r 3000:3500 COMMITTERS Index: COMMITTERS =================================================================== --- COMMITTERS (revision 3000) +++ COMMITTERS (revision 3500)
Use --diff-cmd
CMD
--extensions
(-x
) to pass arguments directly to the
external diff program:
$ svn diff --diff-cmd /usr/bin/diff -x "-i -b" COMMITTERS Index: COMMITTERS =================================================================== 0a1,2 > This is a test >
Lastly, you can use the --xml
option
along with the --summarize
option to view
XML describing the changes that occurred between
revisions, but not the contents of the diff itself:
$ svn diff --summarize --xml http://svn.red-bean.com/repos/test@r2 \ http://svn.red-bean.com/repos/test <?xml version="1.0"?> <diff> <paths> <path props="none" kind="file" item="modified">http://svn.red-bean.com/repos/test/sandwich.txt</path> <path props="none" kind="file" item="deleted">http://svn.red-bean.com/repos/test/burrito.txt</path> <path props="none" kind="dir" item="added">http://svn.red-bean.com/repos/test/snacks</path> </paths> </diff>
svnlook diff — Print differences of changed files and properties.
--diff-copy-from --no-diff-added --no-diff-deleted --revision (-r) REV --transaction (-t) TXN --extensions (-x) ARG
This shows a newly added (empty) file, a deleted file, and a copied file:
$ svnlook diff -r 40 /var/svn/repos/ Copied: egg.txt (from rev 39, trunk/vendors/deli/pickle.txt) Added: trunk/vendors/deli/soda.txt ============================================================================== Modified: trunk/vendors/deli/sandwich.txt ============================================================================== --- trunk/vendors/deli/sandwich.txt (original) +++ trunk/vendors/deli/sandwich.txt 2003-02-22 17:45:04.000000000 -0600 @@ -0,0 +1 @@ +Don't forget the mayo! Modified: trunk/vendors/deli/logo.jpg ============================================================================== (Binary files differ) Deleted: trunk/vendors/deli/chips.txt ============================================================================== Deleted: trunk/vendors/deli/pickle.txt ==============================================================================
If a file has a nontextual
svn:mime-type
property, the
differences are not explicitly shown.
svnlook tree — Print the tree.
Print the tree, starting at
PATH_IN_REPOS
(if supplied; at
the root of the tree otherwise), optionally showing node
revision IDs.
This shows the tree output (with nodeIDs) for revision 13 in our sample repository:
$ svnlook tree -r 13 /var/svn/repos --show-ids / <0.0.r13/811> trunk/ <1.0.r9/551> button.c <2.0.r9/238> Makefile <3.0.r7/41> integer.c <4.0.r6/98> branches/ <5.0.r13/593> bookstore/ <1.1.r13/390> button.c <2.1.r12/85> Makefile <3.0.r7/41> integer.c <4.1.r13/109>
Now we've covered most of the Subversion client commands. Notable exceptions are those dealing with branching and merging (see Chapter 4, Branching and Merging) and properties (see the section called “Propertiesâ€). However, you may want to take a moment to skim through Chapter 9, Subversion Complete Reference to get an idea of all the different commands that Subversion has—and how you can use them to make your work easier.
svnadmin rmtxns — Delete transactions from a repository.
Delete outstanding transactions from a repository. This is covered in detail in the section called “Removing dead transactionsâ€.
svn merge — Apply the differences between two sources to a working copy path.
svn merge sourceURL1[@N] sourceURL2[@M] [WCPATH]
svn merge sourceWCPATH1@N sourceWCPATH2@M [WCPATH]
svn merge [[-c M]... | [-r N:M]...] [SOURCE[@REV] [WCPATH]]
In the first form, the source URLs are specified at
revisions N
and M
.
These are the two sources to be compared. The revisions
default to HEAD
if omitted.
In the second form, the URLs corresponding to the source working copy paths define the sources to be compared. The revisions must be specified.
In the third form, SOURCE
can be either a URL or a working copy path (in which case
its corresponding URL is used). If not specified,
SOURCE
will be the same as
WCPATH
.
SOURCE
in revision
REV
is compared as it existed
between revisions N
and
M
for each revision range
provided. If REV
is not
specified, HEAD
is assumed.
-c M
is equivalent to -r
<M-1>:M
, and -c -M
does
the reverse: -r M:<M-1>
. If no
revision ranges are specified, the default range of
1:HEAD
is used. Multiple
-c
and/or -r
instances may be specified, and mixing of forward and
reverse ranges is allowed—the ranges are internally
compacted to their minimum representation before merging
begins (which may result in no-op).
WCPATH
is the working copy
path that will receive the changes. If
WCPATH
is omitted, a default
value of “.
†is assumed,
unless the sources have identical basenames that match a
file within “.
â€. In
this case, the differences will be applied to that
file.
Subversion will internally track metadata about the merge operation only if the two sources are ancestrally related—if the first source is an ancestor of the second or vice versa. This is guaranteed to be the case when using the third form. Unlike svn diff, the merge command takes the ancestry of a file into consideration when performing a merge operation. This is very important when you're merging changes from one branch into another and you've renamed a file on one branch but not the other.
--accept ACTION --change (-c) REV --depth ARG --diff3-cmd CMD --dry-run --extensions (-x) ARG --force --ignore-ancestry --quiet (-q) --record-only --reintegrate --revision (-r) REV
Merge a branch back into the trunk (assuming that you have an up-to-date working copy of the trunk):
$ svn merge --reintegrate \ http://svn.example.com/repos/calc/branches/my-calc-branch --- Merging differences between repository URLs into '.': U button.c U integer.c U Makefile U . $ # build, test, verify, ... $ svn commit -m "Merge my-calc-branch back into trunk!" Sending . Sending button.c Sending integer.c Sending Makefile Transmitting file data .. Committed revision 391.
To merge changes to a single file:
$ cd myproj $ svn merge -r 30:31 thhgttg.txt U thhgttg.txt
pre-commit — Notification just prior to commit completion.
The pre-commit
hook is run just
before a commit transaction is promoted to a new revision.
Typically, this hook is used to protect against commits that
are disallowed due to content or location (e.g., your
site might require that all commits to a certain branch
include a ticket number from the bug tracker, or that the
incoming log message is nonempty).
If the pre-commit
hook program
returns a nonzero exit value, the commit is aborted, the
commit transaction is removed, and anything printed to
stderr
is marshalled back to the client.
svn resolved — Deprecated. Remove “conflicted†state on working copy files or directories.
This command has been deprecated in favor of
running svn resolve --accept working
.
See svn resolve in the preceding section for
details.PATH
Remove “conflicted†state on working copy
files or directories. This routine does not semantically
resolve conflict markers; it merely removes
conflict-related artifact files and allows
PATH
to be committed again;
that is, it tells Subversion that the conflicts have been
“resolved.†See the section called “Resolve Conflicts (Merging Others' Changes)†for an in-depth look at
resolving conflicts.
If you get a conflict on an update, your working copy will sprout three new files:
$ svn update C foo.c Updated to revision 31. $ ls foo.c foo.c.mine foo.c.r30 foo.c.r31
Once you've resolved the conflict and
foo.c
is ready to be committed, run
svn resolved to let your working copy
know you've taken care of everything.
Warning | |
---|---|
You can just remove the conflict files and commit, but svn resolved fixes up some bookkeeping data in the working copy administrative area in addition to removing the conflict files, so we recommend that you use this command. |