Christophe Royer wrote on Sat, 14 May 2022 23:28 +00:00: > Thank you for looking into this, taking the time to clean up the script > and share your comments. Lessons learnt. > > I will likely revert (maybe manually) those invalid mergeinfo. >
Sure. I recommend that you use a record-only reverse merge, as opposed to a propedit. The latter could cause rather a lot more fun if you commit a syntax error to the repository. > Still not quite sure of the consequences, and if this situation could be > detected. Maybe a defect or enhancement should be logged - but I am not > familiar how this done. > See <https://subversion.apache.org/reporting-issues.html>. You've already posted a thread and gotten someone to validate/buddy your complaint (me, hereby), so feel free to submit an issue. If you wish, you can wait a day or two before filing anything, in case any of the other devs respond to my previous post with the analysis and the specific question. > Thanks again. > You're welcome. Daniel > Christophe > > On 5/14/2022 5:39 AM, Daniel Shahaf wrote: >> Christophe Royer wrote on Fri, May 13, 2022 at 10:45:14 -0700: >>> Daniel, the first script I sent may confuse things a little, because of the >>> tree conflict. >>> Here is another script that avoid that issue. The problem is the same: it >>> looks like the mergeinfo does not match the state of the branch. >> >> [ There's a longish preface here about the reproduction script and its >> output. For Christophe's mergeinfo-related question, skip the >> triple-braced part. ] >> >> {{{ >> Here's a Unix version of your script: >> >> [[[ >> #!/usr/bin/env zsh >> alias '@ECHO'=: REM=: ECHO.=echo ECHO=echo md=mkdir SET='() { >> repoRoot=file://$PWD/repo }' TYPE=cat >> rd() { rm -rf -- ${argv:#/*} } >> s="$(< script.bat tr '\\' '/' | sed -e 's/%repoRoot%/$repoRoot/g' -e >> 's/FileA/fileA/g' -e 's/FileB/fileB/g' | perl -C -Mutf8 -pE $'y/()\'"/{}’”/ >> if /ECHO|REM/')" >> setopt ignorebraces >> set -ex >> eval "$s" >> ]]] >> >> That assumes ./script.bat contains the script you posted, without the >> delimiter lines. It's written as a dense multilingual mix because it >> doesn't need to be team-maintained indefinitely going forward, so I >> optimized for whatever was fastest to implement. It'd be fairly easy to >> port that to sh if need be. >> >> Also, it would also have been helpful if you hadn't used different >> letter cases to refer to a single on-disk file, to make it easier to >> port the script; if the script began by deleting ./repo ./WC >> ./workingCopy, so it would be easier to re-run it; and if the script had >> been attached rather than inlined, because long lines were hard-wrapped >> along the way; and if you'd posted your script's _output_ as well as its >> code, so those of us on other platforms would be able to analyze the >> script without porting it first. Anyway, no harm done. >> >> Here's the script's output: >> >>> +(eval):1> : off >>> +(eval):2> : -- Script to test handling of merge info during a 2-url merge >>> +(eval):3> : -- this time, we setup to avoid tree conflict: we don’t add >>> file after the branches are created, >>> +(eval):4> : -- we just update them >>> +(eval):7> : script.bat script.zsh >>> +(eval):8> : 2 files in trunk: fileA and fileB >>> +(eval):9> : 2 branches >>> +(eval):10> : edit fileA in trunk, merge to foo >>> +(eval):11> : edit fileB in foo >>> +(eval):12> : diff between trunk and foo do NOT show fileA '{merged,' same >>> im 'both}' >>> +(eval):13> : 2-url merge trunk to foo into bar: should bring changes to >>> fileB only >>> +(eval):14> : script.bat script.zsh >>> +(eval):17> echo >>> >>> +(eval):18> echo -- Create empty repo in current folder >>> -- Create empty repo in current folder >>> +(eval):19> mkdir repo >>> +(eval):20> svnadmin create --fs-type fsfs repo/testRepo >>> +(eval):22> '(anon)' 'repoRoot=file:///%CD:/=/%/repo' >>> +(anon):0> repoRoot=file:///scratch/tmp.9SbJ9D2q2o/repo >>> +(eval):24> echo >>> >>> +(eval):25> echo -- Create sructure to import in repo >>> -- Create sructure to import in repo >>> +(eval):26> mkdir WC >>> +(eval):27> mkdir WC/trunk >>> +(eval):28> mkdir WC/branches >>> +(eval):29> svn import WC file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo >>> -mImporting >>> Adding WC/branches >>> Adding WC/trunk >>> Committing transaction... >>> Committed revision 1. >>> +(eval):30> rd /s /Q WC >>> +rd:0> rm -rf -- WC >>> +(eval):32> echo >>> >>> +(eval):33> echo -- Check out working copy of the entire repo >>> -- Check out working copy of the entire repo >>> +(eval):34> svn co file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo workingCopy >>> A workingCopy/branches >>> A workingCopy/trunk >>> Checked out revision 1. >>> +(eval):36> echo >>> >>> +(eval):37> echo -- Play in trunk, adding two files >>> -- Play in trunk, adding two files >>> +(eval):38> pushd workingCopy/trunk >>> +(eval):39> echo Adding fileA in trunk >>> +(eval):40> echo Adding fileB in trunk >>> +(eval):41> svn add fileA.txt fileB.txt >>> A fileA.txt >>> A fileB.txt >>> +(eval):42> svn commit . '-mAdding 2 files to trunk' >>> Adding fileA.txt >>> Adding fileB.txt >>> Transmitting file data ..done >>> Committing transaction... >>> Committed revision 2. >>> +(eval):43> popd >>> +(eval):45> echo >>> >>> +(eval):46> echo -- Create 2 branches from trunk. This does not create any >>> mergeinfo >>> -- Create 2 branches from trunk. This does not create any mergeinfo >>> +(eval):47> svn copy file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/trunk >>> file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/branches/foo '-mbranching to >>> foo' --parents >>> Committing transaction... >>> Committed revision 3. >>> +(eval):48> svn copy file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/trunk >>> file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/branches/bar '-mbranching to >>> bar' --parents >>> Committing transaction... >>> Committed revision 4. >>> +(eval):50> echo >>> >>> +(eval):51> echo -- Edit fileA in trunk >>> -- Edit fileA in trunk >>> +(eval):52> svn update workingCopy >>> Updating 'workingCopy': >>> A workingCopy/branches/bar >>> A workingCopy/branches/bar/fileA.txt >>> A workingCopy/branches/bar/fileB.txt >>> A workingCopy/branches/foo >>> A workingCopy/branches/foo/fileA.txt >>> A workingCopy/branches/foo/fileB.txt >>> Updated to revision 4. >>> +(eval):53> pushd workingCopy/trunk >>> +(eval):54> echo Editing fileA in trunk >>> +(eval):55> svn commit . '-mEditing fileA in trunk' >>> Sending fileA.txt >>> Transmitting file data .done >>> Committing transaction... >>> Committed revision 5. >>> +(eval):56> popd >>> +(eval):57> svn update workingCopy >>> Updating 'workingCopy': >>> At revision 5. >>> +(eval):59> echo >>> >>> +(eval):60> echo -- Merge latest from trunk to foo. This creates mergeinfo >>> in foo and brings fileA changes >>> -- Merge latest from trunk to foo. This creates mergeinfo in foo and brings >>> fileA changes >>> +(eval):61> svn merge file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/trunk >>> workingCopy/branches/foo >>> --- Merging r3 through r5 into 'workingCopy/branches/foo': >>> U workingCopy/branches/foo/fileA.txt >>> --- Recording mergeinfo for merge of r3 through r5 into >>> 'workingCopy/branches/foo': >>> U workingCopy/branches/foo >>> +(eval):62> svn commit workingCopy/branches/foo '-mMerging latest from >>> trunk to foo' >>> Sending workingCopy/branches/foo >>> Sending workingCopy/branches/foo/fileA.txt >>> Transmitting file data .done >>> Committing transaction... >>> Committed revision 6. >>> +(eval):63> svn update workingCopy >>> Updating 'workingCopy': >>> At revision 6. >>> +(eval):65> echo >>> >>> +(eval):66> echo -- Edit fileB in foo >>> -- Edit fileB in foo >>> +(eval):67> svn update workingCopy >>> Updating 'workingCopy': >>> At revision 6. >>> +(eval):68> pushd workingCopy/branches/foo >>> +(eval):69> echo Editing fileB in foo >>> +(eval):70> svn commit . '-mEditing fileB in foo' >>> Sending fileB.txt >>> Transmitting file data .done >>> Committing transaction... >>> Committed revision 7. >>> +(eval):71> popd >>> +(eval):72> svn update workingCopy >>> Updating 'workingCopy': >>> At revision 7. >>> +(eval):75> echo >>> >>> +(eval):76> echo -- Perform 2-URL merge to get diff between trunk and foo >>> and apply to bar >>> -- Perform 2-URL merge to get diff between trunk and foo and apply to bar >>> +(eval):77> echo >>> >>> +(eval):78> echo -- Showing the diff first: fileA is not listed '{only' >>> 'fileB}' >>> -- Showing the diff first: fileA is not listed {only fileB} >>> +(eval):79> svn diff file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/trunk >>> file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/branches/foo >>> Index: fileB.txt >>> =================================================================== >>> --- fileB.txt (.../trunk) (revision 7) >>> +++ fileB.txt (.../branches/foo) (revision 7) >>> @@ -1 +1,2 @@ >>> Adding fileB in trunk >>> +Editing fileB in foo >>> Index: . >>> =================================================================== >>> --- . (.../trunk) (revision 7) >>> +++ . (.../branches/foo) (revision 7) >>> >>> Property changes on: . >>> ___________________________________________________________________ >>> Added: svn:mergeinfo >>> ## -0,0 +0,1 ## >>> Merged /trunk:r3-5 >>> +(eval):80> echo >>> >>> +(eval):82> echo -- Now merging >>> -- Now merging >>> +(eval):83> svn merge file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/trunk >>> file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/branches/foo >>> workingCopy/branches/bar >>> --- Merging differences between repository URLs into >>> 'workingCopy/branches/bar': >>> U workingCopy/branches/bar/fileB.txt >>> U workingCopy/branches/bar >>> --- Recording mergeinfo for merge between repository URLs into >>> 'workingCopy/branches/bar': >>> G workingCopy/branches/bar >>> +(eval):84> svn commit workingCopy/branches/bar '-mMerging diff from trunk >>> to foo into bar' >>> Sending workingCopy/branches/bar >>> Sending workingCopy/branches/bar/fileB.txt >>> Transmitting file data .done >>> Committing transaction... >>> Committed revision 8. >>> +(eval):85> svn update workingCopy >>> Updating 'workingCopy': >>> At revision 8. >>> +(eval):87> echo >>> >>> +(eval):88> echo -- In bar, fileA does not have the trunk changes, good >>> -- In bar, fileA does not have the trunk changes, good >>> +(eval):89> cat workingCopy/branches/bar/fileA.txt >>> Adding fileA in trunk >>> +(eval):91> echo >>> >>> +(eval):92> echo -- But the trunk revision where fileA was changed '{r5}' >>> shows as merged in bar >>> -- But the trunk revision where fileA was changed {r5} shows as merged in >>> bar >>> +(eval):93> echo -- rev5 of fileA in the trunk >>> -- rev5 of fileA in the trunk >>> +(eval):94> svn cat >>> file:///scratch/tmp.9SbJ9D2q2o/repo/testRepo/trunk/fileA.txt@5 >>> Adding fileA in trunk >>> Editing fileA in trunk >>> +(eval):97> echo >>> >>> +(eval):98> echo -- mergeinfo porperty for bar >>> -- mergeinfo porperty for bar >>> +(eval):99> svn pg svn:mergeinfo workingCopy/branches/bar >>> /branches/foo:3-7 >>> /trunk:4-5 >>> +(eval):100> echo >>> >>> +(eval):101> echo -- svn mergeinfo between trunk and bar >>> -- svn mergeinfo between trunk and bar >>> +(eval):102> svn mergeinfo workingCopy/trunk workingCopy/branches/bar >>> youngest common ancestor >>> | last full merge >>> | | tip of branch >>> | | | repository path >>> >>> 3 5 8 >>> | | | >>> -------| |------------ trunk >>> \ \ >>> \ \ >>> --| |------------ branches/bar >>> | >>> WC >> >> And 'log -v' of the resulting repository: >> >>> ------------------------------------------------------------------------ >>> r8 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> M /branches/bar >>> M /branches/bar/fileB.txt >>> >>> Merging diff from trunk to foo into bar >>> ------------------------------------------------------------------------ >>> r7 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> M /branches/foo/fileB.txt >>> >>> Editing fileB in foo >>> ------------------------------------------------------------------------ >>> r6 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> M /branches/foo >>> M /branches/foo/fileA.txt >>> >>> Merging latest from trunk to foo >>> ------------------------------------------------------------------------ >>> r5 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> M /trunk/fileA.txt >>> >>> Editing fileA in trunk >>> ------------------------------------------------------------------------ >>> r4 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> A /branches/bar (from /trunk:3) >>> >>> branching to bar >>> ------------------------------------------------------------------------ >>> r3 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> A /branches/foo (from /trunk:2) >>> >>> branching to foo >>> ------------------------------------------------------------------------ >>> r2 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> A /trunk/fileA.txt >>> A /trunk/fileB.txt >>> >>> Adding 2 files to trunk >>> ------------------------------------------------------------------------ >>> r1 | daniel | 2022-05-14 11:55:46 +0000 (Sat, 14 May 2022) | 1 line >>> Changed paths: >>> A /branches >>> A /trunk >>> >>> Importing >>> ------------------------------------------------------------------------ >> }}} >> >> So, here's r8: >> >> [[[ >> % cd workingCopy >> % svn di -c 8 >> Index: branches/bar/fileB.txt >> =================================================================== >> --- branches/bar/fileB.txt (revision 7) >> +++ branches/bar/fileB.txt (revision 8) >> @@ -1 +1,2 @@ >> Adding fileB in trunk >> +Editing fileB in foo >> Index: branches/bar >> =================================================================== >> --- branches/bar (revision 7) >> +++ branches/bar (revision 8) >> >> Property changes on: branches/bar >> ___________________________________________________________________ >> Added: svn:mergeinfo >> ## -0,0 +0,2 ## >> Merged /trunk:r4-5 >> Merged /branches/foo:r3-7 >> ]]] >> >> The question is why r8 adds mergeinfo for trunk:5 even though it doesn't >> bring in the changes to fileA.txt made in that revision. >> >> I'm guessing the 2-URL merge added mergeinfo for trunk:4-5 because >> trunk:4-5 appear in the diff between trunk@HEAD and foo@HEAD. >> Similarly, the changes to fileA.txt in r5 weren't part of that diff and >> therefore weren't added to bar. >> >> The resulting state is definitely incorrect. It can be corrected by >> an appropriate record-only reverse merge (e.g., «svn merge --record-only >> -c-5 trunk branches/bar»). >> >> Could Subversion get this right by default? Good question. I don't >> remember whether this has been discussed before. If anyone else does, >> do jump in ☺ >> >> Cheers, >> >> Daniel >> >>> -----start of 2nd script >>> ⋮ >>> -----end of 2nd script >>> >>> Christophe >>> >>> On 5/12/2022 4:41 PM, Christophe Royer wrote: >>>> Thank you Daniel, below is the script I used (line wrapping might mess >>>> up a few lines, sorry) >>>> >>>> As I was cleaning it up, I realized that in 1.6.17 (yes, still using it, >>>> and where I saw the issue first) the behavior is different (2-url merge >>>> gives me a tree conflict). >>>> >>>> I am really tempted to delete the extra merginfo-that is my biggest >>>> concern at this time. >>>> >>>> --------- start of script (dos cmd) >>>> ⋮ >>>> ------------------ end of script >>>> Christophe >>>> >>>> On 5/12/2022 10:52 AM, Daniel Shahaf wrote: >>>>> Could you post the script, please? It's hard to answer your question >>>>> when it describes the details verbally rather than machine-readably. >>>>> >>>>> It sounds like a supported scenario. >>>>> >>>>> Cheers, >>>>> >>>>> Daniel >>>>> >>>>> >>>>> Christophe Royer wrote on Fri, 06 May 2022 21:46 +00:00: >>>>>> I recently saw some mergeinfo that I can explain but still look wrong to >>>>>> me. Not sure if it’s a wrong usage of svn, or possibly a defect, and so >>>>>> far I have not seen any post about this. Here is the scenario (I have a >>>>>> script, batch file for windows, if needed): >>>>>> >>>>>> Seen first using svn 1.6.17, confirmed with with svn 1.14.2 >>>>>> >>>>>> Here is the setup: >>>>>> >>>>>> * Create repo with trunk and branches >>>>>> * Add a file to trunk >>>>>> * Create 2 branches from trunk, foo and bar (at this point, neither >>>>>> branch has mergeinfo for trunk) >>>>>> * In foo, edit the existing file >>>>>> * Make some changes in trunk (I added a file) >>>>>> * Merge trunk to foo (this bring the new file in and adds mergeinfo >>>>>> for trunk, including the revision where the new file was added) >>>>>> >>>>>> Now the fun part: >>>>>> >>>>>> * Do a 2-url merge to merge the changes solely made in foo, >>>>>> and apply >>>>>> them to bar >>>>>> >>>>>> The diff between trunk and foo shows only one file was edited (the >>>>>> second file does not show, since merge made it the same in trunk and >>>>>> foo). But the diff also shows mergeinfo changed between trunk and foo, >>>>>> so those get merged to bar, which seem appropriate. >>>>>> >>>>>> However, it follows that bar now indicates that it has those changes >>>>>> from trunk (esp. the one revision where the file was added in trunk) but >>>>>> of course that file is not in bar…And this occurs whether or not I use >>>>>> –ignore-ancestry. >>>>>> >>>>>> I could use cherrypicking instead, but I did not want to have to pick >>>>>> specific changes (I really want all the changes made in foo, but only >>>>>> those changes) >>>>>> >>>>>> So, >>>>>> >>>>>> 1)is that a misuse of svn, an unsupported scenario?. Or is there room >>>>>> for improvement to the mergeinfo management? >>>>>> >>>>>> 2)should I manually delete those “unwanted” mergeinfo? If I don’t, I >>>>>> have an idea of the issues I can run into. But I am afraid to miss >>>>>> something here, and removing them would cause other issues. >>>>>> >>>>>> >>>>>> Thanks >>>>>> >>>>>> Christophe