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 第 6 章 服务配置). 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!
有时候你希望你的“快照”能够很复杂,而不只是一个单独修订版本的一个单独目录。
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 第 9 章 Subversion 完全参考), 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.