Differences between revisions 1 and 2
Revision 1 as of 2008-09-04 15:54:46
Size: 250
Editor: 194
Comment:
Revision 2 as of 2008-09-04 16:01:48
Size: 9013
Editor: 194
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
= Performing 'svn merge URL_TO_TRUNK BRANCH_WC' and handling conflicts with SVNKit =
Line 2: Line 3:
you can handle conflicts programmatically using [[ISVNConflictHandler]].
Line 3: Line 5:
you can handle conflicts programmatically using [[ISVNConflictHandler]]. {{{#!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.internal.wc.DefaultSVNOptions;
import org.tmatesoft.svn.core.wc.ISVNConflictHandler;
import org.tmatesoft.svn.core.wc.SVNClientManager;
import org.tmatesoft.svn.core.wc.SVNCommitClient;
import org.tmatesoft.svn.core.wc.SVNConflictChoice;
import org.tmatesoft.svn.core.wc.SVNConflictDescription;
import org.tmatesoft.svn.core.wc.SVNConflictReason;
import org.tmatesoft.svn.core.wc.SVNConflictResult;
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.SVNMergeFileSet;
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 ConflictedMerge {
    /**
     * 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) {
        //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 {
            //first create a repository and fill it with data
            SamplesUtility.createRepository(reposRoot);
            SVNCommitInfo info = SamplesUtility.createRepositoryTree(reposRoot);
            //print out new revision info
            System.out.println(info);

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

            //copy A to A_copy in 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);
            
            //checkout the entire repository tree
            SamplesUtility.checkOutWorkingCopy(reposURL, wcRoot);

            
            //now make some changes to the A tree
            SamplesUtility.writeToFile(new File(wcRoot, "A/B/lambda"), "New text appended to 'lambda'", 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);
            
            //now diff the base revision of the working copy against the repository
            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.UNKNOWN, true, false, false, false);
            
            //now make some changes to the A tree again
            //change file contents of iota and A/D/gamma
            SamplesUtility.writeToFile(new File(wcRoot, "A/B/lambda"), "New text2 appended to 'lambda'", true);
            SamplesUtility.writeToFile(new File(wcRoot, "A/D/gamma"), "New text in 'gamma'", false);

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

            //now make some local changes to the A_copy tree
            //change file contents of iota and A/D/gamma
            SamplesUtility.writeToFile(new File(wcRoot, "A_copy/B/lambda"), "New text in copied 'lambda'", true);
            SamplesUtility.writeToFile(new File(wcRoot, "A_copy/D/gamma"), "New text in copied 'gamma'", false);

            /*
             * Since we provided no custom ISVNOptions implementation to SVNClientManager, our
             * manager uses DefaultSVNOptions, which is set to all SVN*Client classes which the
             * manager produces. So, we can cast ISVNOptions to DefaultSVNOptions.
             */
            DefaultSVNOptions options = (DefaultSVNOptions) diffClient.getOptions();
            //This way we set a conflict handler which will automatically resolve conflicts for those
            //cases that we would like
            options.setConflictHandler(new ConflictResolverHandler());
            
            /* do the same merge call, merge-tracking feature will merge only those revisions
             * which were not still merged.
             */
            diffClient.doMerge(A_URL, SVNRevision.HEAD, Collections.singleton(rangeToMerge),
                    new File(wcRoot, "A_copy"), SVNDepth.UNKNOWN, true, false, false, false);
            
        } catch (SVNException svne) {
            System.out.println(svne.getErrorMessage());
            System.exit(1);
        } catch (IOException ioe) {
            ioe.printStackTrace();
            System.exit(1);
        }
    }

    /**
     * Conflict resolver which always selects the local version of a file.
     *
     * @version 1.2.0
     * @author TMate Software Ltd.
     */
    private static class ConflictResolverHandler implements ISVNConflictHandler {
    
        public SVNConflictResult handleConflict(SVNConflictDescription conflictDescription) throws SVNException {
            SVNConflictReason reason = conflictDescription.getConflictReason();
            SVNMergeFileSet mergeFiles = conflictDescription.getMergeFiles();
            
            SVNConflictChoice choice = SVNConflictChoice.THEIRS_FULL;
            if (reason == SVNConflictReason.EDITED) {
                //If the reason why conflict occurred is local edits, chose local version of the file
                //Otherwise the repository version of the file will be chosen.
                choice = SVNConflictChoice.MINE_FULL;
            }
            System.out.println("Automatically resolving conflict for " + mergeFiles.getWCFile() +
                    ", choosing " + (choice == SVNConflictChoice.MINE_FULL ? "local file" : "repository file"));
            return new SVNConflictResult(choice, mergeFiles.getResultFile());
        }
    
    }
}
}}}


When you run the program you will see an output similar to this one:

{{{
r1 by 'alex' at Thu Sep 04 17:44:53 CEST 2008
r2 by 'alex' at Thu Sep 04 17:44:53 CEST 2008
Automatically resolving conflict for /home/alex/workspace/tmp/exampleWC/A_copy/B/lambda, choosing local file
Automatically resolving conflict for /home/alex/workspace/tmp/exampleWC/A_copy/D/gamma, choosing local file
}}}

Performing 'svn merge URL_TO_TRUNK BRANCH_WC' and handling conflicts with SVNKit

This example is similar to Merging from trunk to a branch except for the second merge to the branch working copy produces a conflict. In this example we demonstrate how you can handle conflicts programmatically using ISVNConflictHandler.

   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.internal.wc.DefaultSVNOptions;
  24 import org.tmatesoft.svn.core.wc.ISVNConflictHandler;
  25 import org.tmatesoft.svn.core.wc.SVNClientManager;
  26 import org.tmatesoft.svn.core.wc.SVNCommitClient;
  27 import org.tmatesoft.svn.core.wc.SVNConflictChoice;
  28 import org.tmatesoft.svn.core.wc.SVNConflictDescription;
  29 import org.tmatesoft.svn.core.wc.SVNConflictReason;
  30 import org.tmatesoft.svn.core.wc.SVNConflictResult;
  31 import org.tmatesoft.svn.core.wc.SVNCopyClient;
  32 import org.tmatesoft.svn.core.wc.SVNCopySource;
  33 import org.tmatesoft.svn.core.wc.SVNDiffClient;
  34 import org.tmatesoft.svn.core.wc.SVNMergeFileSet;
  35 import org.tmatesoft.svn.core.wc.SVNRevision;
  36 import org.tmatesoft.svn.core.wc.SVNRevisionRange;
  37 import org.tmatesoft.svn.core.wc.SVNWCClient;
  38 
  39 
  40 /**
  41  * @version 1.2.0
  42  * @author  TMate Software Ltd.
  43  */
  44 public class ConflictedMerge {
  45     /**
  46      * Pass the absolute path of the base directory where all example data will be created in 
  47      * arg[0]. The sample will create:
  48      *  
  49      *  - arg[0]/exampleRepository - repository with some test data
  50      *  - arg[0]/exampleWC         - working copy checked out from exampleRepository
  51      */
  52     public static void main (String[] args) {
  53         //initialize SVNKit to work through file:/// protocol
  54         SamplesUtility.initializeFSFSprotocol();
  55         
  56         File baseDirectory = new File(args[0]);
  57         File reposRoot = new File(baseDirectory, "exampleRepository");
  58         File wcRoot = new File(baseDirectory, "exampleWC");
  59         
  60         try {
  61             //first create a repository and fill it with data
  62             SamplesUtility.createRepository(reposRoot);
  63             SVNCommitInfo info = SamplesUtility.createRepositoryTree(reposRoot);
  64             //print out new revision info
  65             System.out.println(info);
  66 
  67             SVNClientManager clientManager = SVNClientManager.newInstance();
  68             
  69             SVNURL reposURL = SVNURL.fromFile(reposRoot);
  70 
  71             //copy A to A_copy in repository (url-to-url copy)
  72             SVNCopyClient copyClient = clientManager.getCopyClient();
  73             SVNURL A_URL = reposURL.appendPath("A", true);
  74             SVNURL copyTargetURL = reposURL.appendPath("A_copy", true);
  75             SVNCopySource copySource = new SVNCopySource(SVNRevision.UNDEFINED, SVNRevision.HEAD, A_URL); 
  76             info = copyClient.doCopy(new SVNCopySource[] { copySource }, copyTargetURL, false, false, true, 
  77                     "copy A to A_copy", null);
  78             //print out new revision info
  79             System.out.println(info);
  80             
  81             //checkout the entire repository tree
  82             SamplesUtility.checkOutWorkingCopy(reposURL, wcRoot);
  83 
  84             
  85             //now make some changes to the A tree
  86             SamplesUtility.writeToFile(new File(wcRoot, "A/B/lambda"), "New text appended to 'lambda'", true);
  87             SamplesUtility.writeToFile(new File(wcRoot, "A/mu"), "New text in 'mu'", false);
  88             
  89             SVNWCClient wcClient = SVNClientManager.newInstance().getWCClient();
  90             wcClient.doSetProperty(new File(wcRoot, "A/B"), "spam", SVNPropertyValue.create("egg"), false, 
  91                     SVNDepth.EMPTY, null, null);
  92 
  93             //commit local changes
  94             SVNCommitClient commitClient = clientManager.getCommitClient();
  95             commitClient.doCommit(new File[] { wcRoot }, false, "committing changes", null, null, false, false, SVNDepth.INFINITY);
  96             
  97             //now diff the base revision of the working copy against the repository
  98             SVNDiffClient diffClient = clientManager.getDiffClient();
  99             SVNRevisionRange rangeToMerge = new SVNRevisionRange(SVNRevision.create(1), SVNRevision.HEAD);
 100             
 101             diffClient.doMerge(A_URL, SVNRevision.HEAD, Collections.singleton(rangeToMerge), 
 102                     new File(wcRoot, "A_copy"), SVNDepth.UNKNOWN, true, false, false, false);
 103             
 104             //now make some changes to the A tree again
 105             //change file contents of iota and A/D/gamma
 106             SamplesUtility.writeToFile(new File(wcRoot, "A/B/lambda"), "New text2 appended to 'lambda'", true);
 107             SamplesUtility.writeToFile(new File(wcRoot, "A/D/gamma"), "New text in 'gamma'", false);
 108 
 109             //commit local changes
 110             commitClient.doCommit(new File[] { wcRoot }, false, "committing changes again", null, null, false, false, SVNDepth.INFINITY);
 111 
 112             //now make some local changes to the A_copy tree 
 113             //change file contents of iota and A/D/gamma
 114             SamplesUtility.writeToFile(new File(wcRoot, "A_copy/B/lambda"), "New text in copied 'lambda'", true);
 115             SamplesUtility.writeToFile(new File(wcRoot, "A_copy/D/gamma"), "New text in copied 'gamma'", false);
 116 
 117             /*
 118              * Since we provided no custom ISVNOptions implementation to SVNClientManager, our 
 119              * manager uses DefaultSVNOptions, which is set to all SVN*Client classes which the 
 120              * manager produces. So, we can cast ISVNOptions to DefaultSVNOptions.
 121              */
 122             DefaultSVNOptions options = (DefaultSVNOptions) diffClient.getOptions();
 123             //This way we set a conflict handler which will automatically resolve conflicts for those 
 124             //cases that we would like
 125             options.setConflictHandler(new ConflictResolverHandler());
 126             
 127             /* do the same merge call, merge-tracking feature will merge only those revisions
 128              * which were not still merged.
 129              */ 
 130             diffClient.doMerge(A_URL, SVNRevision.HEAD, Collections.singleton(rangeToMerge), 
 131                     new File(wcRoot, "A_copy"), SVNDepth.UNKNOWN, true, false, false, false);
 132             
 133         } catch (SVNException svne) {
 134             System.out.println(svne.getErrorMessage());
 135             System.exit(1);
 136         } catch (IOException ioe) {
 137             ioe.printStackTrace();
 138             System.exit(1);
 139         }
 140     }
 141 
 142     /**
 143      * Conflict resolver which always selects the local version of a file.
 144      * 
 145      * @version 1.2.0
 146      * @author  TMate Software Ltd.
 147      */
 148     private static class ConflictResolverHandler implements ISVNConflictHandler {
 149     
 150         public SVNConflictResult handleConflict(SVNConflictDescription conflictDescription) throws SVNException {
 151             SVNConflictReason reason = conflictDescription.getConflictReason();
 152             SVNMergeFileSet mergeFiles = conflictDescription.getMergeFiles();
 153             
 154             SVNConflictChoice choice = SVNConflictChoice.THEIRS_FULL;
 155             if (reason == SVNConflictReason.EDITED) {
 156                 //If the reason why conflict occurred is local edits, chose local version of the file
 157                 //Otherwise the repository version of the file will be chosen.
 158                 choice = SVNConflictChoice.MINE_FULL;
 159             }
 160             System.out.println("Automatically resolving conflict for " + mergeFiles.getWCFile() + 
 161                     ", choosing " + (choice == SVNConflictChoice.MINE_FULL ? "local file" : "repository file"));
 162             return new SVNConflictResult(choice, mergeFiles.getResultFile()); 
 163         }   
 164     
 165     }
 166 }

When you run the program you will see an output similar to this one:

r1 by 'alex' at Thu Sep 04 17:44:53 CEST 2008
r2 by 'alex' at Thu Sep 04 17:44:53 CEST 2008
Automatically resolving conflict for /home/alex/workspace/tmp/exampleWC/A_copy/B/lambda, choosing local file
Automatically resolving conflict for /home/alex/workspace/tmp/exampleWC/A_copy/D/gamma, choosing local file

Merging from trunk to a branch with conflicts (last edited 2008-09-04 16:40:51 by 194)