Reputation: 387
Assume we have these streams in a depot
main
/ \
A B
All these streams have following files:
01.txt: 01
02.txt: 02
From A, I submit these two changelists.
#1: p4 move 01.txt legacy_01.txt
#2: p4 move 02.txt 01.txt
Then I copy-up these changelists to main. At this point, main's files are as expected.
legacy_01.txt: 01
01.txt: 02
However, the problem arises when I merge-down to B.
After some auto-resolve (It doesn't matter you've p4 resolve
then blindly accepted all, or even used p4v's safe no-merge autoresolve), files become:
legacy_01.txt: 02
(other files are deleted)
It is more problematic becuase it happens even if you used p4v's Safe automatic resolve. Sure, I could've carefully adjusted resolve order to prevent this situation, but why this is the default?
Upvotes: 0
Views: 497
Reputation: 71517
tl;dr: renaming files into each others' places and then squashing the resulting changelists is problematic.
The problem arises when you copy up to main.
C:\Perforce\test\seongchan-test>p4 copy A/... main/...
//stream/main/seongchan-test/main/02.txt#1 - delete from //stream/main/seongchan-test/A/02.txt#1,#2
//stream/main/seongchan-test/main/01.txt#1 - sync/integrate from //stream/main/seongchan-test/A/01.txt#1,#3
//stream/main/seongchan-test/main/legacy_01.txt#1 - branch/sync from //stream/main/seongchan-test/A/legacy_01.txt#1
C:\Perforce\test\seongchan-test>p4 opened
//stream/main/seongchan-test/main/01.txt#1 - integrate default change (text)
//stream/main/seongchan-test/main/02.txt#1 - delete default change (text)
//stream/main/seongchan-test/main/legacy_01.txt#1 - branch default change (text)
C:\Perforce\test\seongchan-test>p4 resolved
c:\Perforce\test\seongchan-test\main\01.txt - copy from //stream/main/seongchan-test/A/01.txt#1,#3
c:\Perforce\test\seongchan-test\main\02.txt - delete from //stream/main/seongchan-test/A/02.txt#1,#2
c:\Perforce\test\seongchan-test\main\legacy_01.txt - branch from //stream/main/seongchan-test/A/legacy_01.txt#1
Note that none of the files are open for "move" -- the sequence of 01->legacy_01
and 02->01
operations (which would be represented by move/add
and move/delete
actions happening in a specific order) have been lost due to the "squashing" of these two changelists!
This ends up confusing the subsequent merge/resolve; it's trying to do all of the operations at once, and its best effort is to combine 02->01
and 01->legacy_01
into 02->legacy_01
, which is not actually what you want given the order these operations originally happened in.
There is an undoc setting that will warn you about this during a copy
operation:
C:\Perforce\test\seongchan-test>p4 configure set dm.copy.movewarn=1
For server 'any', configuration variable 'dm.copy.movewarn' set to '1'
C:\Perforce\test\seongchan-test>p4 copy A/... main/...
//stream/main/seongchan-test/main/02.txt#1 - delete from //stream/main/seongchan-test/A/02.txt#1,#2
//stream/main/seongchan-test/main/01.txt#1 - sync/integrate from //stream/main/seongchan-test/A/01.txt#1,#3
... can't open as move/add because a file already exists in this location.
//stream/main/seongchan-test/main/legacy_01.txt#1 - branch/sync from //stream/main/seongchan-test/A/legacy_01.txt#1
... can't open as move/add because //stream/main/seongchan-test/main/01.txt is not being opened for delete.
Some files couldn't be opened for move. Try copying from @268 instead?
If I take the advice of the error message I end up doing the copy in stages, each of which copies over one of the move
operations:
C:\Perforce\test\seongchan-test>p4 revert ...
//stream/main/seongchan-test/main/legacy_01.txt#none - was branch, deleted
//stream/main/seongchan-test/main/01.txt#1 - was integrate, reverted
//stream/main/seongchan-test/main/02.txt#1 - was delete, reverted
C:\Perforce\test\seongchan-test>p4 copy A/...@268 main/...
//stream/main/seongchan-test/main/01.txt#1 - move/delete from //stream/main/seongchan-test/A/01.txt#1,#2
//stream/main/seongchan-test/main/legacy_01.txt#1 - move/add/sync from //stream/main/seongchan-test/A/legacy_01.txt#1
C:\Perforce\test\seongchan-test>p4 submit -d "copy from A@268"
Submitting change 271.
Locking 2 files ...
move/delete //stream/main/seongchan-test/main/01.txt#2
move/add //stream/main/seongchan-test/main/legacy_01.txt#1
Change 271 submitted.
C:\Perforce\test\seongchan-test>p4 copy A/... main/...
//stream/main/seongchan-test/main/02.txt#1 - move/delete from //stream/main/seongchan-test/A/02.txt#1,#2
//stream/main/seongchan-test/main/01.txt#2 - move/add/sync from //stream/main/seongchan-test/A/01.txt#3
C:\Perforce\test\seongchan-test>p4 submit -d "finish copy from A"
Submitting change 272.
Locking 2 files ...
move/add //stream/main/seongchan-test/main/01.txt#3
move/delete //stream/main/seongchan-test/main/02.txt#2
Change 272 submitted.
Now when we merge down to B, it sees both of the moves and tries to resolve both of them -- rather than trying to "squash" them the way that copy
does, resolve
will warn you that you can't do both of them at once:
c:\Perforce\test\seongchan-test\B\02.txt - resolving move to //stream/main/seongchan-test/B/01.txt
//Samwise-dvcs-1509687817/seongchan-test/B/01.txt - can't move to an existing file
The fix at this point is similar to before; you have to back up and do the changelists one at a time (submitting in between) for them to merge successfully.
C:\Perforce\test\seongchan-test>p4 merge main/...@271 B/...
//stream/main/seongchan-test/B/01.txt#1 - integrate from //stream/main/seongchan-test/main/legacy_01.txt#1 (remapped from //stream/main/seongchan-test/B/legacy_01.txt)
... must resolve content from //stream/main/seongchan-test/main/legacy_01.txt#1
... must resolve move to //stream/main/seongchan-test/B/legacy_01.txt
C:\Perforce\test\seongchan-test>p4 resolve -as
c:\Perforce\test\seongchan-test\B\01.txt - merging //stream/main/seongchan-test/main/legacy_01.txt#1
Diff chunks: 0 yours + 0 theirs + 0 both + 0 conflicting
//Samwise-dvcs-1509687817/seongchan-test/B/01.txt - copy from //stream/main/seongchan-test/main/legacy_01.txt
c:\Perforce\test\seongchan-test\B\01.txt - resolving move to //stream/main/seongchan-test/B/legacy_01.txt
//stream/main/seongchan-test/B/legacy_01.txt - moved from //stream/main/seongchan-test/B/01.txt
C:\Perforce\test\seongchan-test>p4 submit -d "merge from main@271"
Submitting change 273.
Locking 2 files ...
move/delete //stream/main/seongchan-test/B/01.txt#2
move/add //stream/main/seongchan-test/B/legacy_01.txt#1
Change 273 submitted.
C:\Perforce\test\seongchan-test>p4 merge main/... B/...
//stream/main/seongchan-test/B/02.txt#1 - integrate from //stream/main/seongchan-test/main/01.txt#3 (remapped from //stream/main/seongchan-test/B/01.txt)
... must resolve content from //stream/main/seongchan-test/main/01.txt#3
... must resolve move to //stream/main/seongchan-test/B/01.txt
C:\Perforce\test\seongchan-test>p4 resolve -as
c:\Perforce\test\seongchan-test\B\02.txt - merging //stream/main/seongchan-test/main/01.txt#3
Diff chunks: 0 yours + 0 theirs + 0 both + 0 conflicting
//Samwise-dvcs-1509687817/seongchan-test/B/02.txt - copy from //stream/main/seongchan-test/main/01.txt
c:\Perforce\test\seongchan-test\B\02.txt - resolving move to //stream/main/seongchan-test/B/01.txt
//stream/main/seongchan-test/B/01.txt - moved from //stream/main/seongchan-test/B/02.txt
C:\Perforce\test\seongchan-test>p4 submit -d "finish merge from main"
Submitting change 274.
Locking 2 files ...
move/add //stream/main/seongchan-test/B/01.txt#3
move/delete //stream/main/seongchan-test/B/02.txt#2
Change 274 submitted.
As with the copy, we can see that now each merge operation "replays" one of the source's move operations; they have to happen one at a time since the second merge needs to move a file into the path that was deleted by the first.
Upvotes: 1