You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2010/09/29 17:38:12 UTC

svn commit: r1002684 [1/2] - in /subversion/branches/1.6.x-issue3646: ./ subversion/bindings/javahl/native/ subversion/bindings/swig/ruby/svn/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_fs_fs/ subversion/libsvn_ra_neon/ sub...

Author: stsp
Date: Wed Sep 29 15:38:10 2010
New Revision: 1002684

URL: http://svn.apache.org/viewvc?rev=1002684&view=rev
Log:
Sync the 1.6.x-issue3646 branch with the 1.6.x branch.

* subversion/tests/cmdline/merge_tests.py: Resolve conflicts in this file.

Modified:
    subversion/branches/1.6.x-issue3646/   (props changed)
    subversion/branches/1.6.x-issue3646/CHANGES   (props changed)
    subversion/branches/1.6.x-issue3646/STATUS
    subversion/branches/1.6.x-issue3646/subversion/bindings/javahl/native/SVNAdmin.cpp
    subversion/branches/1.6.x-issue3646/subversion/bindings/swig/ruby/svn/core.rb
    subversion/branches/1.6.x-issue3646/subversion/include/private/svn_mergeinfo_private.h
    subversion/branches/1.6.x-issue3646/subversion/include/private/svn_opt_private.h
    subversion/branches/1.6.x-issue3646/subversion/libsvn_client/commit.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_client/export.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_client/merge.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs.h
    subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/lock.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_neon/fetch.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_neon/util.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_serf/commit.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_serf/ra_serf.h
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_serf/update.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_serf/util.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_svn/editorp.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_svn/marshal.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_svn/ra_svn.h
    subversion/branches/1.6.x-issue3646/subversion/libsvn_subr/mergeinfo.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_subr/opt.c
    subversion/branches/1.6.x-issue3646/subversion/libsvn_wc/props.c
    subversion/branches/1.6.x-issue3646/subversion/mod_dav_svn/reports/update.c
    subversion/branches/1.6.x-issue3646/subversion/po/zh_CN.po
    subversion/branches/1.6.x-issue3646/subversion/svn/export-cmd.c
    subversion/branches/1.6.x-issue3646/subversion/svn/merge-cmd.c
    subversion/branches/1.6.x-issue3646/subversion/tests/cmdline/export_tests.py
    subversion/branches/1.6.x-issue3646/subversion/tests/cmdline/merge_authz_tests.py
    subversion/branches/1.6.x-issue3646/subversion/tests/cmdline/merge_tests.py   (contents, props changed)

Propchange: subversion/branches/1.6.x-issue3646/
------------------------------------------------------------------------------
    (empty)

Propchange: subversion/branches/1.6.x-issue3646/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Sep 29 15:38:10 2010
@@ -1,10 +1,12 @@
 /subversion/branches/1.5.x-r30215:870312
+/subversion/branches/1.6.x:957327-1002678
 /subversion/branches/1.6.x-1.6.8-serfassertion:900822-900868
 /subversion/branches/1.6.x-3242-partial-fixes:931279-932637
 /subversion/branches/1.6.x-UNC-paths:876471-876545
 /subversion/branches/1.6.x-dirent-basename:876130-876262
 /subversion/branches/1.6.x-future-proof:880259-884209
 /subversion/branches/1.6.x-issue-3242-partial:916088-923778
+/subversion/branches/1.6.x-issue3242-reintegrate:954549-1001798
 /subversion/branches/1.6.x-issue3303:950948-955336
 /subversion/branches/1.6.x-issue3390:907042-927863
 /subversion/branches/1.6.x-issue3432:878598-924025
@@ -16,8 +18,11 @@
 /subversion/branches/1.6.x-issue3573:906488-923765
 /subversion/branches/1.6.x-issue3605:923668-923887
 /subversion/branches/1.6.x-issue3623:952794-956049
+/subversion/branches/1.6.x-issue3648:964172-1001805
 /subversion/branches/1.6.x-issue3651:952977-954985
 /subversion/branches/1.6.x-issue3654:953882-955338
+/subversion/branches/1.6.x-issue3683:965785-988062
+/subversion/branches/1.6.x-issue3700:991967-997279
 /subversion/branches/1.6.x-no-svn_uri:876360-876415
 /subversion/branches/1.6.x-r36178:877876-877884
 /subversion/branches/1.6.x-r36252:876328-876788
@@ -37,6 +42,7 @@
 /subversion/branches/1.6.x-r39557:879668-879907
 /subversion/branches/1.6.x-r39887:880024-880066
 /subversion/branches/1.6.x-r40452:880530-890996
+/subversion/branches/1.6.x-r879757:987687-999407
 /subversion/branches/1.6.x-r889840:889888-890974
 /subversion/branches/1.6.x-r891672:891676-923748
 /subversion/branches/1.6.x-r892050:923839-923856
@@ -48,6 +54,10 @@
 /subversion/branches/1.6.x-r933299:933310-934492
 /subversion/branches/1.6.x-r935631:952683-955333
 /subversion/branches/1.6.x-r935996:936212-952816
+/subversion/branches/1.6.x-r979045:987702-997248
+/subversion/branches/1.6.x-r980811:980813-987709
+/subversion/branches/1.6.x-r981921:981922-997253
+/subversion/branches/1.6.x-r997457:997808-1002642
 /subversion/branches/1.6.x-wc-ng-check-override:910213-923776
 /subversion/branches/1.6.x-wc-ng-error:929379-929636
 /subversion/branches/bdb-reverse-deltas:872050-872529
@@ -70,6 +80,7 @@
 /subversion/branches/kwallet:870785-871314
 /subversion/branches/log-g-performance:870941-871032
 /subversion/branches/merge-skips-obstructions:874525-874615
+/subversion/branches/performance:983766,984927
 /subversion/branches/reintegrate-improvements:873853-874164
 /subversion/branches/subtree-mergeinfo:876855
 /subversion/branches/svn-mergeinfo-enhancements:870119-870195,870197-870288
@@ -81,4 +92,4 @@
 /subversion/branches/tc_url_rev:874351-874483
 /subversion/branches/tree-conflicts:868291-873154
 /subversion/branches/tree-conflicts-notify:873926-874008
-/subversion/trunk:875965,875968,876004,876012,876017,876019,876022,876024,876032,876041-876042,876048,876051,876055-876056,876059,876083,876091,876097,876101,876104,876109,876123-876125,876129,876132,876138,876160,876167,876175,876180,876185,876205,876223-876225,876230,876233,876245,876252,876256,876283,876287,876312,876326-876327,876330,876366,876372,876374,876376,876383,876386,876442,876456-876457,876462-876464,876467,876469,876480,876486,876495-876497,876516-876518,876524,876526,876583,876601,876614,876628,876633,876641,876659,876687,876689,876705,876715,876726,876760,876763,876794,876804,876815-876816,876821,876825,876837,876840-876841,876843,876849,876857-876858,876862,876873,876890,876897,876905,876908,876925,876931,876934,876948-876949,876953,876987,876993,877011,877014,877016,877028-877029,877038,877119,877127,877146,877157,877191,877195,877203,877211,877230,877234,877237,877243,877249,877259,877261,877304,877319,877407,877437,877441-877442,877453,877459,877472,87754
 4,877553,877565,877568,877573,877593,877595,877597,877601,877612,877665,877667,877681,877692,877696,877701,877720,877730,877784,877793,877797,877809,877815,877819,877821,877842,877848,877853,877867,877869,877873,877901,877909,877916,877931,877942,877953,877964,877968,877970,877981-877982,878005,878013,878015,878020,878046,878053,878062,878074,878080,878089,878091,878093,878095,878127,878129,878131,878142,878173-878176,878216,878240,878242,878255,878269,878272,878279,878296-878297,878303,878321,878335,878338,878341,878343,878353,878364,878367-878368,878385,878399,878423,878426,878447,878462,878484,878491,878498,878532,878595,878646,878659,878673,878682-878683,878690-878691,878693,878723,878760-878761,878873,878875,878877,878879,878905,878910-878911,878915-878916,878924-878925,878946,878949,878955,878960,878970,878981,879001,879033,879056,879074,879076,879081-879082,879093,879105,879126,879148,879170,879198-879199,879201,879271,879293,879357,879375-879376,879403,879631,879635-
 879636,879688,879709-879711,879747,879902,879916,879954,879961,879966,879971,880082,880095,880105,880162,880226,880274-880275,880370,880450,880461,880474,880525-880526,880552,881905,884842,886164,886197,888715,888979,889081,889840,891672,892050,892085,895514,895653,896522,896915,898048,898963,899826,899828,900797,901304,901752,902093,904301,904394,904594,905303,905326,906256,906305,906587,908980-908981,917640,918211,922516,923389,923391,926151,926167,927323,927328,931209,931211,931392,931568,932942,933299,934599,934603,935631,935992,935996,937610,939375-939376,944635,948512,949307,950931,950933,951753,952992,953317
+/subversion/trunk:875965,875968,876004,876012,876017,876019,876022,876024,876032,876041-876042,876048,876051,876055-876056,876059,876083,876091,876097,876101,876104,876109,876123-876125,876129,876132,876138,876160,876167,876175,876180,876185,876205,876223-876225,876230,876233,876245,876252,876256,876283,876287,876312,876326-876327,876330,876366,876372,876374,876376,876383,876386,876442,876456-876457,876462-876464,876467,876469,876480,876486,876495-876497,876516-876518,876524,876526,876583,876601,876614-876615,876628,876633,876641,876659,876687,876689,876705,876715,876726,876760,876763,876794,876804,876815-876816,876821,876825,876837,876840-876841,876843,876849,876857-876858,876862,876873,876890,876897,876905,876908,876925,876931,876934,876948-876949,876953,876987,876993,877011,877014,877016,877028-877029,877038,877119,877127,877146,877157,877191,877195,877203,877211,877230,877234,877237,877243,877249,877259,877261,877304,877319,877407,877437,877441-877442,877453,877459,87747
 2,877544,877553,877565,877568,877573,877593,877595,877597,877601,877612,877665,877667,877681,877692,877696,877701,877720,877730,877784,877793,877797,877809,877815,877819,877821,877842,877848,877853,877867,877869,877873,877901,877909,877916,877931,877942,877953,877964,877968,877970,877981-877982,878005,878013,878015,878020,878046,878053,878062,878074,878080,878089,878091,878093,878095,878127,878129,878131,878142,878173-878176,878216,878240,878242,878255,878269,878272,878279,878296-878297,878303,878321,878335,878338,878341,878343,878353,878364,878367-878368,878385,878399,878423,878426,878447,878462,878484,878491,878498,878532,878595,878646,878659,878673,878682-878683,878690-878691,878693,878723,878760-878761,878873,878875,878877,878879,878905,878910-878911,878915-878916,878924-878925,878946,878949,878955,878960,878970,878981,879001,879033,879056,879074,879076,879081-879082,879093,879105,879126,879148,879170,879198-879199,879201,879271,879293,879357,879375-879376,879403,879631,
 879635-879636,879688,879709-879711,879747,879902,879916,879954,879961,879966,879971,880082,880095,880105,880162,880226,880274-880275,880370,880450,880461,880474,880525-880526,880552,881905,884842,886164,886197,888715,888979,889081,889840,891672,892050,892085,895514,895653,896522,896915,898048,898963,899826,899828,900797,901304,901752,902093,904301,904394,904594,905303,905326,906256,906305,906587,908980-908981,917640,918211,922516,923389,923391,926151,926167,927323,927328,931209,931211,931392,931568,932942,933299,934599,934603,935631,935992,935996,937610,939375-939376,944635,945350,946767,948512,948916,949307,950931,950933,951753,952992,953317,955369,957507,958024,959004,959760,961055,961970,964167,964767,965405,965469,965508,979045,979429,980811,981449,981921,984928,984931,997457,997466

Propchange: subversion/branches/1.6.x-issue3646/CHANGES
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Sep 29 15:38:10 2010
@@ -1,10 +1,12 @@
 /subversion/branches/1.5.x-r30215/CHANGES:870312
+/subversion/branches/1.6.x/CHANGES:957327-1002678
 /subversion/branches/1.6.x-1.6.8-serfassertion/CHANGES:900822-900868
 /subversion/branches/1.6.x-3242-partial-fixes/CHANGES:931279-932637
 /subversion/branches/1.6.x-UNC-paths/CHANGES:876471-876545
 /subversion/branches/1.6.x-dirent-basename/CHANGES:876130-876262
 /subversion/branches/1.6.x-future-proof/CHANGES:880259-884209
 /subversion/branches/1.6.x-issue-3242-partial/CHANGES:916088-923778
+/subversion/branches/1.6.x-issue3242-reintegrate/CHANGES:954549-1001798
 /subversion/branches/1.6.x-issue3303/CHANGES:950948-955336
 /subversion/branches/1.6.x-issue3390/CHANGES:907042-927863
 /subversion/branches/1.6.x-issue3432/CHANGES:878598-924025
@@ -16,8 +18,11 @@
 /subversion/branches/1.6.x-issue3573/CHANGES:906488-923765
 /subversion/branches/1.6.x-issue3605/CHANGES:923668-923887
 /subversion/branches/1.6.x-issue3623/CHANGES:952794-956049
+/subversion/branches/1.6.x-issue3648/CHANGES:964172-1001805
 /subversion/branches/1.6.x-issue3651/CHANGES:952977-954985
 /subversion/branches/1.6.x-issue3654/CHANGES:953882-955338
+/subversion/branches/1.6.x-issue3683/CHANGES:965785-988062
+/subversion/branches/1.6.x-issue3700/CHANGES:991967-997279
 /subversion/branches/1.6.x-no-svn_uri/CHANGES:876360-876415
 /subversion/branches/1.6.x-r36178/CHANGES:877876-877884
 /subversion/branches/1.6.x-r36252/CHANGES:876328-876788
@@ -37,6 +42,7 @@
 /subversion/branches/1.6.x-r39557/CHANGES:879668-879907
 /subversion/branches/1.6.x-r39887/CHANGES:880024-880066
 /subversion/branches/1.6.x-r40452/CHANGES:880530-890996
+/subversion/branches/1.6.x-r879757/CHANGES:987687-999407
 /subversion/branches/1.6.x-r889840/CHANGES:889888-890974
 /subversion/branches/1.6.x-r891672/CHANGES:891676-923748
 /subversion/branches/1.6.x-r892050/CHANGES:923839-923856
@@ -48,6 +54,10 @@
 /subversion/branches/1.6.x-r933299/CHANGES:933310-934492
 /subversion/branches/1.6.x-r935631/CHANGES:952683-955333
 /subversion/branches/1.6.x-r935996/CHANGES:936212-952816
+/subversion/branches/1.6.x-r979045/CHANGES:987702-997248
+/subversion/branches/1.6.x-r980811/CHANGES:980813-987709
+/subversion/branches/1.6.x-r981921/CHANGES:981922-997253
+/subversion/branches/1.6.x-r997457/CHANGES:997808-1002642
 /subversion/branches/1.6.x-wc-ng-check-override/CHANGES:910213-923776
 /subversion/branches/1.6.x-wc-ng-error/CHANGES:929379-929636
 /subversion/branches/bdb-reverse-deltas/CHANGES:872050-872529
@@ -80,4 +90,4 @@
 /subversion/branches/tc_url_rev/CHANGES:874351-874483
 /subversion/branches/tree-conflicts/CHANGES:868291-873154
 /subversion/branches/tree-conflicts-notify/CHANGES:873926-874008
-/subversion/trunk/CHANGES:837701-841355,875962-955766
+/subversion/trunk/CHANGES:837701-841355,875962-955766,957507,958024,959004,959760,961055,961970,964167,964767,965405,965469,965508,979045,979429,981921,984928,984931

Modified: subversion/branches/1.6.x-issue3646/STATUS
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/STATUS?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/STATUS (original)
+++ subversion/branches/1.6.x-issue3646/STATUS Wed Sep 29 15:38:10 2010
@@ -57,80 +57,147 @@ Candidate changes:
            the r878607 log msg.)
 
  * r916286, r917512
-   Issue description:
-    With the below apache configuration(See the trailing slash at the 
-    end of '/svn/').
-
-    <Location /svn/>
-     DAV svn
-     SVNParentPath /repositories
-     #See the trailing slash on the master URI also can cause the confusion.
-     SVNMasterURI http://master/svn/
-     SVNAdvertiseV2Protocol Off
-    </Location>
-
-   Vague and useless error message *without* this fix on client side is
-   snipped below.
-   <snip>
-   svn: Commit failed (details follow):
-   svn: MKACTIVITY of '/svn/demujin/!svn/act/4b6d547c-018d-4e02-9d3f-2b283076cc06': Could not read status line: connection was closed by server (http://localhost)
-   </snip>
+   Fixes failing commmits (with vague error messages) seen on client
+   side for WebDAV proxy configurations such as the following (note
+   the trailing slash at the end of '/svn/'):
 
+      <Location /svn/>
+         DAV svn
+         SVNParentPath /repositories
+         # Trailing slash on the master URI also can cause the confusion.
+         SVNMasterURI http://master/svn/
+         SVNAdvertiseV2Protocol Off
+      </Location>
+
+   Error message shows up like so:
+
+      svn: Commit failed (details follow):
+      svn: MKACTIVITY of '/svn/demujin/!svn/act/4b6d547c-018d-4e02-9d3f-2b28\
+      3076cc06': Could not read status line: connection was closed by server\
+       (http://localhost)
 
    Notes:
-     This backport depends on the r878590 group only for the conflict free port.
+     Depends on the r878590 group for a conflict-free backport.
    Justification:
-    With this fix commit successfully gets proxied and succeeds.
+     Fixes failed commits.
    Votes:
      +1: kameshj
 
  * r917523
-     If the configured slave url has the *uri encodable* characters(<space>,
-     '?', '%') *write through* is not happening rather commit happens in
-     slave itself.
+   If the configured slave url employes URI-unsafe characters
+   (<space>, '?', '%'), proxying of commits fails and commit affects
+   the slave repository directly.
    Notes:
      This backport depends on the r878590 and r916286 groups only for the
      conflict free port.
    Justification:
-    With this commit we avoid accidental commit to the slave and hence 
-    making it unusable as a proxy anymore.
+     With this commit we avoid accidental commit to the slave and hence 
+     making it unusable as a proxy anymore.
    Votes:
      +1: kameshj
 
- * r950445, 950468
-   Fix for issue #2591 "'svnadmin hotcopy' does not replicate symlinks".
+ * r948512, r949307
+   Fix issue #3646 'record-only merges create self-referential mergeinfo'.
    Justification:
-     This fix helps server administrators who has common files symlinked
-     across their repositories and take frequent backups of their repos
-     using svnadmin hotcopy.
+     Prevents creation of self-referential mergeinfo (i.e. mergeinfo that
+     is redundant with a path's natural history).  Self-referential mergeinfo
+     is a source of confusion at best and a source of bugs at worst (e.g.
+     http://subversion.tigris.org/issues/show_bug.cgi?id=3294#desc1 and
+     http://svn.apache.org/viewvc?view=revision&revision=873767).
+   Branch:
+     WCNG work on trunk necessitated a backport branch.
+     ^/subversion/branches/1.6.x-issue3646
    Notes:
-     r950445 fixes the issue and r950468 is a test for this issue.
+     r948512 is a new test for the issue and r949307 is the fix.
    Votes:
-     +1: stylesen,
-     -0: julianfoad, cmpilato (Tested and works fine, but changes
-           semantics of svn_io_dir_walk() which we should not do in a
-           back-port.  Discussing on list.)
-
- * r945350, r946767, r955369
-   Fix issue #3242 'Subversion demands unnecessary access to parent
-   directories of operations' as relates to reintegrate merges.
+     +1: pburba, cmpilato
+
+ * r996884
+   Hide unreadable directory children in mod_dav_svn's GET response.
    Justification:
-     Without this backport, reintegrate merges fail if the user isn't
-     authorized to the root of the repository.
-   Branch:
-     Drift between trunk and 1.6.x, particularly in libsvn_client/merge.c
-     necessitated a backport branch.
-     ^/subversion/branches/1.6.x-issue3242-reintegrate
-   Notes:
-    r945350 adds a new merge_authz test for the issue.
-    r946767 is the fix for the issue.
-    r955369 is a fix for issue #3564 'added subtrees with mergeinfo break
-    reintegrate', which was a regression introduced by r946767.  So despite
-    having it's own issue number, it is a logical part of the issue #3242
-    group.
-    The rest of the issue #3242 fixes have already been backported in r934494.
+     We might as well be as tight security-wise as we can, even if
+     we've publicly stated for years that this was an expected leak of
+     information.  Not showing unreadable subdirs, for example, prevents
+     folks from clicking that sucker in the browser only to get an authz
+     failure.
    Votes:
-     +1: pburba
+     +1: cmpilato
+
+ * r997026, r997070, r997474
+   For issue #3709 ("Inconsistency between "svn list" and "svn
+   checkout"), omit unreadable paths from the get-dir RA response.
+   Justification:
+     Fixes 'svn ls -R' failing when recursing into a read-blocked
+     subdirectory by teaching servers not to mention such
+     subdirectories so the client doesn't try to recurse into them.
+   Notes:
+     Depends on the r996884 group for a function rename and
+     introduction of another.
+   Votes:
+     +1: cmpilato
+
+ * r997471
+   Client-side workaround for issue #3709 ("Inconsistency between "svn
+   list" and "svn checkout").
+   Justification:
+     Fixes issue #3709 for clients talking to servers that don't strip
+     out unreadable paths from their get-dir responses.
+   Notes:
+     Depends on the r997457 group.
+   Votes:
+     +1: cmpilato
+
+ * r962377, r962378
+   Fix svnsync handling of directory copyfrom.
+   Justification:
+     Could lead to sync'd repositories being different from the master.
+   Concerns:
+     http://article.gmane.org/gmane.comp.version-control.subversion.devel/120590
+   Votes:
+     +1: danielsh
+
+ * r1000038, r1000060
+   Fix for issue #3695(r1000060), in which the use of
+   "SVNPathAuthz short_circuit" causes Subversion to ignore authz access rule
+   sections which contain a repository prefix.
+   r1000038 - whiteline formatting only fix, without this merge of r1000060
+   would give a conflict.
+   Justification:
+     Rules are made to be broken.  Except when they're access rules.
+   Votes:
+     +1: cmpilato, kameshj
+
+ * r1000607, r1001009
+   Fix 'svnmucc propset'.
+   Justification:
+     Without this fix, 'svnmucc propset' used with existing URLs complains
+     that they exist already, and used in conjunction with a creating
+     command (such as 'put') complains that they don't exist.  It's
+     all rather restrictive.
+   Votes:
+     +1: cmpilato
+
+ * r1000612
+   Add new 'propsetf' subcommand to 'svnmucc'.
+   Justification:
+     This allows folks to more easily set binary and multi-line
+     property values.
+   Notes:
+     svnmucc isn't a core deliverable, so I'm not quite where it fits
+     into our version compatibility promise landscape.
+   Votes:
+     +1: cmpilato
+
+ * r1002094
+   Print a warning about copied directories during commits with limited depth.
+   Justification:
+     Users may not be aware that while limiting the scope of a commit via
+     depth works for most kinds of local changes, copies are always done
+     server-side with depth infinity. Without this warning, users may not
+     realise that the commit may not have the desired effect in the repository.
+     See issue #3699 for details.
+   Votes:
+     +1: stsp
 
 Veto-blocked changes:
 =====================
@@ -174,8 +241,11 @@ Veto-blocked changes:
    Votes:
      +1: arfrever
      -0: peters
-     -1: stsp, rhuijben ("/proc/%ld/stat" is ugly and Linux-specific -
-                         would just getenv("WINDOWID") work instead?)
+     -1: rhuijben ("/proc/%ld/stat" is ugly and Linux-specific -
+                   would just getenv("WINDOWID") work instead?)
+     -1: stsp (I've removed the Linux-specific code from trunk in r1002144
+               and r1002151, so trunk code only relies on getenv("WINDOWID").
+               I would +1 a backport that also merges these revisions).
 
  * r921453, r927184, r927243
    Fix reopened issue #3020 'Reflect dropped/renumbered revisions in
@@ -205,5 +275,23 @@ Veto-blocked changes:
    Votes:
      -1: cmpilato (pending results of aforemented discussion)
 
+ * r950445, 950468
+   Fix for issue #2591 "'svnadmin hotcopy' does not replicate symlinks".
+   Justification:
+     This fix helps server administrators who has common files symlinked
+     across their repositories and take frequent backups of their repos
+     using svnadmin hotcopy.
+   Notes:
+     r950445 fixes the issue and r950468 is a test for this issue.
+     In r967173 on trunk, svn_io_dir_walk()'s original functionality
+     was restored, and svn_io_dir_walk2() introduced to also cover
+     symlinks.
+   Votes:
+     +1: stylesen,
+     -0: julianfoad (Tested and works fine, but changes semantics of
+           svn_io_dir_walk() which we should not do in a back-port.
+           Discussing on list.)
+     -1: cmpilato (Changes semantics of svn_io_dir_walk()).
+
 Approved changes:
 =================

Modified: subversion/branches/1.6.x-issue3646/subversion/bindings/javahl/native/SVNAdmin.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/bindings/javahl/native/SVNAdmin.cpp?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/bindings/javahl/native/SVNAdmin.cpp (original)
+++ subversion/branches/1.6.x-issue3646/subversion/bindings/javahl/native/SVNAdmin.cpp Wed Sep 29 15:38:10 2010
@@ -485,12 +485,10 @@ void SVNAdmin::verify(const char *path, 
       (SVN_ERR_INCORRECT_PARAMS, NULL,
        _("Start revision cannot be higher than end revision")), );
 
-  SVN_JNI_ERR(svn_repos_dump_fs2(repos, NULL,
-                                 messageOut.getStream(requestPool),
-                                 lower, upper, FALSE /* incremental */,
-                                 TRUE /* use deltas */,
-                                 NULL, NULL /* cancel callback/baton */,
-                                 requestPool.pool()), );
+  SVN_JNI_ERR(svn_repos_verify_fs(repos, messageOut.getStream(requestPool),
+                                  lower, upper,
+                                  NULL, NULL /* cancel callback/baton */,
+                                  requestPool.pool()), );
 }
 
 jobjectArray SVNAdmin::lslocks(const char *path)

Modified: subversion/branches/1.6.x-issue3646/subversion/bindings/swig/ruby/svn/core.rb
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/bindings/swig/ruby/svn/core.rb?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/bindings/swig/ruby/svn/core.rb (original)
+++ subversion/branches/1.6.x-issue3646/subversion/bindings/swig/ruby/svn/core.rb Wed Sep 29 15:38:10 2010
@@ -644,16 +644,16 @@ module Svn
 
       def infinity_or_empty_from_recurse(depth_or_recurse)
         case depth_or_recurse
-          when true  : DEPTH_INFINITY
-          when false : DEPTH_EMPTY
+          when true  then DEPTH_INFINITY
+          when false then DEPTH_EMPTY
           else depth_or_recurse
         end
       end
 
       def infinity_or_immediates_from_recurse(depth_or_recurse)
         case depth_or_recurse
-          when true  : DEPTH_INFINITY
-          when false : DEPTH_IMMEDIATES
+          when true  then DEPTH_INFINITY
+          when false then DEPTH_IMMEDIATES
           else depth_or_recurse
         end
       end

Modified: subversion/branches/1.6.x-issue3646/subversion/include/private/svn_mergeinfo_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/include/private/svn_mergeinfo_private.h?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/include/private/svn_mergeinfo_private.h (original)
+++ subversion/branches/1.6.x-issue3646/subversion/include/private/svn_mergeinfo_private.h Wed Sep 29 15:38:10 2010
@@ -85,6 +85,19 @@ svn_mergeinfo__remove_prefix_from_catalo
                                           const char *prefix,
                                           apr_pool_t *pool);
 
+/* Make a shallow (ie, mergeinfos are not duped, or altered at all;
+   though keys are reallocated) copy of IN_CATALOG in *OUT_CATALOG,
+   adding PREFIX_PATH to the beginning of each key in the catalog.
+
+   The new hash keys are allocated in RESULT_POOL.  SCRATCH_POOL
+   is used for any temporary allocations.*/
+svn_error_t *
+svn_mergeinfo__add_prefix_to_catalog(svn_mergeinfo_catalog_t *out_catalog,
+                                     svn_mergeinfo_catalog_t in_catalog,
+                                     const char *prefix_path,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool);
+
 /* Create a string representation of CATALOG in *OUTPUT, allocated in POOL.
    The hash keys of CATALOG and the merge source paths of each key's mergeinfo
    are represented in sorted order as per svn_sort_compare_items_as_paths.
@@ -152,6 +165,18 @@ svn_mergeinfo__filter_catalog_by_ranges(
   svn_revnum_t oldest_rev,
   apr_pool_t *pool);
 
+/* Combine one mergeinfo catalog, CHANGES_CATALOG, into another mergeinfo
+  catalog MERGEINFO_CATALOG.  If both catalogs have mergeinfo for the same
+  key, use svn_mergeinfo_merge() to combine the mergeinfos.
+ 
+  Additions to MERGEINFO_CATALOG are deep copies allocated in
+  RESULT_POOL.  Temporary allocations are made in SCRATCH_POOL. */
+svn_error_t *
+svn_mergeinfo__catalog_merge(svn_mergeinfo_catalog_t mergeinfo_catalog,
+                             svn_mergeinfo_catalog_t changes_catalog,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
+                            
 /* Removes ERASER (the subtrahend) from WHITEBOARD (the
    minuend), and places the resulting difference in *MERGEINFO.
    Allocates *MERGEINFO in RESULT_POOL.  Temporary allocations

Modified: subversion/branches/1.6.x-issue3646/subversion/include/private/svn_opt_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/include/private/svn_opt_private.h?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/include/private/svn_opt_private.h (original)
+++ subversion/branches/1.6.x-issue3646/subversion/include/private/svn_opt_private.h Wed Sep 29 15:38:10 2010
@@ -61,7 +61,6 @@ svn_opt__split_arg_at_peg_revision(const
 /* Attempt to transform URL_IN, which is a URL-like user input, into a
  * valid URL:
  *   - escape IRI characters and some other non-URI characters
- *   - check that only valid URI characters remain
  *   - check that no back-path ("..") components are present
  *   - canonicalize the separator ("/") characters
  * URL_IN is in UTF-8 encoding and has no peg revision specifier.

Modified: subversion/branches/1.6.x-issue3646/subversion/libsvn_client/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/libsvn_client/commit.c?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/libsvn_client/commit.c (original)
+++ subversion/branches/1.6.x-issue3646/subversion/libsvn_client/commit.c Wed Sep 29 15:38:10 2010
@@ -1140,6 +1140,7 @@ struct post_commit_baton
   svn_boolean_t keep_changelists;
   svn_boolean_t keep_locks;
   apr_hash_t *checksums;
+  svn_depth_t depth;
 };
 
 static svn_error_t *
@@ -1183,7 +1184,8 @@ post_process_commit_item(void *baton, vo
 
   if ((item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
       && (item->kind == svn_node_dir)
-      && (item->copyfrom_url))
+      && (item->copyfrom_url)
+      && btn->depth >= svn_depth_immediates)
     loop_recurse = TRUE;
 
   remove_lock = (! btn->keep_locks && (item->state_flags
@@ -1683,6 +1685,7 @@ svn_client_commit4(svn_commit_info_t **c
       btn.keep_changelists = keep_changelists;
       btn.keep_locks = keep_locks;
       btn.checksums = checksums;
+      btn.depth = depth;
 
       /* Make a note that our commit is finished. */
       commit_in_progress = FALSE;

Modified: subversion/branches/1.6.x-issue3646/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/libsvn_client/export.c?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/libsvn_client/export.c (original)
+++ subversion/branches/1.6.x-issue3646/subversion/libsvn_client/export.c Wed Sep 29 15:38:10 2010
@@ -620,7 +620,12 @@ add_file(const char *path,
   struct edit_baton *eb = pb->edit_baton;
   struct file_baton *fb = apr_pcalloc(pool, sizeof(*fb));
   const char *full_path = svn_path_join(eb->root_path, path, pool);
-  const char *full_url = svn_path_join(eb->root_url, path, pool);
+
+  /* PATH is not canonicalized, i.e. it may still contain spaces etc.
+   * but EB->root_url is. */
+  const char *full_url = svn_path_url_add_component2(eb->root_url,
+                                                     path,
+                                                     pool);
 
   fb->edit_baton = eb;
   fb->path = full_path;

Modified: subversion/branches/1.6.x-issue3646/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/libsvn_client/merge.c?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/1.6.x-issue3646/subversion/libsvn_client/merge.c Wed Sep 29 15:38:10 2010
@@ -1085,8 +1085,12 @@ merge_props_changed(svn_wc_adm_access_t 
                                       ctx->cancel_baton, subpool));
 
       /* If this is a forward merge then don't add new mergeinfo to
-         PATH that is already part of PATH's own history. */
-      if (merge_b->merge_source.rev1 < merge_b->merge_source.rev2)
+         PATH that is already part of PATH's own history, see
+         http://svn.haxx.se/dev/archive-2008-09/0006.shtml.  If the
+         merge sources are not ancestral then there is no concept of a
+         'forward' or 'reverse' merge and we filter unconditionally. */
+      if (merge_b->merge_source.rev1 < merge_b->merge_source.rev2
+          || !merge_b->sources_ancestral)
         SVN_ERR(filter_self_referential_mergeinfo(&props, path, merge_b,
                                                   adm_access, subpool));
 
@@ -4035,12 +4039,23 @@ calculate_merge_inheritance(apr_array_he
   return SVN_NO_ERROR;
 }
 
-/* Calculate the new mergeinfo for the target tree based on the merge
-   info for TARGET_WCPATH and MERGES (a mapping of WC paths to range
-   lists), and record it in the WC (at, and possibly below,
-   TARGET_WCPATH). */
+/* Calculate the new mergeinfo for the target tree rooted at TARGET_WCPATH
+   based on MERGES (a mapping of WC paths to rangelists representing
+   a merge from the source REPOS_REL_PATH).
+
+   If RESULT_CATALOG is NULL, then record the new mergeinfo in the WC (at,
+   and possibly below, TARGET_WCPATH).
+
+   If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the
+   WC, but instead record it in RESULT_CATALOG, with key TARGET_WCPATH and the
+   value the new mergeinfo for that path.  If TARGET_WCPATH is already
+   present in RESULT_CATALOG, then merge the new mergeinfo together with
+   the existing mergeinfo and store the result in RESULT_CATALOG.
+   Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
+   created in. */
 static svn_error_t *
-update_wc_mergeinfo(const char *target_wcpath, const svn_wc_entry_t *entry,
+update_wc_mergeinfo(svn_mergeinfo_catalog_t result_catalog,
+                    const char *target_wcpath, const svn_wc_entry_t *entry,
                     const char *repos_rel_path, apr_hash_t *merges,
                     svn_boolean_t is_rollback,
                     svn_wc_adm_access_t *adm_access,
@@ -4139,25 +4154,42 @@ update_wc_mergeinfo(const char *target_w
 
       svn_mergeinfo__remove_empty_rangelists(mergeinfo, pool);
 
-      err = svn_client__record_wc_mergeinfo(path, mergeinfo,
-                                            adm_access, subpool);
-
-      if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
+      if (result_catalog)
         {
-          /* PATH isn't just missing, it's not even versioned as far
-             as this working copy knows.  But it was included in
-             MERGES, which means that the server knows about it.
-             Likely we don't have access to the source due to authz
-             restrictions.  For now just clear the error and
-             continue...
-
-             ### TODO:  Set non-inheritable mergeinfo on PATH's immediate
-             ### parent and normal mergeinfo on PATH's siblings which we
-             ### do have access to. */
-          svn_error_clear(err);
+          svn_mergeinfo_t existing_mergeinfo =
+            apr_hash_get(result_catalog, target_wcpath, APR_HASH_KEY_STRING);
+          apr_pool_t *result_catalog_pool = apr_hash_pool_get(result_catalog);
+
+          if (existing_mergeinfo)
+            SVN_ERR(svn_mergeinfo_merge(mergeinfo, existing_mergeinfo,
+                                        result_catalog_pool));
+          apr_hash_set(result_catalog,
+                       apr_pstrdup(result_catalog_pool, target_wcpath),
+                       APR_HASH_KEY_STRING,
+                       svn_mergeinfo_dup(mergeinfo, result_catalog_pool));
         }
       else
-        SVN_ERR(err);
+        {
+          err = svn_client__record_wc_mergeinfo(path, mergeinfo,
+                                                adm_access, subpool);
+
+          if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
+            {
+              /* PATH isn't just missing, it's not even versioned as far
+                 as this working copy knows.  But it was included in
+                 MERGES, which means that the server knows about it.
+                 Likely we don't have access to the source due to authz
+                 restrictions.  For now just clear the error and
+                 continue...
+
+                 ### TODO:  Set non-inheritable mergeinfo on PATH's immediate
+                 ### parent and normal mergeinfo on PATH's siblings which we
+                 ### do have access to. */
+              svn_error_clear(err);
+            }
+          else
+            SVN_ERR(err);
+        }
     }
 
   svn_pool_destroy(subpool);
@@ -4235,7 +4267,7 @@ record_skips(const char *mergeinfo_path,
                ### skipped? */
             ;
         }
-      SVN_ERR(update_wc_mergeinfo(merge_b->target, target_entry,
+      SVN_ERR(update_wc_mergeinfo(NULL, merge_b->target, target_entry,
                                   mergeinfo_path, merges,
                                   is_rollback, adm_access,
                                   merge_b->ctx, pool));
@@ -6038,11 +6070,18 @@ filter_natural_history_from_mergeinfo(ap
    cousins thrice removed, etc...).  (This is used to simulate the
    history checks that the repository logic does in the directory case.)
 
+   If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
+   is not NULL, then don't record the new mergeinfo on the TARGET_WCPATH,
+   but instead record it in RESULT_CATALOG, where the key is TARGET_WCPATH
+   and the value is the new mergeinfo for that path.  Allocate additions
+   to RESULT_CATALOG in pool which RESULT_CATALOG was created in.
+
    Note: MERGE_B->RA_SESSION1 must be associated with URL1 and
    MERGE_B->RA_SESSION2 with URL2.
 */
 static svn_error_t *
-do_file_merge(const char *url1,
+do_file_merge(svn_mergeinfo_catalog_t result_catalog,
+              const char *url1,
               svn_revnum_t revision1,
               const char *url2,
               svn_revnum_t revision2,
@@ -6351,9 +6390,9 @@ do_file_merge(const char *url1,
 
           apr_hash_set(merges, target_wcpath, APR_HASH_KEY_STRING,
                        filtered_rangelist);
-          SVN_ERR(update_wc_mergeinfo(target_wcpath, entry, mergeinfo_path,
-                                      merges, is_rollback, adm_access,
-                                      ctx, subpool));
+          SVN_ERR(update_wc_mergeinfo(result_catalog, target_wcpath, entry,
+                                      mergeinfo_path, merges, is_rollback,
+                                      adm_access, ctx, subpool));
         }
     }
 
@@ -6569,17 +6608,29 @@ do_mergeinfo_unaware_dir_merge(const cha
 
 /* Helper for do_directory_merge().
 
-   Record mergeinfo describing a merge of MERGED_RANGE->START:
-   MERGED_RANGE->END from the repository relative path MERGEINFO_PATH to
-   the directory represented by TARGET_ENTRY.  Obviously this should only
+   If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
+   MERGED_RANGE->START:MERGED_RANGE->END from the repository relative path
+   MERGEINFO_PATH to the merge target (and possibly its subtrees) described
+   by NOTIFY_B->CHILDREN_WITH_MERGEINFO -- see the global comment
+   'THE CHILDREN_WITH_MERGEINFO ARRAY'.  Obviously this should only
    be called if recording mergeinfo -- see doc string for
    mergeinfo_behavior().
 
+   If RESULT_CATALOG is not NULL, then don't record the new mergeinfo on the
+   WC, but instead record it in RESULT_CATALOG, where the keys are
+   working copy paths and the values are the new mergeinfos for each.
+   The WC path keys are either absolute or relative to the current working
+   directory in the same way NOTIFY_B->CHILDREN_WITH_MERGEINFO's
+   svn_client__merge_path_t's PATH member is.
+   Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
+   created in.
+
    TARGET_ENTRY, DEPTH, NOTIFY_B, MERGE_B, and ADM_ACCESS are all cascaded
    from do_directory_merge's arguments of the same names.
 */
 static svn_error_t *
-record_mergeinfo_for_dir_merge(const svn_wc_entry_t *target_entry,
+record_mergeinfo_for_dir_merge(svn_mergeinfo_catalog_t result_catalog,
+                               const svn_wc_entry_t *target_entry,
                                svn_merge_range_t *merged_range,
                                const char *mergeinfo_path,
                                svn_depth_t depth,
@@ -6680,7 +6731,7 @@ record_mergeinfo_for_dir_merge(const svn
       child_merges = apr_hash_make(iterpool);
       apr_hash_set(child_merges, child->path, APR_HASH_KEY_STRING,
                    child_merge_rangelist);
-      SVN_ERR(update_wc_mergeinfo(child->path, child_entry,
+      SVN_ERR(update_wc_mergeinfo(result_catalog, child->path, child_entry,
                                   child_merge_src_canon_path,
                                   child_merges, is_rollback,
                                   adm_access, merge_b->ctx, iterpool));
@@ -6872,6 +6923,15 @@ record_mergeinfo_for_added_subtrees(svn_
    requirements around the values of URL1, REVISION1, URL2, and REVISION2
    in this case).
 
+   If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
+   is not NULL, then don't record the new mergeinfo on the WC, but instead
+   record it in RESULT_CATALOG, where the keys are working copy paths and the
+   values are the new mergeinfos for each.  The WC path keys are either
+   absolute or relative to the current working directory in the same way
+   NOTIFY_B->CHILDREN_WITH_MERGEINFO's svn_client__merge_path_t's PATH member
+   is.  Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
+   created in.
+
    Handle DEPTH as documented for svn_client_merge3().
 
    NOTE: This is a wrapper around drive_merge_report_editor() which
@@ -6880,7 +6940,8 @@ record_mergeinfo_for_added_subtrees(svn_
    meet one or more of the criteria described in get_mergeinfo_paths()).
 */
 static svn_error_t *
-do_directory_merge(const char *url1,
+do_directory_merge(svn_mergeinfo_catalog_t result_catalog,
+                   const char *url1,
                    svn_revnum_t revision1,
                    const char *url2,
                    svn_revnum_t revision2,
@@ -7143,7 +7204,8 @@ do_directory_merge(const char *url1,
   /* Record mergeinfo where appropriate.*/
   if (record_mergeinfo)
     {
-      SVN_ERR(record_mergeinfo_for_dir_merge(target_entry,
+      SVN_ERR(record_mergeinfo_for_dir_merge(result_catalog,
+                                             target_entry,
                                              &range,
                                              mergeinfo_path,
                                              depth,
@@ -7234,6 +7296,14 @@ ensure_ra_session_url(svn_ra_session_t *
    repository as the one from which the target working copy has been
    checked out.
 
+   If mergeinfo is being recorded to describe this merge, and RESULT_CATALOG
+   is not NULL, then don't record the new mergeinfo on the WC, but instead
+   record it in RESULT_CATALOG, where the keys are working copy paths and the
+   values are the new mergeinfos for each.  The WC path keys are absolute if
+   TARGET is absolute and relative to the current working directory otherwise.
+   Allocate additions to RESULT_CATALOG in pool which RESULT_CATALOG was
+   created in.
+
    FORCE, DRY_RUN, RECORD_ONLY, IGNORE_ANCESTRY, DEPTH, MERGE_OPTIONS,
    and CTX are as described in the docstring for svn_client_merge_peg3().
 
@@ -7243,7 +7313,8 @@ ensure_ra_session_url(svn_ra_session_t *
    integrity, *USE_SLEEP will be unchanged if no sleep is required.
 */
 static svn_error_t *
-do_merge(apr_array_header_t *merge_sources,
+do_merge(svn_mergeinfo_catalog_t result_catalog,
+         apr_array_header_t *merge_sources,
          const char *target,
          const svn_wc_entry_t *target_entry,
          svn_wc_adm_access_t *adm_access,
@@ -7386,13 +7457,15 @@ do_merge(apr_array_header_t *merge_sourc
       /* Call our merge helpers based on entry kind. */
       if (target_entry->kind == svn_node_file)
         {
-          SVN_ERR(do_file_merge(url1, rev1, url2, rev2, target,
+          SVN_ERR(do_file_merge(result_catalog,
+                                url1, rev1, url2, rev2, target,
                                 sources_related, adm_access, &notify_baton,
                                 &merge_cmd_baton, subpool));
         }
       else if (target_entry->kind == svn_node_dir)
         {
-          SVN_ERR(do_directory_merge(url1, rev1, url2, rev2, target_entry,
+          SVN_ERR(do_directory_merge(result_catalog,
+                                     url1, rev1, url2, rev2, target_entry,
                                      adm_access, depth, &notify_baton,
                                      &merge_cmd_baton, subpool));
         }
@@ -7426,8 +7499,8 @@ do_merge(apr_array_header_t *merge_sourc
    merge (unless this is record-only), followed by record-only merges
    to represent the changed mergeinfo.
 
-   The merge is between URL1@REV1 (in RA_SESSION1) and URL2@REV2 (in
-   RA_SESSION2); YC_REV is their youngest common ancestor.
+   The merge is between URL1@REV1 (in URL1_RA_SESSION1) and URL2@REV2 (in
+   URL2_RA_SESSION2); YC_REV is their youngest common ancestor.
    SOURCE_REPOS_ROOT and WC_REPOS_ROOT are the repository roots of the
    source URL and the target working copy.  ENTRY is the wc entry for
    TARGET_WCPATH.  Other arguments are as in all of the public merge
@@ -7440,7 +7513,8 @@ static svn_error_t *
 merge_cousins_and_supplement_mergeinfo(const char *target_wcpath,
                                        const svn_wc_entry_t *entry,
                                        svn_wc_adm_access_t *adm_access,
-                                       svn_ra_session_t *ra_session,
+                                       svn_ra_session_t *URL1_ra_session,
+                                       svn_ra_session_t *URL2_ra_session,
                                        const char *URL1,
                                        svn_revnum_t rev1,
                                        const char *URL2,
@@ -7461,7 +7535,6 @@ merge_cousins_and_supplement_mergeinfo(c
   svn_opt_revision_range_t *range;
   apr_array_header_t *remove_sources, *add_sources, *ranges;
   svn_opt_revision_t peg_revision;
-  const char *old_url;
   svn_boolean_t same_repos;
 
   if (strcmp(wc_repos_root, source_repos_root) != 0)
@@ -7469,7 +7542,7 @@ merge_cousins_and_supplement_mergeinfo(c
       const char *source_repos_uuid;
       const char *wc_repos_uuid;
 
-      SVN_ERR(svn_ra_get_uuid2(ra_session, &source_repos_uuid, pool));
+      SVN_ERR(svn_ra_get_uuid2(URL1_ra_session, &source_repos_uuid, pool));
       if (entry)
         wc_repos_uuid = entry->uuid;
       else
@@ -7481,7 +7554,6 @@ merge_cousins_and_supplement_mergeinfo(c
     same_repos = TRUE;
 
   peg_revision.kind = svn_opt_revision_number;
-  SVN_ERR(svn_ra_get_session_url(ra_session, &old_url, pool));
 
   range = apr_pcalloc(pool, sizeof(*range));
   range->start.kind = svn_opt_revision_number;
@@ -7491,10 +7563,9 @@ merge_cousins_and_supplement_mergeinfo(c
   ranges = apr_array_make(pool, 2, sizeof(svn_opt_revision_range_t *));
   APR_ARRAY_PUSH(ranges, svn_opt_revision_range_t *) = range;
   peg_revision.value.number = rev1;
-  SVN_ERR(svn_ra_reparent(ra_session, URL1, pool));
   SVN_ERR(normalize_merge_sources(&remove_sources, URL1, URL1,
                                   source_repos_root, &peg_revision,
-                                  ranges, ra_session, ctx, pool));
+                                  ranges, URL1_ra_session, ctx, pool));
 
   range = apr_pcalloc(pool, sizeof(*range));
   range->start.kind = svn_opt_revision_number;
@@ -7504,12 +7575,9 @@ merge_cousins_and_supplement_mergeinfo(c
   ranges = apr_array_make(pool, 2, sizeof(svn_opt_revision_range_t *));
   APR_ARRAY_PUSH(ranges, svn_opt_revision_range_t *) = range;
   peg_revision.value.number = rev2;
-  SVN_ERR(svn_ra_reparent(ra_session, URL2, pool));
   SVN_ERR(normalize_merge_sources(&add_sources, URL2, URL2,
                                   source_repos_root, &peg_revision,
-                                  ranges, ra_session, ctx, pool));
-
-  SVN_ERR(svn_ra_reparent(ra_session, old_url, pool));
+                                  ranges, URL2_ra_session, ctx, pool));
 
   /* If this isn't a record-only merge, we'll first do a stupid
      point-to-point merge... */
@@ -7524,7 +7592,7 @@ merge_cousins_and_supplement_mergeinfo(c
       faux_source->rev1 = rev1;
       faux_source->rev2 = rev2;
       APR_ARRAY_PUSH(faux_sources, merge_source_t *) = faux_source;
-      SVN_ERR(do_merge(faux_sources, target_wcpath, entry, adm_access,
+      SVN_ERR(do_merge(NULL, faux_sources, target_wcpath, entry, adm_access,
                        FALSE, TRUE, same_repos,
                        ignore_ancestry, force, dry_run, FALSE, TRUE,
                        depth, merge_options, use_sleep, ctx, pool));
@@ -7540,17 +7608,61 @@ merge_cousins_and_supplement_mergeinfo(c
      pair of record-only merges using the real sources we've
      calculated.  (We know that each tong in our fork of our merge
      source history tree has an ancestral relationship with the common
-     ancestral, so we force ancestral=TRUE here.) */
+     ancestral, so we force ancestral=TRUE here.)
+
+     Issue #3648: We don't actually perform these two record-only merges
+     on the WC at first, but rather see what each would do and store that
+     in two mergeinfo catalogs.  We then merge the catalogs together and
+     then record the result in the WC.  This prevents the second record
+     only merge from removing legitimate mergeinfo history, from the same
+     source, that was made in prior merges. */
   if (same_repos)
     {
-      SVN_ERR(do_merge(add_sources, target_wcpath, entry,
+      svn_mergeinfo_catalog_t add_result_catalog = apr_hash_make(pool);
+      svn_mergeinfo_catalog_t remove_result_catalog = apr_hash_make(pool);
+
+      SVN_ERR(do_merge(add_result_catalog, add_sources, target_wcpath, entry,
                        adm_access, TRUE, TRUE, same_repos,
                        ignore_ancestry, force, dry_run, TRUE, TRUE,
                        depth, merge_options, use_sleep, ctx, pool));
-      SVN_ERR(do_merge(remove_sources, target_wcpath, entry,
-                       adm_access, TRUE, TRUE, same_repos,
+      SVN_ERR(do_merge(remove_result_catalog, remove_sources, target_wcpath,
+                       entry, adm_access, TRUE, TRUE, same_repos,
                        ignore_ancestry, force, dry_run, TRUE, TRUE,
                        depth, merge_options, use_sleep, ctx, pool));
+      SVN_ERR(svn_mergeinfo__catalog_merge(add_result_catalog,
+                                           remove_result_catalog,
+                                           pool, pool));
+
+      if (apr_hash_count(add_result_catalog))
+        {
+          int i;
+          apr_array_header_t *sorted_cat;
+
+          sorted_cat = svn_sort__hash(add_result_catalog,
+                                      svn_sort_compare_items_as_paths, pool);
+          for (i = 0; i < sorted_cat->nelts; i++)
+            {
+              svn_sort__item_t elt = APR_ARRAY_IDX(sorted_cat, i,
+                                                   svn_sort__item_t);
+              svn_error_t *err = svn_client__record_wc_mergeinfo(elt.key,
+                                                                 elt.value,
+                                                                 adm_access,
+                                                                 pool);
+
+              if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
+                {
+                  /* PATH isn't just missing, it's not even versioned as far
+                     as this working copy knows.  But it was included in
+                     MERGES, which means that the server knows about it.
+                     Likely we don't have access to the source due to authz
+                     restrictions.  For now just clear the error and
+                     continue... */
+                  svn_error_clear(err);
+                }
+              else
+                SVN_ERR(err);
+                }
+        }
     }
   return SVN_NO_ERROR;
 }
@@ -7757,6 +7869,7 @@ svn_client_merge3(const char *source1,
           err = merge_cousins_and_supplement_mergeinfo(target_wcpath, entry,
                                                        adm_access,
                                                        ra_session1,
+                                                       ra_session2,
                                                        URL1, rev1,
                                                        URL2, rev2,
                                                        yc_rev,
@@ -7799,7 +7912,7 @@ svn_client_merge3(const char *source1,
   /* Close our temporary RA sessions. */
   svn_pool_destroy(sesspool);
 
-  err = do_merge(merge_sources, target_wcpath, entry, adm_access,
+  err = do_merge(NULL, merge_sources, target_wcpath, entry, adm_access,
                  ancestral, related, same_repos,
                  ignore_ancestry, force, dry_run,
                  record_only, FALSE, depth, merge_options,
@@ -7860,19 +7973,21 @@ ensure_wc_reflects_repository_subtree(co
 
 /* Given a mergeinfo catalog UNMERGED_HISTORY representing the history
    (as mergeinfo) from a merge target that is not represented in the merge
-   source, check (using RA_SESSION, which is pointed at the repository
-   root) that all of the ranges in the catalog's mergeinfos are "phantoms":
-   that is, their corresponding path did not change in any of their revisions.
-   Raises SVN_ERR_CLIENT_NOT_READY_TO_MERGE if any are not phantoms.
-   Temporary allocations in POOL.
+   source, check (using TARGET_RA_SESSION, which points to
+   MERGE_TARGET_REPOS_REL_PATH) that all of the ranges in the catalog's
+   mergeinfos are "phantoms": that is, their corresponding path did not
+   change in any of their revisions.  Raises SVN_ERR_CLIENT_NOT_READY_TO_MERGE
+   if any are not phantoms.  Temporary allocations in POOL.
  */
 static svn_error_t *
-ensure_all_missing_ranges_are_phantoms(svn_ra_session_t *ra_session,
+ensure_all_missing_ranges_are_phantoms(const char *target_repos_rel_path,
+                                       svn_ra_session_t *target_ra_session,
                                        svn_mergeinfo_catalog_t unmerged_history,
                                        apr_pool_t *pool)
 {
   apr_hash_index_t *hi1, *hi2;
   apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_size_t target_repos_rel_len = strlen(target_repos_rel_path);
 
   for (hi1 = apr_hash_first(pool, unmerged_history); hi1;
        hi1 = apr_hash_next(hi1))
@@ -7897,10 +8012,11 @@ ensure_all_missing_ranges_are_phantoms(s
           path = key;
           rangelist = value;
 
-          /* mergeinfo hashes contain paths that start with slashes;
-             ra APIs take paths without slashes. */
-          SVN_ERR_ASSERT(*path);
-          path++;
+          /* Mergeinfo source paths are always repository absolute, so adjust
+             the path so it is relative to TARGET_RA_SESSION. */
+          path = path + target_repos_rel_len + 1;
+          if (path[0] == '/')
+            path++;
 
           for (i = 0; i < rangelist->nelts; i++)
             {
@@ -7914,7 +8030,7 @@ ensure_all_missing_ranges_are_phantoms(s
 
               svn_pool_clear(iterpool);
 
-              SVN_ERR(svn_ra_stat(ra_session,
+              SVN_ERR(svn_ra_stat(target_ra_session,
                                   path,
                                   range->end,
                                   &dirent,
@@ -7926,7 +8042,7 @@ ensure_all_missing_ranges_are_phantoms(s
 
                   svn_pool_destroy(iterpool);
 
-                  SVN_ERR(svn_ra_get_session_url(ra_session, &full_url,
+                  SVN_ERR(svn_ra_get_session_url(target_ra_session, &full_url,
                                                  pool));
                   full_url = svn_path_url_add_component2(full_url, path, pool);
                   return svn_error_createf(SVN_ERR_CLIENT_NOT_READY_TO_MERGE,
@@ -7971,7 +8087,8 @@ ensure_all_missing_ranges_are_phantoms(s
    TARGET_REPOS_REL_PATH is at.  SOURCE_REV is the peg revision of the
    reintegrate source.
 
-   RA_SESSION is a session opened to the repository root.
+   SOURCE_RA_SESSION is a session opened to the SOURCE_REPOS_REL_PATH
+   and TARGET_RA_SESSION is open to TARGET_REPOS_REL_PATH.
 
    For each path/segment in TARGET_SEGMENTS_HASH check that the history that
    segment represents is contained in either the explicit mergeinfo for the
@@ -8003,7 +8120,8 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
                         const char *target_repos_rel_path,
                         svn_revnum_t target_rev,
                         svn_revnum_t source_rev,
-                        svn_ra_session_t *ra_session,
+                        svn_ra_session_t *source_ra_session,
+                        svn_ra_session_t *target_ra_session,
                         svn_client_ctx_t *ctx,
                         apr_pool_t *pool)
 {
@@ -8014,6 +8132,7 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
   apr_pool_t *subpool = svn_pool_create(pool);
   apr_pool_t *iterpool = svn_pool_create(subpool);
   svn_revnum_t old_rev, young_rev;
+  apr_size_t source_repos_rel_len = strlen(source_repos_rel_path);
 
   *never_synched = TRUE;
   *youngest_merged_rev = SVN_INVALID_REVNUM;
@@ -8028,6 +8147,7 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
       void *val;
       const char *path, *source_path;
       apr_array_header_t *segments;
+      const char *source_path_rel_to_session;
       svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo;
 
       svn_pool_clear(iterpool);
@@ -8040,6 +8160,9 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
         source_path++;
       source_path = svn_path_join(source_repos_rel_path, source_path,
         iterpool);
+      source_path_rel_to_session = source_path + source_repos_rel_len;
+      if (source_path_rel_to_session[0] == '/')
+        source_path_rel_to_session++;
 
       /* Convert this target path's natural history into mergeinfo. */
       SVN_ERR(svn_client__mergeinfo_from_segments(&target_history_as_mergeinfo,
@@ -8100,8 +8223,9 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
           svn_node_kind_t kind;
           svn_mergeinfo_catalog_t subtree_catalog;
           apr_array_header_t *source_repos_rel_path_as_array;
-          SVN_ERR(svn_ra_check_path(ra_session, source_path, source_rev,
-                                    &kind, iterpool));
+          SVN_ERR(svn_ra_check_path(source_ra_session,
+                                    source_path_rel_to_session,
+                                    source_rev, &kind, iterpool));
           if (kind == svn_node_none)
               continue;
           /* Else source_path does exist though it has no explicit mergeinfo.
@@ -8110,8 +8234,8 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
           source_repos_rel_path_as_array =
             apr_array_make(iterpool, 1, sizeof(const char *));
           APR_ARRAY_PUSH(source_repos_rel_path_as_array, const char *)
-            = source_path;
-          SVN_ERR(svn_ra_get_mergeinfo(ra_session, &subtree_catalog,
+            = source_path_rel_to_session;
+          SVN_ERR(svn_ra_get_mergeinfo(source_ra_session, &subtree_catalog,
                                        source_repos_rel_path_as_array,
                                        source_rev, svn_mergeinfo_inherited,
                                        FALSE, iterpool));
@@ -8128,8 +8252,8 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
          Then merge that natural history into source path's explicit
          or inherited mergeinfo. */
       SVN_ERR(svn_client__repos_location_segments(&segments,
-                                                  ra_session,
-                                                  source_path,
+                                                  source_ra_session,
+                                                  source_path_rel_to_session,
                                                   source_rev, source_rev,
                                                   SVN_INVALID_REVNUM,
                                                   ctx, iterpool));
@@ -8178,6 +8302,7 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
           const void *key;
           void *val;
           const char *source_path;
+          const char *source_path_rel_to_session;
           svn_mergeinfo_t source_mergeinfo, filtered_mergeinfo;
           const char *target_path;
           apr_array_header_t *segments;
@@ -8188,14 +8313,16 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
           source_path = key;
           source_mergeinfo = val;
 
-          target_path = source_path + strlen(source_repos_rel_path);
+          target_path = source_path + source_repos_rel_len;
           if (target_path[0] == '/') /* Remove leading '/' for svn_path_join */
             target_path++;
-          target_path = svn_path_join(target_repos_rel_path, target_path,
-                                      iterpool);
+
+          source_path_rel_to_session = source_path + source_repos_rel_len;
+          if (source_path_rel_to_session[0] == '/')
+            source_path_rel_to_session++;
 
           err = svn_client__repos_location_segments(&segments,
-                                                    ra_session,
+                                                    target_ra_session,
                                                     target_path,
                                                     target_rev, target_rev,
                                                     SVN_INVALID_REVNUM,
@@ -8246,13 +8373,14 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
               /* Get the source path's natural history and convert it to
                  mergeinfo.  Then merge that natural history into source
                  path's explicit or inherited mergeinfo. */
-              SVN_ERR(svn_client__repos_location_segments(&segments,
-                                                          ra_session,
-                                                          source_path,
-                                                          target_rev,
-                                                          target_rev,
-                                                          SVN_INVALID_REVNUM,
-                                                          ctx, iterpool));
+              SVN_ERR(svn_client__repos_location_segments(
+                &segments,
+                source_ra_session,
+                source_path_rel_to_session,
+                target_rev,
+                target_rev,
+                SVN_INVALID_REVNUM,
+                ctx, iterpool));
               SVN_ERR(svn_client__mergeinfo_from_segments(
                 &source_history_as_mergeinfo, segments, iterpool));
               SVN_ERR(svn_mergeinfo_merge(source_mergeinfo,
@@ -8281,13 +8409,11 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
   /* Limit new_catalog to the youngest revisions previously merged from
      the target to the source. */
   if (SVN_IS_VALID_REVNUM(*youngest_merged_rev))
-    {
-      SVN_ERR(svn_mergeinfo__filter_catalog_by_ranges(&new_catalog,
-                                                      new_catalog,
-                                                      *youngest_merged_rev,
-                                                      0, /* No oldest bound. */
-                                                      subpool));
-    }
+    SVN_ERR(svn_mergeinfo__filter_catalog_by_ranges(&new_catalog,
+                                                    new_catalog,
+                                                    *youngest_merged_rev,
+                                                    0, /* No oldest bound. */
+                                                    subpool));
 
   /* Make a shiny new copy before blowing away all the temporary pools. */
   *unmerged_to_source_catalog = svn_mergeinfo_catalog_dup(new_catalog, pool);
@@ -8320,7 +8446,8 @@ find_unmerged_mergeinfo(svn_mergeinfo_ca
    from the target to the source if such exists, see doc string for
    find_unmerged_mergeinfo().
 
-   RA_SESSION is a session opened to the repository root. */
+   SOURCE_RA_SESSION is a session opened to the SOURCE_REPOS_REL_PATH
+   and TARGET_RA_SESSION is open to TARGET_REPOS_REL_PATH. */
 static svn_error_t *
 calculate_left_hand_side(const char **url_left,
                          svn_revnum_t *rev_left,
@@ -8331,7 +8458,8 @@ calculate_left_hand_side(const char **ur
                          const char *source_repos_rel_path,
                          const char *source_repos_root,
                          svn_revnum_t source_rev,
-                         svn_ra_session_t *ra_session,
+                         svn_ra_session_t *source_ra_session,
+                         svn_ra_session_t *target_ra_session,
                          svn_client_ctx_t *ctx,
                          apr_pool_t *pool)
 {
@@ -8348,6 +8476,7 @@ calculate_left_hand_side(const char **ur
   const char *yc_ancestor_path;
   const char *source_url;
   const char *target_url;
+  apr_size_t target_repos_rel_len = strlen(target_repos_rel_path);
 
   /* Get the history (segments) for the target and any of its subtrees
      with explicit mergeinfo. */
@@ -8358,12 +8487,17 @@ calculate_left_hand_side(const char **ur
       const void *key;
       void *val;
       const char *path;
+      const char *path_rel_to_session;
 
       apr_hash_this(hi, &key, NULL, &val);
       path = key;
+      path_rel_to_session = path + target_repos_rel_len;
+      if (path_rel_to_session[0] == '/')
+        path_rel_to_session++;
+
       SVN_ERR(svn_client__repos_location_segments(&segments,
-                                                  ra_session,
-                                                  path,
+                                                  target_ra_session,
+                                                  path_rel_to_session,
                                                   target_rev, target_rev,
                                                   SVN_INVALID_REVNUM,
                                                   ctx, subpool));
@@ -8394,12 +8528,17 @@ calculate_left_hand_side(const char **ur
 
   /* Get the mergeinfo from the source, including its descendants
      with differing explicit mergeinfo. */
-  APR_ARRAY_PUSH(source_repos_rel_path_as_array, const char *)
-    = source_repos_rel_path;
-  SVN_ERR(svn_ra_get_mergeinfo(ra_session, &mergeinfo_catalog,
+  APR_ARRAY_PUSH(source_repos_rel_path_as_array, const char *) = "";
+  SVN_ERR(svn_ra_get_mergeinfo(source_ra_session, &mergeinfo_catalog,
                                source_repos_rel_path_as_array, source_rev,
                                svn_mergeinfo_inherited, TRUE, subpool));
 
+  if (mergeinfo_catalog)
+    SVN_ERR(svn_mergeinfo__add_prefix_to_catalog(&mergeinfo_catalog,
+                                                 mergeinfo_catalog,
+                                                 source_repos_rel_path,
+                                                 subpool, subpool));
+
   if (!mergeinfo_catalog)
     mergeinfo_catalog = apr_hash_make(subpool);
 
@@ -8416,7 +8555,8 @@ calculate_left_hand_side(const char **ur
                                   target_repos_rel_path,
                                   target_rev,
                                   source_rev,
-                                  ra_session,
+                                  source_ra_session,
+                                  target_ra_session,
                                   ctx,
                                   subpool));
 
@@ -8449,7 +8589,7 @@ calculate_left_hand_side(const char **ur
         svn_path_url_add_component2(source_repos_root,
                                     target_repos_rel_path,
                                     subpool),
-        &peg_revision, ra_session, NULL, ctx, subpool));
+        &peg_revision, target_ra_session, NULL, ctx, subpool));
       *url_left = apr_pstrdup(pool, youngest_url);
     }
 
@@ -8535,7 +8675,8 @@ svn_client_merge_reintegrate(const char 
   const svn_wc_entry_t *entry;
   const char *wc_repos_root, *source_repos_root;
   svn_opt_revision_t working_revision;
-  svn_ra_session_t *ra_session;
+  svn_ra_session_t *target_ra_session;
+  svn_ra_session_t *source_ra_session;
   const char *source_repos_rel_path, *target_repos_rel_path;
   const char *yc_ancestor_path;
   svn_revnum_t yc_ancestor_rev;
@@ -8567,11 +8708,12 @@ svn_client_merge_reintegrate(const char 
   /* Determine the working copy target's repository root URL. */
   working_revision.kind = svn_opt_revision_working;
   SVN_ERR(svn_client__get_repos_root(&wc_repos_root, target_wcpath,
-                                     &working_revision, adm_access, ctx, pool));
+                                     &working_revision, adm_access, ctx,
+                                     pool));
 
   /* Determine the source's repository root URL. */
-  SVN_ERR(svn_client__get_repos_root(&source_repos_root, url2,
-                                     peg_revision, adm_access, ctx, pool));
+  SVN_ERR(svn_client__get_repos_root(&source_repos_root, url2, peg_revision,
+                                     adm_access, ctx, pool));
 
   /* source_repos_root and wc_repos_root are required to be the same,
      as mergeinfo doesn't come into play for cross-repository merging. */
@@ -8581,16 +8723,6 @@ svn_client_merge_reintegrate(const char 
                                "'%s'"), svn_path_local_style(source, pool),
                              svn_path_local_style(target_wcpath, pool));
 
-  /* Open an RA session to our (common) repository root URL */
-
-  /* ### FIXME: Oops!  Can we open this session to a more conservative
-     ### location, in case the user lacks read access at the
-     ### repository root? */
-  SVN_ERR(svn_client__open_ra_session_internal(&ra_session, wc_repos_root,
-                                               NULL, NULL, NULL,
-                                               FALSE, FALSE, ctx,
-                                               pool));
-
   SVN_ERR(ensure_wc_reflects_repository_subtree(target_wcpath, ctx, pool));
 
   /* As the WC tree is "pure", use its last-updated-to revision as
@@ -8599,12 +8731,13 @@ svn_client_merge_reintegrate(const char 
      (with regard to the WC). */
   rev1 = entry->revision;
 
-  SVN_ERR(svn_client__path_relative_to_root(&source_repos_rel_path,
-                                            url2, NULL, FALSE,
-                                            ra_session, NULL, pool));
+  source_repos_rel_path =
+    url2 + 1 + strlen(svn_path_get_longest_ancestor(wc_repos_root, url2,
+                                                    pool));
+  source_repos_rel_path = svn_path_uri_decode(source_repos_rel_path, pool);
   SVN_ERR(svn_client__path_relative_to_root(&target_repos_rel_path,
                                             target_wcpath, wc_repos_root,
-                                            FALSE, ra_session, NULL, pool));
+                                            FALSE, NULL, NULL, pool));
 
   /* Can't reintegrate to or from the root of the repository. */
   if (svn_path_is_empty(source_repos_rel_path)
@@ -8623,9 +8756,16 @@ svn_client_merge_reintegrate(const char 
                                &wb, svn_depth_infinity, TRUE,
                                ctx->cancel_func, ctx->cancel_baton, pool));
 
-  SVN_ERR(svn_client__get_revision_number(&rev2, NULL,
-                                          ra_session, peg_revision,
-                                          source_repos_rel_path, pool));
+  /* Open two RA sessions, one to our source and one to our target. */
+  SVN_ERR(svn_client__open_ra_session_internal(&target_ra_session, entry->url,
+                                               NULL, NULL, NULL, FALSE, FALSE,
+                                               ctx, pool));
+  SVN_ERR(svn_client__open_ra_session_internal(&source_ra_session, url2,
+                                               NULL, NULL, NULL, FALSE, FALSE,
+                                               ctx, pool));
+
+  SVN_ERR(svn_client__get_revision_number(&rev2, NULL, source_ra_session,
+                                          peg_revision, "", pool));
 
   SVN_ERR(calculate_left_hand_side(&url1, &rev1,
                                    &unmerged_to_source_mergeinfo_catalog,
@@ -8635,10 +8775,17 @@ svn_client_merge_reintegrate(const char 
                                    source_repos_rel_path,
                                    source_repos_root,
                                    rev2,
-                                   ra_session,
+                                   source_ra_session,
+                                   target_ra_session,
                                    ctx,
                                    pool));
 
+  /* If the target was moved after the source was branched from it,
+     it is possible that the left URL differs from the target's current
+     URL.  If so, then adjust TARGET_RA_SESSION to point to the old URL. */
+  if (strcmp(url1, entry->url))
+    SVN_ERR(svn_ra_reparent(target_ra_session, url1, pool));
+
   SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_ancestor_path,
                                                    &yc_ancestor_rev,
                                                    url2, rev2,
@@ -8656,7 +8803,8 @@ svn_client_merge_reintegrate(const char 
          target?  If so, make sure we've merged a contiguous
          prefix. */
       err = ensure_all_missing_ranges_are_phantoms(
-        ra_session, unmerged_to_source_mergeinfo_catalog, pool);
+        target_repos_rel_path, target_ra_session,
+        unmerged_to_source_mergeinfo_catalog, pool);
       if (err)
         {
           if (err->apr_err == SVN_ERR_CLIENT_NOT_READY_TO_MERGE)
@@ -8696,7 +8844,9 @@ svn_client_merge_reintegrate(const char 
      ### related" in this source file).  We can merge to trunk without
      ### implementing this. */
   err = merge_cousins_and_supplement_mergeinfo(target_wcpath, entry,
-                                               adm_access, ra_session,
+                                               adm_access,
+                                               target_ra_session,
+                                               source_ra_session,
                                                url1, rev1, url2, rev2,
                                                yc_ancestor_rev,
                                                source_repos_root,
@@ -8803,7 +8953,7 @@ svn_client_merge_peg3(const char *source
 
   /* Do the real merge!  (We say with confidence that our merge
      sources are both ancestral and related.) */
-  err = do_merge(merge_sources, target_wcpath, entry, adm_access,
+  err = do_merge(NULL, merge_sources, target_wcpath, entry, adm_access,
                  TRUE, TRUE, same_repos, ignore_ancestry, force, dry_run,
                  record_only, FALSE, depth, merge_options,
                  &use_sleep, ctx, pool);

Modified: subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs.h?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs.h Wed Sep 29 15:38:10 2010
@@ -113,6 +113,9 @@ extern "C" {
 /* The minimum format number that stores node kinds in changed-paths lists. */
 #define SVN_FS_FS__MIN_KIND_IN_CHANGED_FORMAT 4
 
+/* The minimum format number that supports a configuration file (fsfs.conf) */
+#define SVN_FS_FS__MIN_CONFIG_FILE 4
+
 /* Private FSFS-specific data shared between all svn_txn_t objects that
    relate to a particular transaction in a filesystem (as identified
    by transaction id and filesystem UUID).  Objects of this type are

Modified: subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs_fs.c?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/fs_fs.c Wed Sep 29 15:38:10 2010
@@ -33,6 +33,7 @@
 
 #include "svn_pools.h"
 #include "svn_fs.h"
+#include "svn_dirent_uri.h"
 #include "svn_path.h"
 #include "svn_hash.h"
 #include "svn_props.h"
@@ -1221,11 +1222,29 @@ upgrade_body(void *baton, apr_pool_t *po
   svn_fs_t *fs = baton;
   int format, max_files_per_dir;
   const char *format_path = path_format(fs, pool);
+  svn_node_kind_t kind;
 
   /* Read the FS format number and max-files-per-dir setting. */
   SVN_ERR(read_format(&format, &max_files_per_dir, format_path, pool));
 
-  /* If we're already up-to-date, there's nothing to be done here. */
+  /* If the config file does not exist, create one. */
+  SVN_ERR(svn_io_check_path(svn_dirent_join(fs->path, PATH_CONFIG, pool),
+                            &kind, pool));
+  switch (kind)
+    {
+    case svn_node_none:
+      SVN_ERR(write_config(fs, pool));
+      break;
+    case svn_node_dir:
+      return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
+                               _("'%s' is a directory. Please move it out of "
+                                 "the way and try again"),
+                               svn_dirent_join(fs->path, PATH_CONFIG, pool));
+    default:
+      break;
+    }
+
+  /* If we're already up-to-date, there's nothing else to be done here. */
   if (format == SVN_FS_FS__FORMAT_NUMBER)
     return SVN_NO_ERROR;
 
@@ -1423,15 +1442,69 @@ svn_fs_fs__hotcopy(const char *src_path,
                       pool));
   SVN_ERR(check_format(format));
 
+  /* Try to copy the config.
+   *
+   * ### We try copying the config file before doing anything else,
+   * ### because higher layers will abort the hotcopy if we throw
+   * ### an error from this function, and that renders the hotcopy
+   * ### unusable anyway. */
+  if (format >= SVN_FS_FS__MIN_CONFIG_FILE)
+    {
+      svn_error_t *err;
+
+      err = svn_io_dir_file_copy(src_path, dst_path, PATH_CONFIG, pool);
+      if (err)
+        {
+          if (APR_STATUS_IS_ENOENT(err->apr_err))
+            {
+              /* 1.6.0 to 1.6.11 did not copy the configuration file during
+               * hotcopy. So if we're hotcopying a repository which has been
+               * created as a hotcopy itself, it's possible that fsfs.conf
+               * does not exist. Ask the user to re-create it.
+               *
+               * ### It would be nice to make this a non-fatal error,
+               * ### but this function does not get an svn_fs_t object
+               * ### so we have no way of just printing a warning via
+               * ### the fs->warning() callback. */
+
+              const char *msg;
+              const char *src_abspath;
+              const char *dst_abspath;
+              const char *config_relpath;
+              svn_error_t *err2;
+
+              config_relpath = svn_dirent_join(src_path, PATH_CONFIG, pool);
+              err2 = svn_dirent_get_absolute(&src_abspath, src_path, pool);
+              if (err2)
+                return svn_error_compose_create(err, err2);
+              err2 = svn_dirent_get_absolute(&dst_abspath, dst_path, pool);
+              if (err2)
+                return svn_error_compose_create(err, err2);
+              
+              /* ### hack: strip off the 'db/' directory from paths so
+               * ### they make sense to the user */
+              src_abspath = svn_dirent_dirname(src_abspath, pool);
+              dst_abspath = svn_dirent_dirname(dst_abspath, pool);
+
+              msg = apr_psprintf(pool,
+                                 _("Failed to create hotcopy at '%s'. "
+                                   "The file '%s' is missing from the source "
+                                   "repository. Please create this file, for "
+                                   "instance by running 'svnadmin upgrade %s'"),
+                                 dst_abspath, config_relpath, src_abspath);
+              return svn_error_quick_wrap(err, msg);
+            }
+          else
+            return err;
+        }
+    }
+
   /* Copy the current file. */
   SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_CURRENT, pool));
 
   /* Copy the uuid. */
   SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_UUID, pool));
 
-  /* Copy the config. */
-  SVN_ERR(svn_io_dir_file_copy(src_path, dst_path, PATH_CONFIG, pool));
-
   /* Copy the min unpacked rev, and read its value. */
   if (format >= SVN_FS_FS__MIN_PACKED_FORMAT)
     {
@@ -5956,11 +6029,12 @@ svn_fs_fs__reserve_copy_id(const char **
 static svn_error_t *
 write_revision_zero(svn_fs_t *fs)
 {
+  const char *path_revision_zero = path_rev(fs, 0, fs->pool);
   apr_hash_t *proplist;
   svn_string_t date;
 
   /* Write out a rev file for revision 0. */
-  SVN_ERR(svn_io_file_create(path_rev(fs, 0, fs->pool),
+  SVN_ERR(svn_io_file_create(path_revision_zero,
                              "PLAIN\nEND\nENDREP\n"
                              "id: 0.0.r0/17\n"
                              "type: dir\n"
@@ -5969,6 +6043,7 @@ write_revision_zero(svn_fs_t *fs)
                              "2d2977d1c96f487abe4a1e202dd03b4e\n"
                              "cpath: /\n"
                              "\n\n17 107\n", fs->pool));
+  SVN_ERR(svn_io_set_file_read_only(path_revision_zero, FALSE, fs->pool));
 
   /* Set a date on revision 0. */
   date.data = svn_time_to_cstring(apr_time_now(), fs->pool);
@@ -7002,6 +7077,8 @@ pack_shard(const char *revs_dir,
   SVN_ERR(svn_stream_close(manifest_stream));
   SVN_ERR(svn_stream_close(pack_stream));
   SVN_ERR(svn_fs_fs__dup_perms(pack_file_dir, shard_path, pool));
+  SVN_ERR(svn_io_set_file_read_only(pack_file_path, FALSE, pool));
+  SVN_ERR(svn_io_set_file_read_only(manifest_file_path, FALSE, pool));
 
   /* Update the min-unpacked-rev file to reflect our newly packed shard.
    * (ffd->min_unpacked_rev will be updated by open_pack_or_rev_file().)

Modified: subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/lock.c?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/1.6.x-issue3646/subversion/libsvn_fs_fs/lock.c Wed Sep 29 15:38:10 2010
@@ -320,7 +320,7 @@ set_lock(svn_fs_t *fs,
          apr_pool_t *pool)
 {
   svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
-  svn_stringbuf_t *last_child = svn_stringbuf_create("", pool);
+  const char *lock_digest_path = NULL;
   apr_pool_t *subpool;
 
   SVN_ERR_ASSERT(lock);
@@ -351,15 +351,16 @@ set_lock(svn_fs_t *fs,
         {
           this_lock = lock;
           lock = NULL;
-          svn_stringbuf_set(last_child, digest_file);
+          lock_digest_path = apr_pstrdup(pool, digest_file);
         }
       else
         {
           /* If we already have an entry for this path, we're done. */
-          if (apr_hash_get(this_children, last_child->data, last_child->len))
+          if (apr_hash_get(this_children, lock_digest_path,
+                           APR_HASH_KEY_STRING))
             break;
-          apr_hash_set(this_children, last_child->data,
-                       last_child->len, (void *)1);
+          apr_hash_set(this_children, lock_digest_path,
+                       APR_HASH_KEY_STRING, (void *)1);
         }
       SVN_ERR(write_digest_file(this_children, this_lock, fs,
                                 digest_path, subpool));
@@ -382,13 +383,13 @@ delete_lock(svn_fs_t *fs,
             apr_pool_t *pool)
 {
   svn_stringbuf_t *this_path = svn_stringbuf_create(lock->path, pool);
-  svn_stringbuf_t *child_to_kill = svn_stringbuf_create("", pool);
+  const char *child_to_kill = NULL;
   apr_pool_t *subpool;
 
   SVN_ERR_ASSERT(lock);
 
   /* Iterate in reverse, deleting the lock for LOCK->path, and then
-     pruning entries from its parents. */
+     deleting its entry as it appears in each of its parents. */
   subpool = svn_pool_create(pool);
   while (1729)
     {
@@ -406,32 +407,27 @@ delete_lock(svn_fs_t *fs,
       SVN_ERR(read_digest_file(&this_children, &this_lock, fs,
                                digest_path, subpool));
 
-      /* If we are supposed to drop the last entry from this path's
-         children list, do so. */
-      if (child_to_kill->len)
-        apr_hash_set(this_children, child_to_kill->data,
-                     child_to_kill->len, NULL);
-
       /* Delete the lock (first time through only). */
       if (lock)
         {
           this_lock = NULL;
           lock = NULL;
+          child_to_kill = apr_pstrdup(pool, digest_file);
         }
 
+      if (child_to_kill)
+        apr_hash_set(this_children, child_to_kill, APR_HASH_KEY_STRING, NULL);
+
       if (! (this_lock || apr_hash_count(this_children) != 0))
         {
           /* Special case:  no goodz, no file.  And remember to nix
              the entry for it in its parent. */
-          svn_stringbuf_set(child_to_kill,
-                            svn_path_basename(digest_path, subpool));
           SVN_ERR(svn_io_remove_file(digest_path, subpool));
         }
       else
         {
           SVN_ERR(write_digest_file(this_children, this_lock, fs,
                                     digest_path, subpool));
-          svn_stringbuf_setempty(child_to_kill);
         }
 
       /* Prep for next iteration, or bail if we're done. */

Modified: subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_neon/fetch.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_neon/fetch.c?rev=1002684&r1=1002683&r2=1002684&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_neon/fetch.c (original)
+++ subversion/branches/1.6.x-issue3646/subversion/libsvn_ra_neon/fetch.c Wed Sep 29 15:38:10 2010
@@ -1688,8 +1688,10 @@ start_element(int *elem, void *userdata,
       if (! rb->receiving_all)
         break;
 
+      base_checksum = svn_xml_get_attr_value("base-checksum", atts);
+
       SVN_ERR((*rb->editor->apply_textdelta)(rb->file_baton,
-                                             NULL, /* ### base_checksum */
+                                             base_checksum,
                                              rb->file_pool,
                                              &(rb->whandler),
                                              &(rb->whandler_baton)));