Differences between revisions 1 and 9 (spanning 8 versions)
Revision 1 as of 2008-09-03 16:14:17
Size: 19
Editor: 194
Comment:
Revision 9 as of 2008-09-03 18:06:49
Size: 8480
Editor: 194
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
{{{{#!java This example demonstrates how you can merge changes from trunk to a branch several times without specifying revisions.
What we are going to do here is the following:
 0. Initialize SVNKit to work with file:/// protocol.
 1. Create a repository.
 2. Populate it with some tree.
 3. Make a copy of that tree: /A to /A_copy.
 4. Checkout the entire repository tree to a working copy.
 5. Make some changes to trunk (A). Commit those changes to the repository.
 6. Then merge the changes from trunk (A) to the branch (A_copy).
 7. Then again make some changes to trunk and commit them to the repository.
 8. Again, merge the changes from trunk (A) to the branch (A_copy).
 
This steps are reflected in code comments:
Line 3: Line 15:
{{{#!java
/*
 * ====================================================================
 * Copyright (c) 2004-2008 TMate Software Ltd. All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution. The terms
 * are also available at http://svnkit.com/license.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 * ====================================================================
 */
package org.tmatesoft.svn.examples.wc;

import java.io.File;
import java.io.IOException;
import java.util.Collections;

import org.tmatesoft.svn.core.SVNCommitInfo;
import org.tmatesoft.svn.core.SVNDepth;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNPropertyValue;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNCommitClient;
import org.tmatesoft.svn.core.wc.SVNCopyClient;
import org.tmatesoft.svn.core.wc.SVNCopySource;
import org.tmatesoft.svn.core.wc.SVNDiffClient;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc.SVNRevisionRange;
import org.tmatesoft.svn.core.wc.SVNWCClient;


/**
 * @version 1.2.0
 * @author TMate Software Ltd.
 */
public class Merge {

    /**
     * Pass the absolute path of the base directory where all example data will be created in
     * arg[0]. The sample will create:
     *
     * - arg[0]/exampleRepository - repository with some test data
     * - arg[0]/exampleWC - working copy checked out from exampleRepository
     */
    public static void main (String[] args) {
        //0. initialize SVNKit to work through file:/// protocol
        SamplesUtility.initializeFSFSprotocol();
        
        File baseDirectory = new File(args[0]);
        File reposRoot = new File(baseDirectory, "exampleRepository");
        File wcRoot = new File(baseDirectory, "exampleWC");
        
        try {
            //1. first create a repository
            SamplesUtility.createRepository(reposRoot);
            //2. fill it with data
            SVNCommitInfo info = SamplesUtility.createRepositoryTree(reposRoot);
            //print out new revision info
            System.out.println(info);

            SVNClientManager clientManager = SVNClientManager.newInstance();
            
            SVNURL reposURL = SVNURL.fromFile(reposRoot);

            //3. copy A to A_copy in the repository (url-to-url copy)
            SVNCopyClient copyClient = clientManager.getCopyClient();
            SVNURL A_URL = reposURL.appendPath("A", true);
            SVNURL copyTargetURL = reposURL.appendPath("A_copy", true);
            SVNCopySource copySource = new SVNCopySource(SVNRevision.UNDEFINED, SVNRevision.HEAD, A_URL);
            info = copyClient.doCopy(new SVNCopySource[] { copySource }, copyTargetURL, false, false, true,
                    "copy A to A_copy", null);
            //print out new revision info
            System.out.println(info);
            
            //4. checkout the entire repository tree
            SamplesUtility.checkOutWorkingCopy(reposURL, wcRoot);

            
            //5. now make some changes to the A tree and commit them
            SamplesUtility.writeToFile(new File(wcRoot, "iota"), "New text appended to 'iota'", true);
            SamplesUtility.writeToFile(new File(wcRoot, "A/mu"), "New text in 'mu'", false);
            
            SVNWCClient wcClient = SVNClientManager.newInstance().getWCClient();
            wcClient.doSetProperty(new File(wcRoot, "A/B"), "spam", SVNPropertyValue.create("egg"), false,
                    SVNDepth.EMPTY, null, null);

            //commit local changes
            SVNCommitClient commitClient = clientManager.getCommitClient();
            commitClient.doCommit(new File[] { wcRoot }, false, "committing changes", null, null, false, false, SVNDepth.INFINITY);
            
            //6. now merge changes from trunk to the branch.
            SVNDiffClient diffClient = clientManager.getDiffClient();
            SVNRevisionRange rangeToMerge = new SVNRevisionRange(SVNRevision.create(1), SVNRevision.HEAD);
            
            diffClient.doMerge(A_URL, SVNRevision.HEAD, Collections.singleton(rangeToMerge),
                    new File(wcRoot, "A_copy"), SVNDepth.INFINITY, true, false, false, false);
            
            
            //7. now make some changes to the A tree again and commit them
            //change file contents of iota and A/D/gamma
            SamplesUtility.writeToFile(new File(wcRoot, "iota"), "New text2 appended to 'iota'", true);
            SamplesUtility.writeToFile(new File(wcRoot, "A/D/gamma"), "New text in 'gamma'", false);
            //remove A/C from version control
            wcClient.doDelete(new File(wcRoot, "A/C"), false, true, false);

            //commit local changes
            commitClient.doCommit(new File[] { wcRoot }, false, "committing changes again", null, null, false, false, SVNDepth.INFINITY);

            /* 8. do the same merge call, merge-tracking feature will merge only those revisions
             * which were not merged yet.
             */
            diffClient.doMerge(A_URL, SVNRevision.HEAD, Collections.singleton(rangeToMerge),
                    new File(wcRoot, "A_copy"), SVNDepth.INFINITY, true, false, false, false);
            
        } catch (SVNException svne) {
            System.out.println(svne.getErrorMessage());
            System.exit(1);
        } catch (IOException ioe) {
            ioe.printStackTrace();
            System.exit(1);
        }
    }
}
Line 4: Line 141:

Here are some comments on calling ''doMerge()'' in this example:
 * We use a pegged version of ''doMerge()'' which allows to merge differences between different revisions of the same file.
 * A_URL - URL of the merge source.
 * ''SVNRevision.HEAD'' - [[Peg revision|peg revision]] in which A_URL is valid for sure.
 * We use the entire revision range - from revisio 1 to HEAD not caring of how already merged revisions are skipped - merge-tracking feature will do that for us.
 * Then goes the merge target local path.
 * We use ''SVNDepth.INFINITY'' to recursively merge the whole target tree.
 * We want to merge only related (by history) objects, so the next parameter is ''true''.
 * We do not want our merge to delete any versioned files containing local edits or unversioned ones, so passing ''false''.
 * We do want a real merge to perform, not a just the final status of a potential merge, so passing ''false''.
 * We do wand a real merge to perform, not just to record mergeinfo without bringing real changes to A_copy.

Each merge operation in this example is equivalent to the following command line client' command:
{{{
svn merge file:///home/alex/workspace/tmp/exampleRepository/A /home/alex/workspace/exampleWC/A_copy
}}}

After the first merge, if you run 'svn status' in the working copy you should see this report:

{{{
alex@UFO:~/workspace/tmp/exampleWC$ $JSVN_PATH stat
 M A_copy
 M A_copy/B
M A_copy/mu
}}}

And 'svn pg svn:mergeinfo .' in A_copy gives:

{{{
alex@UFO:~/workspace/tmp/exampleWC/A_copy$ $JSVN_PATH pg svn:mergeinfo .
/A:2-3
}}}

After the second merge the status report will look like this:

{{{
alex@UFO:~/workspace/tmp/exampleWC$ $JSVN_PATH stat
 M A_copy
D A_copy/C
M A_copy/D/gamma
}}}

and propget report like this:
{{{
alex@UFO:~/workspace/tmp/exampleWC/A_copy$ $JSVN_PATH pg svn:mergeinfo .
/A:2-4
}}}

This example demonstrates how you can merge changes from trunk to a branch several times without specifying revisions. What we are going to do here is the following:

  1. Initialize SVNKit to work with file:/// protocol.

  2. Create a repository.
  3. Populate it with some tree.
  4. Make a copy of that tree: /A to /A_copy.
  5. Checkout the entire repository tree to a working copy.
  6. Make some changes to trunk (A). Commit those changes to the repository.
  7. Then merge the changes from trunk (A) to the branch (A_copy).
  8. Then again make some changes to trunk and commit them to the repository.
  9. Again, merge the changes from trunk (A) to the branch (A_copy).

This steps are reflected in code comments:

   1 /*
   2  * ====================================================================
   3  * Copyright (c) 2004-2008 TMate Software Ltd.  All rights reserved.
   4  *
   5  * This software is licensed as described in the file COPYING, which
   6  * you should have received as part of this distribution.  The terms
   7  * are also available at http://svnkit.com/license.html.
   8  * If newer versions of this license are posted there, you may use a
   9  * newer version instead, at your option.
  10  * ====================================================================
  11  */
  12 package org.tmatesoft.svn.examples.wc;
  13 
  14 import java.io.File;
  15 import java.io.IOException;
  16 import java.util.Collections;
  17 
  18 import org.tmatesoft.svn.core.SVNCommitInfo;
  19 import org.tmatesoft.svn.core.SVNDepth;
  20 import org.tmatesoft.svn.core.SVNException;
  21 import org.tmatesoft.svn.core.SVNPropertyValue;
  22 import org.tmatesoft.svn.core.SVNURL;
  23 import org.tmatesoft.svn.core.wc.SVNClientManager;
  24 import org.tmatesoft.svn.core.wc.SVNCommitClient;
  25 import org.tmatesoft.svn.core.wc.SVNCopyClient;
  26 import org.tmatesoft.svn.core.wc.SVNCopySource;
  27 import org.tmatesoft.svn.core.wc.SVNDiffClient;
  28 import org.tmatesoft.svn.core.wc.SVNRevision;
  29 import org.tmatesoft.svn.core.wc.SVNRevisionRange;
  30 import org.tmatesoft.svn.core.wc.SVNWCClient;
  31 
  32 
  33 /**
  34  * @version 1.2.0
  35  * @author  TMate Software Ltd.
  36  */
  37 public class Merge {
  38 
  39     /**
  40      * Pass the absolute path of the base directory where all example data will be created in 
  41      * arg[0]. The sample will create:
  42      *  
  43      *  - arg[0]/exampleRepository - repository with some test data
  44      *  - arg[0]/exampleWC         - working copy checked out from exampleRepository
  45      */
  46     public static void main (String[] args) {
  47         //0. initialize SVNKit to work through file:/// protocol
  48         SamplesUtility.initializeFSFSprotocol();
  49         
  50         File baseDirectory = new File(args[0]);
  51         File reposRoot = new File(baseDirectory, "exampleRepository");
  52         File wcRoot = new File(baseDirectory, "exampleWC");
  53         
  54         try {
  55             //1. first create a repository
  56             SamplesUtility.createRepository(reposRoot);
  57             //2. fill it with data
  58             SVNCommitInfo info = SamplesUtility.createRepositoryTree(reposRoot);
  59             //print out new revision info
  60             System.out.println(info);
  61 
  62             SVNClientManager clientManager = SVNClientManager.newInstance();
  63             
  64             SVNURL reposURL = SVNURL.fromFile(reposRoot);
  65 
  66             //3. copy A to A_copy in the repository (url-to-url copy)
  67             SVNCopyClient copyClient = clientManager.getCopyClient();
  68             SVNURL A_URL = reposURL.appendPath("A", true);
  69             SVNURL copyTargetURL = reposURL.appendPath("A_copy", true);
  70             SVNCopySource copySource = new SVNCopySource(SVNRevision.UNDEFINED, SVNRevision.HEAD, A_URL); 
  71             info = copyClient.doCopy(new SVNCopySource[] { copySource }, copyTargetURL, false, false, true, 
  72                     "copy A to A_copy", null);
  73             //print out new revision info
  74             System.out.println(info);
  75             
  76             //4. checkout the entire repository tree
  77             SamplesUtility.checkOutWorkingCopy(reposURL, wcRoot);
  78 
  79             
  80             //5. now make some changes to the A tree and commit them
  81             SamplesUtility.writeToFile(new File(wcRoot, "iota"), "New text appended to 'iota'", true);
  82             SamplesUtility.writeToFile(new File(wcRoot, "A/mu"), "New text in 'mu'", false);
  83             
  84             SVNWCClient wcClient = SVNClientManager.newInstance().getWCClient();
  85             wcClient.doSetProperty(new File(wcRoot, "A/B"), "spam", SVNPropertyValue.create("egg"), false, 
  86                     SVNDepth.EMPTY, null, null);
  87 
  88             //commit local changes
  89             SVNCommitClient commitClient = clientManager.getCommitClient();
  90             commitClient.doCommit(new File[] { wcRoot }, false, "committing changes", null, null, false, false, SVNDepth.INFINITY);
  91             
  92             //6. now merge changes from trunk to the branch.
  93             SVNDiffClient diffClient = clientManager.getDiffClient();
  94             SVNRevisionRange rangeToMerge = new SVNRevisionRange(SVNRevision.create(1), SVNRevision.HEAD);
  95             
  96             diffClient.doMerge(A_URL, SVNRevision.HEAD, Collections.singleton(rangeToMerge), 
  97                     new File(wcRoot, "A_copy"), SVNDepth.INFINITY, true, false, false, false);
  98             
  99             
 100             //7. now make some changes to the A tree again and commit them
 101             //change file contents of iota and A/D/gamma
 102             SamplesUtility.writeToFile(new File(wcRoot, "iota"), "New text2 appended to 'iota'", true);
 103             SamplesUtility.writeToFile(new File(wcRoot, "A/D/gamma"), "New text in 'gamma'", false);
 104             //remove A/C from version control
 105             wcClient.doDelete(new File(wcRoot, "A/C"), false, true, false);
 106 
 107             //commit local changes
 108             commitClient.doCommit(new File[] { wcRoot }, false, "committing changes again", null, null, false, false, SVNDepth.INFINITY);
 109 
 110             /* 8. do the same merge call, merge-tracking feature will merge only those revisions
 111              * which were not merged yet.
 112              */ 
 113             diffClient.doMerge(A_URL, SVNRevision.HEAD, Collections.singleton(rangeToMerge), 
 114                     new File(wcRoot, "A_copy"), SVNDepth.INFINITY, true, false, false, false);
 115             
 116         } catch (SVNException svne) {
 117             System.out.println(svne.getErrorMessage());
 118             System.exit(1);
 119         } catch (IOException ioe) {
 120             ioe.printStackTrace();
 121             System.exit(1);
 122         }
 123     }
 124 }

Here are some comments on calling doMerge() in this example:

  • We use a pegged version of doMerge() which allows to merge differences between different revisions of the same file.

  • A_URL - URL of the merge source.
  • SVNRevision.HEAD - peg revision in which A_URL is valid for sure.

  • We use the entire revision range - from revisio 1 to HEAD not caring of how already merged revisions are skipped - merge-tracking feature will do that for us.
  • Then goes the merge target local path.
  • We use SVNDepth.INFINITY to recursively merge the whole target tree.

  • We want to merge only related (by history) objects, so the next parameter is true.

  • We do not want our merge to delete any versioned files containing local edits or unversioned ones, so passing false.

  • We do want a real merge to perform, not a just the final status of a potential merge, so passing false.

  • We do wand a real merge to perform, not just to record mergeinfo without bringing real changes to A_copy.

Each merge operation in this example is equivalent to the following command line client' command:

svn merge file:///home/alex/workspace/tmp/exampleRepository/A /home/alex/workspace/exampleWC/A_copy

After the first merge, if you run 'svn status' in the working copy you should see this report:

alex@UFO:~/workspace/tmp/exampleWC$ $JSVN_PATH stat
 M     A_copy
 M     A_copy/B
M      A_copy/mu

And 'svn pg svn:mergeinfo .' in A_copy gives:

alex@UFO:~/workspace/tmp/exampleWC/A_copy$ $JSVN_PATH pg svn:mergeinfo .
/A:2-3

After the second merge the status report will look like this:

alex@UFO:~/workspace/tmp/exampleWC$ $JSVN_PATH stat
 M     A_copy
D      A_copy/C
M      A_copy/D/gamma

and propget report like this:

alex@UFO:~/workspace/tmp/exampleWC/A_copy$ $JSVN_PATH pg svn:mergeinfo .
/A:2-4

Merging from trunk to a branch (last edited 2008-09-04 15:57:55 by 194)