Sophie

Sophie

distrib > Mandriva > 2008.1 > x86_64 > by-pkgid > 0b38be552745286620faf2138b9468d0 > files > 40

subversion-doc-1.4.6-5.1mdv2008.1.x86_64.rpm

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Vendor branches</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Version Control with Subversion" /><link rel="up" href="svn.branchmerge.html" title="Chapter 4. Branching and Merging" /><link rel="prev" href="svn.branchmerge.commonpatterns.html" title="Common Branching Patterns" /><link rel="next" href="svn.branchmerge.summary.html" title="Summary" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Vendor branches</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="svn.branchmerge.commonpatterns.html">Prev</a> </td><th width="60%" align="center">Chapter 4. Branching and Merging</th><td width="20%" align="right"> <a accesskey="n" href="svn.branchmerge.summary.html">Next</a></td></tr></table><hr /></div><div class="sect1" lang="en" xml:lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="svn.advanced.vendorbr"></a>Vendor branches</h2></div></div></div><p>As is especially the case when developing software, the data
      that you maintain under version control is often closely related
      to, or perhaps dependent upon, someone else's data.  Generally,
      the needs of your project will dictate that you stay as
      up-to-date as possible with the data provided by that external
      entity without sacrificing the stability of your own project.
      This scenario plays itself out all the time—anywhere that
      the information generated by one group of people has a direct
      effect on that which is generated by another group.</p><p>For example, software developers might be working on an
      application which makes use of a third-party library.
      Subversion has just such a relationship with the Apache Portable
      Runtime library (see <a class="xref" href="svn.developer.usingapi.html#svn.developer.usingapi.apr" title="The Apache Portable Runtime Library">the section called “The Apache Portable Runtime Library”</a>).  The
      Subversion source code depends on the APR library for all its
      portability needs.  In earlier stages of Subversion's
      development, the project closely tracked APR's changing API,
      always sticking to the “<span class="quote">bleeding edge</span>” of the
      library's code churn.  Now that both APR and Subversion have
      matured, Subversion attempts to synchronize with APR's library
      API only at well-tested, stable release points.</p><p>Now, if your project depends on someone else's information,
      there are several ways that you could attempt to synchronize that
      information with your own.  Most painfully, you could issue oral
      or written instructions to all the contributors of your project,
      telling them to make sure that they have the specific versions
      of that third-party information that your project needs.  If the
      third-party information is maintained in a Subversion
      repository, you could also use Subversion's externals
      definitions to effectively “<span class="quote">pin down</span>” specific
      versions of that information to some location in your own
      working copy directory (see <a class="xref" href="svn.advanced.externals.html" title="Externals Definitions">the section called “Externals Definitions”</a>).</p><p>But sometimes you want to maintain custom modifications to
      third-party code in your own version control system.  Returning
      to the software development example, programmers might need to
      make modifications to that third-party library for their own
      purposes.  These modifications might include new functionality
      or bug fixes, maintained internally only until they become part
      of an official release of the third-party library.  Or the
      changes might never be relayed back to the library maintainers,
      existing solely as custom tweaks to make the library further
      suit the needs of the software developers.</p><p>Now you face an interesting situation.  Your project could
      house its custom modifications to the third-party data in some
      disjointed fashion, such as using patch files or full-fledged
      alternate versions of files and directories.  But these quickly
      become maintenance headaches, requiring some mechanism by which
      to apply your custom changes to the third-party code, and
      necessitating regeneration of those changes with each successive
      version of the third-party code that you track.</p><p>The solution to this problem is to use <em class="firstterm">vendor
      branches</em>.  A vendor branch is a directory tree in
      your own version control system that contains information
      provided by a third-party entity, or vendor.  Each version of
      the vendor's data that you decide to absorb into your project is
      called a <em class="firstterm">vendor drop</em>.</p><p>Vendor branches provide two benefits.  First, by storing
      the currently supported vendor drop in your own version control
      system, the members of your project never need to question
      whether they have the right version of the vendor's data.  They
      simply receive that correct version as part of their regular
      working copy updates.  Secondly, because the data lives in your
      own Subversion repository, you can store your custom changes to
      it in-place—you have no more need of an automated (or
      worse, manual) method for swapping in your customizations.</p><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.advanced.vendorbr.general"></a>General Vendor Branch Management Procedure</h3></div></div></div><p>Managing vendor branches generally works like this: first,
        you create a top-level directory (such as
        <code class="filename">/vendor</code>) to hold the vendor branches.
        Then you import the third party code into a subdirectory of
        that top-level directory.  You then copy that subdirectory
        into your main development branch (for example,
        <code class="filename">/trunk</code>) at the appropriate location.  You
        always make your local changes in the main development branch.
        With each new release of the code you are tracking you bring
        it into the vendor branch and merge the changes into
        <code class="filename">/trunk</code>, resolving whatever conflicts
        occur between your local changes and the upstream
        changes.</p><p>An example will help to clarify this algorithm.  We'll use
        a scenario where your development team is creating a
        calculator program that links against a third-party complex
        number arithmetic library, libcomplex.  We'll begin with the
        initial creation of the vendor branch, and the import of the
        first vendor drop.  We'll call our vendor branch directory
        <code class="filename">libcomplex</code>, and our code drops will go
        into a subdirectory of our vendor branch called
        <code class="filename">current</code>.  And since <span class="command"><strong>svn
        import</strong></span> creates all the intermediate parent
        directories it needs, we can actually accomplish both of these
        steps with a single command.</p><pre class="screen">
$ svn import /path/to/libcomplex-1.0 \
             http://svn.example.com/repos/vendor/libcomplex/current \
             -m 'importing initial 1.0 vendor drop'
…
</pre><p>We now have the current version of the libcomplex source
        code in <code class="filename">/vendor/libcomplex/current</code>.  Now,
        we tag that version (see <a class="xref" href="svn.branchmerge.tags.html" title="Tags">the section called “Tags”</a>)
        and then copy it into the main development branch.  Our copy
        will create a new directory called
        <code class="filename">libcomplex</code> in our existing
        <code class="filename">calc</code> project directory.  It is in this
        copied version of the vendor data that we will make our
        customizations.</p><pre class="screen">
$ svn copy http://svn.example.com/repos/vendor/libcomplex/current  \
           http://svn.example.com/repos/vendor/libcomplex/1.0      \
           -m 'tagging libcomplex-1.0'
…
$ svn copy http://svn.example.com/repos/vendor/libcomplex/1.0  \
           http://svn.example.com/repos/calc/libcomplex        \
           -m 'bringing libcomplex-1.0 into the main branch'
…
</pre><p>We check out our project's main branch—which now
        includes a copy of the first vendor drop—and we get to
        work customizing the libcomplex code.  Before we know it, our
        modified version of libcomplex is now completely integrated
        into our calculator program.
        <sup>[<a id="id375251" href="#ftn.id375251" class="footnote">26</a>]</sup>
      </p><p>A few weeks later, the developers of libcomplex release a
        new version of their library—version 1.1—which
        contains some features and functionality that we really want.
        We'd like to upgrade to this new version, but without losing
        the customizations we made to the existing version.  What we
        essentially would like to do is to replace our current
        baseline version of libcomplex 1.0 with a copy of libcomplex
        1.1, and then re-apply the custom modifications we previously
        made to that library to the new version.  But we actually
        approach the problem from the other direction, applying the
        changes made to libcomplex between versions 1.0 and 1.1 to our
        modified copy of it.</p><p>To perform this upgrade, we check out a copy of our vendor
        branch, and replace the code in the
        <code class="filename">current</code> directory with the new libcomplex
        1.1 source code.  We quite literally copy new files on top of
        existing files, perhaps exploding the libcomplex 1.1 release
        tarball atop our existing files and directories.  The goal
        here is to make our <code class="filename">current</code> directory
        contain only the libcomplex 1.1 code, and to ensure that all
        that code is under version control.  Oh, and we want to do
        this with as little version control history disturbance as
        possible.</p><p>After replacing the 1.0 code with 1.1 code, <span class="command"><strong>svn
        status</strong></span> will show files with local modifications as
        well as, perhaps, some unversioned files.  If we did what we
        were supposed to do, the unversioned files are only those new
        files introduced in the 1.1 release of libcomplex—we
        run <span class="command"><strong>svn add</strong></span> on those to get them under
        version control.  If the 1.1 code no longer has certain files
        that were in the 1.0 tree, it may be hard to notice them;
        you'd have to compare the two trees with some external tool
        and then <span class="command"><strong>svn delete</strong></span> any files present in
        1.0 but not in 1.1.  (Although it might also be just fine to
        let these same files live on in unused obscurity!)  Finally,
        once our <code class="filename">current</code> working copy contains
        only the libcomplex 1.1 code, we commit the changes we made to
        get it looking that way.</p><p>Our <code class="filename">current</code> branch now contains the
        new vendor drop.  We tag the new version as 1.1 (in the same
        way we previously tagged the version 1.0 vendor drop), and
        then merge the differences between the tag of the previous
        version and the new current version into our main development
        branch.</p><pre class="screen">
$ cd working-copies/calc
$ svn merge http://svn.example.com/repos/vendor/libcomplex/1.0      \
            http://svn.example.com/repos/vendor/libcomplex/current  \
            libcomplex
… # resolve all the conflicts between their changes and our changes
$ svn commit -m 'merging libcomplex-1.1 into the main branch'
…
</pre><p>In the trivial use case, the new version of our
        third-party tool would look, from a files-and-directories
        point of view, just like the previous version.  None of the
        libcomplex source files would have been deleted, renamed or
        moved to different locations—the new version would
        contain only textual modifications against the previous one.
        In a perfect world, our modifications would apply cleanly to
        the new version of the library, with absolutely no
        complications or conflicts.</p><p>But things aren't always that simple, and in fact it is
        quite common for source files to get moved around between
        releases of software.  This complicates the process of
        ensuring that our modifications are still valid for the new
        version of code, and can quickly degrade into a situation
        where we have to manually recreate our customizations in the
        new version.  Once Subversion knows about the history of a
        given source file—including all its previous
        locations—the process of merging in the new version of
        the library is pretty simple.  But we are responsible for
        telling Subversion how the source file layout changed from
        vendor drop to vendor drop.</p></div><div class="sect2" lang="en" xml:lang="en"><div class="titlepage"><div><div><h3 class="title"><a id="svn.advanced.vendorbr.svn_load_dirs"></a><span class="command"><strong>svn_load_dirs.pl</strong></span></h3></div></div></div><p>Vendor drops that contain more than a few deletes,
        additions and moves complicate the process of upgrading to
        each successive version of the third-party data.  So
        Subversion supplies the <span class="command"><strong>svn_load_dirs.pl</strong></span>
        script to assist with this process.  This script automates the
        importing steps we mentioned in the general vendor branch
        management procedure to make sure that mistakes are minimized.
        You will still be responsible for using the merge commands to
        merge the new versions of the third-party data into your main
        development branch, but <span class="command"><strong>svn_load_dirs.pl</strong></span>
        can help you more quickly and easily arrive at that
        stage.</p><p>In short, <span class="command"><strong>svn_load_dirs.pl</strong></span> is an
        enhancement to <span class="command"><strong>svn import</strong></span> that has several
        important characteristics:</p><div class="itemizedlist"><ul type="disc"><li><p>It can be run at any point in time to bring an existing
            directory in the repository to exactly match an external
            directory, performing all the necessary adds and deletes,
            and optionally performing moves, too.</p></li><li><p>It takes care of complicated series of operations between
            which Subversion requires an intermediate commit—such
            as before renaming a file or directory twice.</p></li><li><p>It will optionally tag the newly imported directory.</p></li><li><p>It will optionally add arbitrary properties to files and
            directories that match a regular expression.</p></li></ul></div><p><span class="command"><strong>svn_load_dirs.pl</strong></span> takes three mandatory
        arguments.  The first argument is the URL to the base
        Subversion directory to work in.  This argument is followed by
        the URL—relative to the first argument—into which the
        current vendor drop will be imported.  Finally, the third
        argument is the local directory to import.  Using our previous
        example, a typical run of <span class="command"><strong>svn_load_dirs.pl</strong></span>
        might look like:</p><pre class="screen">
$ svn_load_dirs.pl http://svn.example.com/repos/vendor/libcomplex \
                   current                                        \
                   /path/to/libcomplex-1.1
…
</pre><p>You can indicate that you'd like
        <span class="command"><strong>svn_load_dirs.pl</strong></span> to tag the new vendor drop
        by passing the <code class="option">-t</code> command-line option and
        specifying a tag name.  This tag is another URL relative to
        the first program argument.</p><pre class="screen">
$ svn_load_dirs.pl -t libcomplex-1.1                              \
                   http://svn.example.com/repos/vendor/libcomplex \
                   current                                        \
                   /path/to/libcomplex-1.1
…
</pre><p>When you run <span class="command"><strong>svn_load_dirs.pl</strong></span>, it
        examines the contents of your existing “<span class="quote">current</span>”
        vendor drop, and compares them with the proposed new vendor
        drop.  In the trivial case, there will be no files that are in
        one version and not the other, and the script will perform the
        new import without incident.  If, however, there are
        discrepancies in the file layouts between versions,
        <span class="command"><strong>svn_load_dirs.pl</strong></span> will ask you how
        to resolve those differences.  For example, you
        will have the opportunity to tell the script that you know
        that the file <code class="filename">math.c</code> in version 1.0 of
        libcomplex was renamed to <code class="filename">arithmetic.c</code> in
        libcomplex 1.1.  Any discrepancies not explained by moves
        are treated as regular additions and deletions.</p><p>The script also accepts a separate configuration file for
        setting properties on files and directories matching a regular
        expression that are <span class="emphasis"><em>added</em></span> to the
        repository.  This configuration file is specified to
        <span class="command"><strong>svn_load_dirs.pl</strong></span> using the
        <code class="option">-p</code> command-line option.  Each line of the
        configuration file is a whitespace-delimited set of two or
        four values: a Perl-style regular expression to match the
        added path against, a control keyword (either
        <code class="literal">break</code> or <code class="literal">cont</code>), and then
        optionally a property name and value.</p><pre class="screen">
\.png$              break   svn:mime-type   image/png
\.jpe?g$            break   svn:mime-type   image/jpeg
\.m3u$              cont    svn:mime-type   audio/x-mpegurl
\.m3u$              break   svn:eol-style   LF
.*                  break   svn:eol-style   native
</pre><p>For each added path, the configured property changes whose
        regular expression matches the path are applied in order,
        unless the control specification is <code class="literal">break</code>
        (which means that no more property changes should be applied
        to that path).  If the control specification is
        <code class="literal">cont</code>—an abbreviation for
        <code class="literal">continue</code>—then matching will continue
        with the next line of the configuration file.</p><p>Any whitespace in the regular expression, property name,
        or property value must be surrounded by either single or
        double quote characters.  You can escape quote characters that
        are not used for wrapping whitespace by preceding them with a
        backslash (<code class="literal">\</code>) character.  The backslash
        escapes only quotes when parsing the configuration file, so do
        not protect any other characters beyond what is necessary for
        the regular expression.</p></div><div class="footnotes"><br /><hr width="100" align="left" /><div class="footnote"><p><sup>[<a id="ftn.id375251" href="#id375251" class="para">26</a>] </sup>And entirely bug-free, of course!</p></div></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="svn.branchmerge.commonpatterns.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="svn.branchmerge.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="svn.branchmerge.summary.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Common Branching Patterns </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> Summary</td></tr></table></div></body></html>