Subversion for FreeBSD Ports
This page is now historical, as the ports repository was converted from SVN to Git.
Contents
Introduction
This page based on the Subversion Primer (Chapter 5) in the FreeBSD Committer's Guide and will be merged back once we successfully switched to SVN.
More information can found at Version Control with Subversion book.
In this guide the checkout directory refers to /usr/ports. This may not fit with your environment so please use an appropriate path instead of /usr/ports.
The first is to check out directly from the main repository:
% svn checkout svn+ssh://repo.freebsd.org/ports/head /usr/ports
If your FreeBSD login name is different from your login name on your local machine, you must either include it in the URL (for example svn+ssh://jarjar@repo.freebsd.org/ports/head), or add an entry to your ~/.ssh/config in the form:
Host repo.freebsd.org User jarjar
In svn+ssh://repo.freebsd.org/base, base refers to the source tree. Similarly, ports refers to the ports tree, and so on. These are separate repositories with their own change number sequences, access controls and commit mail.
For the ports repository, head refers to the current ports tree. For example, head/www/firefox is what would go into /usr/ports/www/firefox in the ports tree. Some other key locations are:
/tags/n which corresponds to a specific tag taken for a release for example. Naming convention for n is: RELENG_x_y_z for release branches, RELEASE_x_y_z for release tags and RELEASE_x_EOL for branch EOL tags. e.g:
Release branch for FreeBSD 9.1 will be RELENG_9_1_0
Release tag for FreeBSD 9.1 will be RELEASE_9_1_0
EOL tag of FreeBSD 6.x is RELEASE_6_EOL
/branches/ is used during the release process to merge security updates until the tree is tagged.
There will be no /projects and /user space in the official ports repository. Use one of the public available repositories like marcuscom (marcus@), redports (decke@) or chruetertee (beat@).
Help
SVN has built in help documentation. It can be accessed by typing the following command:
% svn help
Getting & Updating Code
Checkout
As seen earlier, to check out the FreeBSD ports head branch:
% svn checkout svn+ssh://repo.freebsd.org/ports/head /usr/ports
or
% svn co --depth=empty svn+ssh://repo.freebsd.org/ports /usr/ports % cd /usr/ports % svn up head
This way you can checkout svnadmin, a tag or branch later in the same working copy.
Anonymous Checkout
Not secure
The data transferred by these commands are unverified. If you do not have a secure and safe connection to repo.freebsd.org, your computer(s) maybe compromised by running code obtained with them. Install security/ca_root_nss port and use https for secure transfers.
It is possible to anonymously check out the FreeBSD repository with Subversion. This will give access to a read-only tree that can be updated, but not committed to. To do this, use one of the following commands:
% svn co http://svn.freebsd.org/ports/head /usr/ports
Partial Checkout
It is possible to check out only part of the FreeBSD ports tree:
% svn checkout --depth empty svn+ssh://repo.freebsd.org/ports/head /usr/ports % cd /usr/ports % svn update --set-depth files % svn update Mk % svn update Templates % svn update Tools % svn update --set-depth files $category % cd $category % svn update $port
Updating
To update a working copy to either the latest revision, or a specific revision:
% svn update % svn update -r12345
Resolving Conflicts
If a svn update resulted in a merge conflict, Subversion will remember which files have conflicts and refuse to commit any changes to those files until explicitly told that the conflicts have been resolved. The simple, not yet deprecated procedure is the following:
% svn resolved foo
However, the preferred procedure is:
% svn resolve --accept=working foo
The two examples are equivalent. Possible values for --accept are:
- working: use the version in your working directory (which one presumes has been edited to resolve the conflicts). - base: use a pristine copy of the version you had before svn update, discarding your own changes, the conflicting changes, and possibly other intervening changes as well. - mine-full: use what you had before svn update, including your own changes, but discarding the conflicting changes, and possibly other intervening changes as well. - theirs-full: use the version that was retrieved when you did svn update, discarding your own changes.
Status
To view the local changes that have been made to the working copy:
% svn status
CVS has no direct equivalent of this command. The nearest would be cvs up -N which shows local changes and files that are out-of-date. Doing this in SVN is possible too, however:
% svn status --show-updates
Making Changes
Adding and Removing Files
Note: Before adding files, get a copy of auto-props.txt and add it to ~/.subversion/config according to the instructions in the file. If you added something before you've read this, you may use svn rm --keep-local for just added files, fix your config file and re-add them again. The initial config file is created when you first run a svn command, even something as simple as svn help.
As with CVS, files are added to a SVN repository with svn add. To add a file named foo, edit it, then:
% svn add foo
Files can be removed with svn remove:
% svn remove foo
Subversion does not require rming the file before svn rming it, and indeed complains if that happens.
It is possible to add directories with svn add:
% mkdir bar % svn add bar
Although svn mkdir makes this easier by combining the creation of the directory and the adding of it:
% svn mkdir bar
In CVS, the directory is immediately created in the repository when you cvs add it; this is not the case in Subversion. Furthermore, unlike CVS, Subversion allows directories to be removed using svn rm, however there is no svn rmdir:
% svn rm bar
Subversion config
Make sure you have a ~/.subversion/config. Simply using it (svn --help) will cause a default one to be created if you don't already have one.
Make the following changes to ~/.subversion/config:
Set:
enable-auto-props = yes
Append/edit auto-props section (if you already use the auto-props for FreeBSD src the entry for Makefile is already done):
[auto-props] bsd.*.mk = svn:eol-style=native; svn:keywords=FreeBSD=%H; svn:mime-type=text/plain distinfo* = svn:eol-style=native; fbsd:nokeywords=yes; svn:mime-type=text/plain extrapatch-* = svn:eol-style=native; fbsd:nokeywords=yes; svn:mime-type=text/plain extra-patch-*= svn:eol-style=native; fbsd:nokeywords=yes; svn:mime-type=text/plain patch-* = svn:eol-style=native; fbsd:nokeywords=yes; svn:mime-type=text/plain pkg-* = svn:eol-style=native; fbsd:nokeywords=yes; svn:mime-type=text/plain Makefile* = svn:eol-style=native; svn:keywords=FreeBSD=%H; svn:mime-type=text/plain
To ignore certain files you can add something like this in the miscellany section:
[miscellany] global-ignores = *.o *.lo *.la *.al .libs *.so *.so.[0-9]* *.a *.pyc *.pyo *.bak *.orig *.rej *~ #*# .#* .*.swp .DS_Store
Properties
To list the current properties use svn proplist:
% svn proplist Makefile Eigenschaften zu »Makefile«: svn:mime-type svn:keywords svn:eol-style
Properties can be showed, deleted and added with svn propget, svn propdel or svn propset:
% svn propdel svn:mime-type Makefile property 'svn:mime-type' deleted from 'Makefile'. % svn proplist Makefile Properties on 'Makefile': svn:keywords svn:eol-style % svn propset svn:mime-type text/plain Makefile property 'svn:mime-type' set on 'Makefile' % svn proplist Makefile Properties on 'Makefile': svn:mime-type svn:keywords svn:eol-style % svn propget svn:mime-type Makefile text/plain
Use those properties:
If your file contains the $FreeBSD$ keyword add: svn:keywords FreeBSD=%H
If the file doesn't contain the $FreeBSD$ keyword add: fbsd:nokeywords yes
All files should have the text/plain mimetype and native EOL's: svn:eol-style native and svn:mime-type text/plain
The cvs2svn:cvs-rev should always be removed prior to committing
The Tools/scripts/psvn wrapper makes sure all properties are set the right way.
Copying and Moving Files
The following (obviously) creates a copy of foo.c, named bar.c:
% svn copy foo.c bar.c
To move and rename a file:
% svn move foo.c bar.c
The above command is the exact equivalent of:
% svn copy foo.c bar.c % svn remove foo.c
Neither of these operations have equivalents in CVS.
Re-adding a removed port
If re-adding a port that has been in the tree in the past, do not simply use svn add-- this will obscure the history of the port's previous existence.
Instead you should copy the last living revision of the port (use http://people.freebsd.org/~crees/removed_ports/index.xml):
% svn co svn+ssh://repo.freebsd.org/ports/head/category % svn cp 'svn+ssh://repo.freebsd.org/ports/head/category/port@{YYYY-MM-DD}' port
Make your changes and ensure that you add or remove any appropriate files. Some revived files may have the cvs2svn:cvs-rev property set which is blocked by a pre-commit hook so you need to remove the cvs2svn:cvs-rev property first:
% svn propdel -R cvs2svn:cvs-rev port
Don't forget to add the revived port to the category Makefile and remove the appropriate entry from the MOVED file. Then commit the changes in a single commit.
Repo-Copy
First make sure that you were using an up to date portstree and the target directory does not exist.
Copy or move the ports directory by using svn cp or svn mv. Edit the files in the new directory (like adding PKGNAMESUFFIX for example) and then commit all changes together (like the removed port, the newly added, the change to category/Makefile and the MOVED entry). There is no longer a need to do a force commit after a repocopy.
Example (Repo-copy www/firefox to www/firefox-esr):
% cd /usr/ports && svn up % ls www/firefox-esr ls: www/firefox-esr: No such file or directory % svn cp www/firefox www/firefox-esr A www/firefox-esr % vi www/Makefile www/firefox-esr/Makefile % svn ci www/Makefile www/firefox-esr
Log and Annotate
svn log will show all the revisions that affect a directory and files within that directory in reverse chronological order, if run on a directory. This contrasts with cvs log in that CVS shows the complete log for each file in the directory, including duplicate entries for revisions that affect multiple files.
svn annotate, or equally svn praise or svn blame, is equivalent to cvs annotate in everything but output format.
Diffs
svn diff displays changes to the working copy of the repository. Diffs generated by SVN are unified by default, unlike CVS, and include new files by default in the diff output.
As with CVS, svn diff can show the changes between two revisions of the same file:
% svn diff -r179453:179454 UPDATING
It can also show all changes for a specific changeset. The following will show what changes were made to the current directory and all subdirectories in changeset 179454:
% svn diff -c179454 .
Reverting
Local changes (including additions and deletions) can be reverted using svn revert. Unlike cvs up -C, it does not update out-of-date files--it just replaces them with pristine copies of the original version.
Committing Changes
Like CVS but unlike Perforce, SVN does not need to be told in advance about file editing.
svn commit works like the equivalent CVS command. To commit all changes in the current directory and all subdirectories:
% svn commit
To commit all changes in, for example, Mk/ and www/firefox/ in a single operation:
% svn commit Mk/ www/firefox/
Always commit all corresponding changes in one commit as SVN will have a single revision number for the whole commit.
If you don't want to deal with Subversion properties (see below) use the psvn wrapper to commit:
% /usr/ports/Tools/scripts/psvn commit
Reverting a Commit
Reverting a commit to a previous version is fairly easy:
% svn merge -r179454:179453 UPDATING % svn commit
Change number syntax, with negative meaning a reverse change, can also be used:
% svn merge -c -179454 UPDATING % svn commit
This can also be done directly in the repository:
% svn merge -r179454:179453 svn+ssh://repo.freebsd.org/ports/head/UPDATING
Reverting the deletion of a file is slightly different. Copying the version of the file that predates the deletion is required. For example, to restore a file that was deleted in revision N, restore version N-1:
% svn copy svn+ssh://repo.freebsd.org/ports/head/UPDATING@179454 % svn commit
or, equally:
% svn copy svn+ssh://repo.freebsd.org/ports/head/UPDATING@179454 svn+ssh://repo.freebsd.org/ports/head/UPDATING
Do not simply recreate the file manually and svn add it--this will cause history to be lost.
Merging
Quarterly Branch
Commits that are quarterly branch (MFH) candidates should be merged to their respective branch after being committed to HEAD.
The process is as follows:
Commit to HEAD, adding MFH: XXXXQN and Security: CVE-YYYY-NNNN in the commit log message body
Adding MFH: XXXXQN automatically sends a notification email to ports-secteam
Check for Approval. If the change has Blanket Approval1, go to Step 4.
Wait for ports-secteam to approve the MFH request they received in Step 1
If you forgot to put MFH: XXXXQN in the commit message:
Forward the mailing list commit email to ports-secteam asking them for approval
Merge the commit with the correct Approved by line (see below), using the Tools/scripts/mfh script:
If the change has Blanket Approval (See Step 2), Add Approved by: ports-secteam (blanket) to the commit log message body
Otherwise, If you had to wait for ports-secteam or portmgr team approval in Step 3, add Approved by: <teamname> (<userid>) to the commit log message body
If the commit has a related Bugzilla issue, set the merge-quarterly flag value to +
Release Branches
Use a full checkout of the release branch (no partial checkouts), do the merge in the top directory (equivalent of /usr/ports) and don't edit mergeinfo manually.
If a commit needs merging to the release branch (like security updates, build fixes) switch to the release branch (make sure your working copy has no uncommitted changes):
% cd /usr/ports % svn switch svn+ssh://repo.FreeBSD.org/ports/branches/RELENG_8_4_1
You can check which commits are available for merging:
% svn mergeinfo ^/head --show-revs eligible r297398
Merge the commit to the release branch now (In this example r297398 is merged to RELENG_8_4_1. Use MFH r297398: at the beginning of the commit message ). The mergeinfo is recorded in the top directory of a release branch only (Make sure you do the merge in the top directory!):
% cd /usr/ports % svn merge -c 297398 ^/head % svn ci
Fixing mergeinfo
If a mergeinfo wasn't recorded properly (for example if the merge wasn't done using svn merge) it can be added afterwards.
Go to the top directory of the release checkout:
% cd /usr/ports
Now record the missing mergeinfo:
% svn merge --record-only -c 307190 ^/head
The merged revisions should be visible now (Please double check if they are there):
% svn mergeinfo ^/head % svn propget svn:mergeinfo .
If you see your merged revisions in both outputs commit it (Commit message could be something like "Fix mergeinfo")
% svn ci
Fixing Mistakes
While we can do surgery in an emergency, do not plan on having mistakes fixed behind the scenes. Plan on mistakes remaining in the logs forever. Be sure to check the output of svn status and svn diff before committing.
Mistakes will happen, but, unlike with CVS, they can generally be fixed without disruption.
Take a case of adding a file in the wrong location. The right thing to do is to svn move the file to the correct location and commit. This causes just a couple of lines of metadata in the repository journal, and the logs are all linked up correctly.
The wrong thing to do is to delete the file and then svn add an independent copy in the correct location: the history of the file is lost.
Forced Commit
Forced commits aren't available with SVN. Nevertheless there is a workaround how to do forced commits with SVN. For example if you like to do a forced commit on a Makefile create a copy of this file first:
% cp Makefile Makefile.orig
Then do a whitespace change or something similar in the file:
% vi Makefile
Now do a svn commit, enter your commit message but don't close the editor:
% svn ci Makefile
Open a second terminal and overwrite the modified file with the original one:
% mv Makefile.orig Makefile
Now close the first editor and finish the commit.
Some Tips
- In commit logs etc., rev 179872 should be spelled r179872 as per convention.
Use Tools/scripts/psvn as a wrapper for svn as it will run some checks and adds the needed svn keywords to new files automatically.
New ports committers should be added in: ports/svnadmin/conf/access
Active mentor - mentee relationships should be documented in ports/svnadmin/conf/mentors (add a new mentee to this file with the access commit and once the mentorship is over just remove it from the mentors file. There is no need to do a forced commit on the access file anymore)
- Don't remove and add the same file in a single commit (is there a sane reason for doing that?) as this will break the CVS exporter.
Release Engineering & Administration
Lock the Tree
Only portmgr should lock the portstree. To lock the ports tree uncommend the ^head/ portmgr line in ports/svnadmin/conf/approvers. To unlock the tree comment out the same line. Don't use svn lock to lock down the tree. This is prohibited by a hook.
Create a Tag
Only create a tag directly from head if there is no need to merge changes (like the CVS tag slips)!
Commit directly in the repository with the revision number you like to tag (stick to the tag naming convention). You don't need to lock the tree for this:
( Just specify the revision you like to tag and make sure you have a trailing slash between head and @! )
% svn copy svn+ssh://repo.FreeBSD.org/ports/head/@295095 svn+ssh://repo.FreeBSD.org/ports/tags/RELEASE_x_y_z
Create and Tag a Release Branch
Release branching and tagging is done by portmgr. Create a release branch once the ports tree is ready for an upcoming release:
( Specify the revision you like to branch/tag and make sure you have a trailing slash between head and @! )
% svn copy svn+ssh://repo.FreeBSD.org/ports/head/@297395 svn+ssh://repo.FreeBSD.org/ports/branches/RELENG_8_4_1
Now security and build/run fixes can be merged to the release branch (see the "Merging" section)
Once the release is done create a tag out of the release branch:
% svn copy svn+ssh://repo.FreeBSD.org/ports/branches/RELENG_8_4_1 svn+ssh://repo.FreeBSD.org/ports/tags/RELEASE_8_4_1
Enable Feature Freeze
To enable a feature freeze change the FEATURE_FREEZE variable in repo.FreeBSD.org/ports/svnadmin/conf/featurefreeze.conf to 1.
CategoryHowTo CategoryHistorical
Approvals are no longer necessary (1)