At this point, you should understand how each commit creates
an entire new filesystem tree (called a “revision”)
in the repository. If not, go back and read about revisions in
the section called “Revisions”.
For this chapter, we'll go back to the same example from
Chapter 2. Remember that you and your collaborator, Sally, are
sharing a repository that contains two projects,
paint
and calc
.
Notice that in
Figure 4.2, “Starting repository layout”, however, each
project directory now contains subdirectories named
trunk
and branches
.
The reason for this will soon become clear.
As before, assume that Sally and you both have working
copies of the “calc” project. Specifically, you
each have a working copy of /calc/trunk
.
All the files for the project are in this subdirectory rather
than in /calc
itself, because your team has
decided that /calc/trunk
is where the
“main line” of development is going to take
place.
Let's say that you've been given the task of performing a
radical reorganization of the project. It will take a long time
to write, and will affect all the files in the project. The
problem here is that you don't want to interfere with Sally, who
is in the process of fixing small bugs here and there. She's
depending on the fact that the latest version of the project (in
/calc/trunk
) is always usable. If you
start committing your changes bit-by-bit, you'll surely break
things for Sally.
One strategy is to crawl into a hole: you and Sally can stop
sharing information for a week or two. That is, start gutting
and reorganizing all the files in your working copy, but don't
commit or update until you're completely finished with the task.
There are a number of problems with this, though. First, it's
not very safe. Most people like to save their work to the
repository frequently, should something bad accidentally happen
to their working copy. Second, it's not very flexible. If you
do your work on different computers (perhaps you have a working
copy of /calc/trunk
on two different
machines), you'll need to manually copy your changes back and
forth, or just do all the work on a single computer. By that
same token, it's difficult to share your changes-in-progress
with anyone else. A common software development “best
practice” is to allow your peers to review your work as you
go. If nobody sees your intermediate commits, you lose
potential feedback. Finally, when you're finished with all your
changes, you might find it very difficult to re-merge your final
work with the rest of the company's main body of code. Sally
(or others) may have made many other changes in the repository
that are difficult to incorporate into your working
copy—especially if you run
svn update
after weeks of isolation.
The better solution is to create your own branch, or line of
development, in the repository. This allows you to save your
half-broken work frequently without interfering with others, yet
you can still selectively share information with your
collaborators. You'll see exactly how this works later
on.
Creating a branch is very simple—you make a copy of
the project in the repository using the
svn
copy
command. Subversion is not only able to copy
single files, but whole directories as well. In this case,
you want to make a copy of the
/calc/trunk
directory. Where should the
new copy live? Wherever you wish—it's a matter of
project policy. Let's say that your team has a policy of
creating branches in the /calc/branches
area of the repository, and you want to name your branch
my-calc-branch
. You'll want to create a
new directory,
/calc/branches/my-calc-branch
, which
begins its life as a copy of
/calc/trunk
.
There are two different ways to make a copy. We'll
demonstrate the messy way first, just to make the concept
clear. To begin, check out a working copy of the project's
root directory, /calc
:
$ svn checkout https://svn.example.com/repos/calc bigwc
A bigwc/trunk/
A bigwc/trunk/Makefile
A bigwc/trunk/integer.c
A bigwc/trunk/button.c
A bigwc/branches/
Checked out revision 340.
Making a copy is now simply a matter of passing two
working-copy paths to the
svn copy
command:
$ cd bigwc
$ svn copy trunk branches/my-calc-branch
$ svn status
A + branches/my-calc-branch
In this case, the
svn copy
command
recursively copies the trunk
working
directory to a new working directory,
branches/my-calc-branch
. As you can see
from the
svn status
command, the new
directory is now scheduled for addition to the repository.
But also notice the “+” sign next to the letter
A. This indicates that the scheduled addition is a
copy
of something, not something new.
When you commit your changes, Subversion will create
/calc/branches/my-calc-branch
in the
repository by copying /calc/trunk
, rather
than resending all of the working copy data over the
network:
$ svn commit -m "Creating a private branch of /calc/trunk."
Adding branches/my-calc-branch
Committed revision 341.
And now the easier method of creating a branch, which we
should have told you about in the first place:
svn
copy
is able to operate directly on two URLs.
$ svn copy https://svn.example.com/repos/calc/trunk \
https://svn.example.com/repos/calc/branches/my-calc-branch \
-m "Creating a private branch of /calc/trunk."
Committed revision 341.
There's really no difference between these two methods.
Both procedures create a new directory in revision 341, and
the new directory is a copy of
/calc/trunk
. This is shown in
Figure 4.3, “Repository with new copy”. Notice that the second method,
however, performs an
immediate
commit.
[8]
It's an easier procedure, because it doesn't require you to
check out a large mirror of the repository. In fact, this
technique doesn't even require you to have a working copy at
all.
[an error occurred while processing this directive]