[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

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

From: Alex Wilton <awilton_at_roboticresearch.com>
Date: Fri, 24 Apr 2020 10:34:37 -0400 (EDT)

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_at_metompkin:~/svnplayground/bug_repo_wc$ svn co file:///home/awilton/svnplayground/repo/bug_repo .
Checked out revision 0.
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ svn mkdir trunk
A trunk
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ svn mkdir branches
A branches
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ svn commit -m "Created trunk and branches."
Adding branches
Adding trunk
Committing transaction...
Committed revision 1.
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ svn up
Updating '.':
At revision 1.
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ cd trunk
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo file1 > file1.txt
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn add file1.txt
A file1.txt
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn mkdir my-project
A my-project
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn mkdir not-my-project
A not-my-project
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo my file > my-project/fileA.txt
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo not my file > not-my-project/fileA.txt
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn add my-project/fileA.txt
A my-project/fileA.txt
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn add not-my-project/fileA.txt
A not-my-project/fileA.txt
awilton_at_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_at_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_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ..
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ svn up
Updating '.':
At revision 2.
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ svn cp ^/trunk ^/branches/my-branch -m "Created my-branch from trunk"
Committing transaction...
Committed revision 3.
awilton_at_metompkin:~/svnplayground/bug_repo_wc$ cd branches/
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches$ cd my-branch/
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ ls
file1.txt my-project
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 1 to file1 > file1.txt
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up
Updating '.':
At revision 4.
awilton_at_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_at_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_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn up
Updating '.':
At revision 5.
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 1 to not my file > not-my-project/fileA.txt
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up
Updating '.':
At revision 6.
awilton_at_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_at_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_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 2 to file1 > file1.txt
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 2 to not my file > not-my-project/fileA.txt
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up
Updating '.':
At revision 8.
awilton_at_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_at_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_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn up
Updating '.':
At revision 9.
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ echo change 3 file1 > file1.txt
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up
Updating '.':
At revision 10.
awilton_at_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_at_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_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ echo change 1 to my file > my-project/fileA.txt
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn up
Updating '.':
At revision 12.
awilton_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cd ../../trunk/
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn up
Updating '.':
At revision 12.
awilton_at_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_at_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_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ svn revert -R .
Reverted '.'
Reverted 'not-my-project/fileA.txt'
Reverted 'my-project/fileA.txt'
awilton_at_metompkin:~/svnplayground/bug_repo_wc/trunk$ cd ../branches/my-branch/
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ svn merge ^/trunk
--- Recording mergeinfo for merge of r11 through r12 into '.':
U .
awilton_at_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_at_metompkin:~/svnplayground/bug_repo_wc/branches/my-branch$ cat not-my-project/fileA.txt
not my file
awilton_at_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.
Received on 2020-04-24 16:36:35 CEST

This is an archived mail posted to the Subversion Users mailing list.