You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@subversion.apache.org by Alex Wilton <aw...@roboticresearch.com> on 2020/04/24 14:34:37 UTC

non-inheritable revisions in mergeinfo being later incorrectly marked as inheritable

Hello, 

This is my first time posting to this mailing list so apologies for any newbie mistakes. I couldn't find a bug report discussing this particular issue and while I'm fairly certain this isn't intended behavior, I wanted to post to users@ just in case there was some strange reasoning for why this is supposed to happen. 

I'll give the gist of what the issue is and then I'll post the sequence of commands I used to reproduce the entire issue, with some intermediate diffs to show whats going on. 

Essentially, I have a full checkout of trunk containing the following directory structure: 



file1.txt 
my-project/fileA.txt 
not-my-project/fileA.txt 



Then we have a copy of trunk, called "my-branch" which has everything checked out except for not-my-project. 
We make a sequence of commits in trunks, each of which is followed by a sync merge from trunk to my-branch. The first commit changes "file1.txt" and the mergeinfo reflects a full merge (good). The next two commits involve changes to not-my-project, and the mergeinfo of my-branch reflects these revisions as non-inheritable (so, partially merged. also good). Finally, we make a commit to "file1.txt" again, but when merging that over, the mergeinfo in my-branch suddenly reverse-merges the non-inheritable ranges and merges them as inheritable, despite the fact that these revisions have not had their changes brought in (we still don't have not-my-project checked out). The consequence is that SVN now thinks that my-branch has had not-my-project updated and a subsequent reintegrate merge from my-branch to trunk reverses all of the changes made in trunk to match what it looked like on the creation of my-branch. It does this with no complaints. Here is all of the steps I did to recreate that: 

Steps for creating trunk and my-branch: 

BQ_BEGIN

awilton@metompkin:~/svnplayground/bug_repo_wc$ svn co file:///home/awilton/svnplayground/repo/bug_repo . 
Checked out revision 0. 
awilton@metompkin:~/svnplayground/bug_repo_wc$ svn mkdir trunk 
A trunk 
awilton@metompkin:~/svnplayground/bug_repo_wc$ svn mkdir branches 
A branches 
awilton@metompkin:~/svnplayground/bug_repo_wc$ svn commit -m "Created trunk and branches." 
Adding branches 
Adding trunk 
Committing transaction... 
Committed revision 1. 
awilton@metompkin:~/svnplayground/bug_repo_wc$ svn up 
Updating '.': 
At revision 1. 
awilton@metompkin:~/svnplayground/bug_repo_wc$ cd trunk 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo file1 > file1.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn add file1.txt 
A file1.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn mkdir my-project 
A my-project 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn mkdir not-my-project 
A not-my-project 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo my file > my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo not my file > not-my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn add my-project/fileA.txt 
A my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn add not-my-project/fileA.txt 
A not-my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn stat 
A file1.txt 
A my-project 
A my-project/fileA.txt 
A not-my-project 
A not-my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn commit -m "Set up trunk." 
Adding file1.txt 
Adding my-project 
Adding my-project/fileA.txt 
Adding not-my-project 
Adding not-my-project/fileA.txt 
Transmitting file data ...done 
Committing transaction... 
Committed revision 2. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ cd .. 
awilton@metompkin:~/svnplayground/bug_repo_wc$ svn up 
Updating '.': 
At revision 2. 
awilton@metompkin:~/svnplayground/bug_repo_wc$ svn cp ^/trunk ^/branches/my-branch -m "Created my-branch from trunk" 
Committing transaction... 
Committed revision 3. 
awilton@metompkin:~/svnplayground/bug_repo_wc$ cd branches/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches$ svn up my-branch --set-depth=files 
Updating 'my-branch': 
A my-branch 
A my-branch/file1.txt 
Updated to revision 3. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches$ cd my-branch/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up my-project --set-depth=infinity 
Updating 'my-project': 
A my-project 
A my-project/fileA.txt 
Updated to revision 3. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ ls 
file1.txt my-project 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ ls my-project/ 
fileA.txt 

BQ_END

Change 1 to trunk, changing a shared file, "file1.txt": 

BQ_BEGIN

awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 1 to file1 > file1.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn commit -m "Changed file1 in trunk" 
Sending file1.txt 
Transmitting file data .done 
Committing transaction... 
Committed revision 4. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up 
Updating '.': 
At revision 4. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn merge ^/trunk 
--- Merging r3 through r4 into '.': 
U file1.txt 
--- Recording mergeinfo for merge of r3 through r4 into '.': 
U . 
--- Recording mergeinfo for merge of r3 through r4 into 'file1.txt': 
U file1.txt 
--- Eliding mergeinfo from 'file1.txt': 
U file1.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn diff 
Index: file1.txt 
=================================================================== 
--- file1.txt (revision 4) 
+++ file1.txt (working copy) 
@@ -1 +1 @@ 
-file1 
+change 1 to file1 
Index: . 
=================================================================== 
--- . (revision 4) 
+++ . (working copy) 

Property changes on: . 
___________________________________________________________________ 
Added: svn:mergeinfo 
## -0,0 +0,1 ## 
Merged /trunk:r3-4 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn commit -m "Merge from trunk to my-branch." 
Sending . 
Sending file1.txt 
Transmitting file data .done 
Committing transaction... 
Committed revision 5. 

BQ_END

Change 2 to trunk, changing a file not checked out in my-branch, "not-my-project/fileA.txt": 

BQ_BEGIN

awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn up 
Updating '.': 
At revision 5. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 1 to not my file > not-my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn commit -m "not my file changed." 
Sending not-my-project/fileA.txt 
Transmitting file data .done 
Committing transaction... 
Committed revision 6. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up 
Updating '.': 
At revision 6. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn merge ^/trunk 
--- Merging r5 through r6 into '.': 
Skipped missing target: 'not-my-project' 
U not-my-project/fileA.txt 
--- Recording mergeinfo for merge of r5 through r6 into '.': 
U . 
Summary of conflicts: 
Skipped paths: 1 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn diff 
Index: . 
=================================================================== 
--- . (revision 6) 
+++ . (working copy) 

Property changes on: . 
___________________________________________________________________ 
Modified: svn:mergeinfo 
## -0,0 +0,1 ## 
Merged /trunk:r5-6* 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn commit -m "Merge from trunk to my-branch." 
Sending . 
Committing transaction... 
Committed revision 7. 

BQ_END

Change 3 to trunk, changing a file checked out in my-branch, "file1.txt" and a file not checked out in my-branch, "not-my-project/fileA.txt": 

BQ_BEGIN

awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 2 to file1 > file1.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 2 to not my file > not-my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn commit -m "Changed file1 and not my file." 
Sending file1.txt 
Sending not-my-project/fileA.txt 
Transmitting file data ..done 
Committing transaction... 
Committed revision 8. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up 
Updating '.': 
At revision 8. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn merge ^/trunk 
--- Merging r7 through r8 into '.': 
U file1.txt 
Skipped missing target: 'not-my-project' 
U not-my-project/fileA.txt 
--- Recording mergeinfo for merge of r5 through r8 into '.': 
U . 
--- Recording mergeinfo for merge of r5 through r8 into 'file1.txt': 
G file1.txt 
Summary of conflicts: 
Skipped paths: 1 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn diff 
Index: file1.txt 
=================================================================== 
--- file1.txt (revision 8) 
+++ file1.txt (working copy) 
@@ -1 +1 @@ 
-change 1 to file1 
+change 2 to file1 

Property changes on: file1.txt 
___________________________________________________________________ 
Added: svn:mergeinfo 
## -0,0 +0,1 ## 
Merged /trunk/file1.txt:r3-8 
Index: . 
=================================================================== 
--- . (revision 8) 
+++ . (working copy) 

Property changes on: . 
___________________________________________________________________ 
Modified: svn:mergeinfo 
## -0,0 +0,1 ## 
Merged /trunk:r7-8* 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn commit -m "Merge from trunk to my-branch." 
Sending . 
Sending file1.txt 
Transmitting file data .done 
Committing transaction... 
Committed revision 9. 

BQ_END

Change 4 on trunk, changing a file checked out in my-branch, "file1.txt". Notice that after the merge, revisions 5-8* are reverse-merged and then merged with inheritability, despite not-my-project changes missing in this branch not being brought over (because its not checked out): 

BQ_BEGIN

awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn up 
Updating '.': 
At revision 9. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 3 file1 > file1.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn commit -m "Changed file1 on trunk." 
Sending file1.txt 
Transmitting file data .done 
Committing transaction... 
Committed revision 10. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up 
Updating '.': 
At revision 10. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn merge ^/trunk 
--- Merging r9 through r10 into '.': 
U file1.txt 
--- Recording mergeinfo for merge of r5 through r10 into '.': 
U . 
--- Recording mergeinfo for merge of r5 through r10 into 'file1.txt': 
U file1.txt 
--- Eliding mergeinfo from 'file1.txt': 
U file1.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn diff 
Index: file1.txt 
=================================================================== 
--- file1.txt (revision 10) 
+++ file1.txt (working copy) 
@@ -1 +1 @@ 
-change 2 to file1 
+change 3 file1 

Property changes on: file1.txt 
___________________________________________________________________ 
Deleted: svn:mergeinfo 
## -0,1 +0,0 ## 
Reverse-merged /trunk/file1.txt:r3-8 
Index: . 
=================================================================== 
--- . (revision 10) 
+++ . (working copy) 

Property changes on: . 
___________________________________________________________________ 
Modified: svn:mergeinfo 
## -0,1 +0,1 ## 
Reverse-merged /trunk:r5-8* 
Merged /trunk:r5-10 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn commit -m "Merge from trunk to my-branch." 
Sending . 
Sending file1.txt 
Transmitting file data .done 
Committing transaction... 
Committed revision 11. 

BQ_END

We change a file in my-project, and then try to merge from my-branch to trunk, but the changes made to not-my-project are reversed, no questions: 

BQ_BEGIN

awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ echo change 1 to my file > my-project/fileA.txt 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn commit -m "Changed my file in my-branch" 
Sending my-project/fileA.txt 
Transmitting file data .done 
Committing transaction... 
Committed revision 12. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up 
Updating '.': 
At revision 12. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn up 
Updating '.': 
At revision 12. 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn merge ^/branches/my-branch 
--- Merging differences between repository URLs into '.': 
U my-project/fileA.txt 
U not-my-project/fileA.txt 
--- Recording mergeinfo for merge between repository URLs into '.': 
U . 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn diff 
Index: my-project/fileA.txt 
=================================================================== 
--- my-project/fileA.txt (revision 12) 
+++ my-project/fileA.txt (working copy) 
@@ -1 +1 @@ 
-my file 
+change 1 to my file 
Index: not-my-project/fileA.txt 
=================================================================== 
--- not-my-project/fileA.txt (revision 12) 
+++ not-my-project/fileA.txt (working copy) 
@@ -1 +1 @@ 
-change 2 to not my file 
+not my file 
Index: . 
=================================================================== 
--- . (revision 12) 
+++ . (working copy) 

Property changes on: . 
___________________________________________________________________ 
Added: svn:mergeinfo 
## -0,0 +0,1 ## 
Merged /branches/my-branch:r3-12 

BQ_END

A further demonstration of the issue. We revert the local changes made by the merge locally. Then we checkout not-my-project in my-branch and attempt another sync merge from trunk to my-branch. Because not-my-project has been marked as having had all changes merged to it, the changes in trunk on that subtree are not brought over: 

BQ_BEGIN

awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ svn revert -R . 
Reverted '.' 
Reverted 'not-my-project/fileA.txt' 
Reverted 'my-project/fileA.txt' 
awilton@metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/ 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up --set-depth=infinity 
Updating '.': 
A not-my-project 
A not-my-project/fileA.txt 
Updated to revision 12. 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn merge ^/trunk 
--- Recording mergeinfo for merge of r11 through r12 into '.': 
U . 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn diff 
Index: . 
=================================================================== 
--- . (revision 12) 
+++ . (working copy) 

Property changes on: . 
___________________________________________________________________ 
Modified: svn:mergeinfo 
## -0,0 +0,1 ## 
Merged /trunk:r11-12 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cat not-my-project/fileA.txt 
not my file 
awilton@metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cat ../../trunk/not-my-project/fileA.txt 
change 2 to not my file 

BQ_END

And thats the bug. To be even more explicit, it seems that the only time it reverse merges those previously non-inheritable revisions, is if the most recent changeset being brought over doesn't include changes to not-my-project. It's almost like SVN merge uses whether the revision range of the actual changeset is inheritable to determine whether the revision ranges of all eligible revisions are inheritabile, which in this use case is incorrect. The newest revisions should be inheritable, but the old ones need to stay non-inheritable so that SVN doesn't accidentally think that branches/my-branch/not-my-project has the newest changes from trunk/not-my-project. 

I am using Ubuntu 16.04 with SVN 1.13. I have also confirmed this bug on SVN 1.9 (thats what the rest of my company uses). Here is my svn version info: 

BQ_BEGIN

$ svn --version 
svn, version 1.13.0 (r1867053) 
compiled Apr 23 2020, 15:50:58 on x86_64-unknown-linux-gnu 

Copyright (C) 2019 The Apache Software Foundation. 
This software consists of contributions made by many people; 
see the NOTICE file for more information. 
Subversion is open source software, see http://subversion.apache.org/ 

The following repository access (RA) modules are available: 

* ra_svn : Module for accessing a repository using the svn network protocol. 
- handles 'svn' scheme 
* ra_local : Module for accessing a repository on local disk. 
- handles 'file' scheme 

The following authentication credential caches are available: 

* GPG-Agent 

BQ_END

I am not subscirbed to the @user list and neither are my colleagues who are CC'ed in this email. Could we all be CC'ed on any followup emails? 

Thank you, 
Alex Wilton 

CONFIDENTIALITY NOTICE: This communication may contain private, confidential and privileged material for the sole use of the intended recipient. If you are not the intended recipient, please delete this e-mail and any attachments permanently.


Re: non-inheritable revisions in mergeinfo being later incorrectly marked as inheritable

Posted by Nathan Hartman <ha...@gmail.com>.
On Fri, Apr 24, 2020 at 10:36 AM Alex Wilton
<aw...@roboticresearch.com> wrote:
>
> Hello,
>
> This is my first time posting to this mailing list so apologies for any newbie mistakes. I couldn't find a bug report discussing this particular issue and while I'm fairly certain this isn't intended behavior, I wanted to post to users@ just in case there was some strange reasoning for why this is supposed to happen.
>
> I'll give the gist of what the issue is and then I'll post the sequence of commands I used to reproduce the entire issue, with some intermediate diffs to show whats going on.
>
> Essentially, I have a full checkout of trunk containing the following directory structure:
>
> file1.txt
> my-project/fileA.txt
> not-my-project/fileA.txt
>
> Then we have a copy of trunk, called "my-branch" which has everything checked out except for not-my-project.
> We make a sequence of commits in trunks, each of which is followed by a sync merge from trunk to my-branch. The first commit changes "file1.txt" and the mergeinfo reflects a full merge (good). The next two commits involve changes to not-my-project, and the mergeinfo of my-branch reflects these revisions as non-inheritable (so, partially merged. also good). Finally, we make a commit to "file1.txt" again, but when merging that over, the mergeinfo in my-branch suddenly reverse-merges the non-inheritable ranges and merges them as inheritable, despite the fact that these revisions have not had their changes brought in (we still don't have not-my-project checked out). The consequence is that SVN now thinks that my-branch has had not-my-project updated and a subsequent reintegrate merge from my-branch to trunk reverses all of the changes made in trunk to match what it looked like on the creation of my-branch. It does this with no complaints. Here is all of the steps I did to recreate that:
>

Thank you for your analysis and detailed reproduction steps.

Hopefully someone with more knowledge than me about the inner workings
of mergeinfo will be able to chime in here, but my immediate thoughts
in the meantime...

I wonder if the problem still manifests if, in your first steps for
setting up trunk and branch, you were to change this:

$ cd branches/
$ svn up my-branch --set-depth=files

to this:

$ cd branches/
$ svn up my-branch --set-depth=immediates

My thinking is that because the 'not-my-project' directory is not
present at all in the branch working copy, perhaps svn isn't updating
mergeinfo for it when it should, in one of the steps along the way,
eventually culminating in the reversal of 'not-my-project' files on
trunk.

At the moment I can't experiment with this further, but I'll try to do
some testing and digging through the mailing list archives over the
weekend.

Thanks,
Nathan