Now you and Sally are working on parallel branches of the
project: you're working on a private branch, and Sally is
working on the trunk, or main line of
development.
For projects that have a large number of contributors, it's
common for most people to have working copies of the trunk.
Whenever someone needs to make a long-running change that is
likely to disrupt the trunk, a standard procedure is to create a
private branch and commit changes there until all the work is
complete.
So, the good news is that you and Sally aren't interfering
with each other. The bad news is that it's very easy to drift
too
far apart. Remember that one of the
problems with the “crawl in a hole” strategy is
that by the time you're finished with your branch, it may be
near-impossible to merge your changes back into the trunk
without a huge number of conflicts.
Instead, you and Sally might continue to share changes as
you work. It's up to you to decide which changes are worth
sharing; Subversion gives you the ability to selectively
“copy” changes between branches. And when you're
completely finished with your branch, your entire set of branch
changes can be copied back into the trunk.
In the previous section, we mentioned that both you and
Sally made changes to integer.c
on
different branches. If you look at Sally's log message for
revision 344, you can see that she fixed some spelling errors.
No doubt, your copy of the same file still has the same spelling
errors. It's likely that your future changes to this file will
be affecting the same areas that have the spelling errors, so
you're in for some potential conflicts when you merge your
branch someday. It's better, then, to receive Sally's change
now,
before
you start working too heavily
in the same places.
It's time to use the
svn merge
command.
This command, it turns out, is a very close cousin to the
svn diff
command (which you read about in
Chapter 3). Both commands are able to compare any two objects
in the repository and describe the differences. For example,
you can ask
svn diff
to show you the exact
change made by Sally in revision 344:
$ svn diff -r 343:344 https://svn.example.com/repos/calc/trunk
Index: integer.c
===================================================================
--- integer.c (revision 343)
+++ integer.c (revision 344)
@@ -147,7 +147,7 @@
case 6: sprintf(info->operating_system, "HPFS (OS/2 or NT)"); break;
case 7: sprintf(info->operating_system, "Macintosh"); break;
case 8: sprintf(info->operating_system, "Z-System"); break;
- case 9: sprintf(info->operating_system, "CPM"); break;
+ case 9: sprintf(info->operating_system, "CP/M"); break;
case 10: sprintf(info->operating_system, "TOPS-20"); break;
case 11: sprintf(info->operating_system, "NTFS (Windows NT)"); break;
case 12: sprintf(info->operating_system, "QDOS"); break;
@@ -164,7 +164,7 @@
low = (unsigned short) read_byte(gzfile); /* read LSB */
high = (unsigned short) read_byte(gzfile); /* read MSB */
high = high << 8; /* interpret MSB correctly */
- total = low + high; /* add them togethe for correct total */
+ total = low + high; /* add them together for correct total */
info->extra_header = (unsigned char *) my_malloc(total);
fread(info->extra_header, total, 1, gzfile);
@@ -241,7 +241,7 @@
Store the offset with ftell() ! */
if ((info->data_offset = ftell(gzfile))== -1) {
- printf("error: ftell() retturned -1.\n");
+ printf("error: ftell() returned -1.\n");
exit(1);
}
@@ -249,7 +249,7 @@
printf("I believe start of compressed data is %u\n", info->data_offset);
#endif
- /* Set postion eight bytes from the end of the file. */
+ /* Set position eight bytes from the end of the file. */
if (fseek(gzfile, -8, SEEK_END)) {
printf("error: fseek() returned non-zero\n");
The
svn merge
command is almost exactly
the same. Instead of printing the differences to your
terminal, however, it applies them directly to your working
copy as
local modifications
:
$ svn merge -r 343:344 https://svn.example.com/repos/calc/trunk
U integer.c
$ svn status
M integer.c
The output of
svn merge
shows that your
copy of integer.c
was patched. It now
contains Sally's change—the change has been
“copied” from the trunk to your working copy of
your private branch, and now exists as a local modification.
At this point, it's up to you to review the local modification
and make sure it works correctly.
In another scenario, it's possible that things may not have
gone so well, and that integer.c
may have
entered a conflicted state. You might need to resolve the
conflict using standard procedures (see Chapter 3), or if you
decide that the merge was a bad idea altogether, simply give up
and
svn revert
the local change.
But assuming that you've reviewed the merged change, you can
svn commit
the change as usual. At that
point, the change has been merged into your repository branch.
In version control terminology, this act of copying changes
between branches is commonly called
porting changes.
When you commit the local modification, make sure your log
message mentions that you're porting a specific change from
one branch to another. For example:
$ svn commit -m "integer.c: ported r344 (spelling fixes) from trunk."
Sending integer.c
Transmitting file data .
Committed revision 360.
As you'll see in the next sections, this is a very
important “best practice” to follow.
A word of warning: while
svn diff
and
svn merge
are very similar in concept, they
do have different syntax in many cases. Be sure to read about
them in Chapter 9 for details, or ask
svn
help
. For example,
svn merge
requires a working-copy path as a target, i.e. a place where
it should apply the tree-changes. If the target isn't
specified, it assumes you are trying to perform one of the
following common operations:
-
You want to merge directory changes into your current
working directory.
-
You want to merge the changes in a specific file into
a file by the same name which exists in your current working
directory.
If you are merging a directory and haven't specified a
target path,
svn merge
assumes the first case
above and tries to apply the changes into your current
directory. If you are merging a file, and that file (or a file
by the same name) exists in your current working directory,
svn merge
assumes the second case and tries
to apply the changes to a local file with the same name.
If you want changes applied somewhere else, you'll
need to say so. For example, if you're sitting in the parent
directory of your working copy, you'll have to specify the
target directory to receive the changes:
$ svn merge -r 343:344 https://svn.example.com/repos/calc/trunk my-calc-branch
U my-calc-branch/integer.c