This question was created in reference to: [Any way to move uassets without destroying Perforce file [Content removed]
Hey Epic,
I apologize in advance for creating another thread on this topic. I understand that the original question was permanently closed, but we found a workaround and we wanted your opinion on whether it would backfire.
I read Cody’s answer and the summary of the last time you guys investigated - which no doubt is a fair number of years ago by now! But I find it interesting that the conversation only covers “p4 move”. I was investigating “p4 integrate” instead, and I didn’t understand why the “p4 integrate” command wouldn’t work, since it is already called via SourceControlHelpers::BranchPackage in FAssetRenameManager::PerformAssetRename. So it got me to run it as a test in perforce - go through the same process that Unreal goes through:
- Check out original file
- Save the new renamed file
- Mark it for add
- Branch it
Notable is that the branch command passes, but like many have noticed - the branch action P4 history is not there.
So it got me thinking about what ordering P4 would require to ensure the history was kept, and I found the following minor reorder/change worked fine:
- Check out original file
- Branch the original file to the new location
- Check out the new file (since the new file shouldn’t be a bit copy, it needs additional changes by the Editor)
- Save the new file on top of the earlier copied writable file
- Resume as before (although the later call to BranchPackage could interfere)
To summarize, our (semi-pseudo) changes are:
//FAssetRenameManager::PerformAssetRename
for each AssetToRename
BranchPackage(Asset);
SourceControlHelpers::CheckOutFiles(BranchedAssets);
FEditorFileUtils::PromptForCheckoutAndSave();
//PerforceSourceControlState.cpp
//FPerforceSourceControlState::CanCheckout
//Technically EPerforceState::Branched is also read-only, and you are allowed to check out a Branched file.
const bool bIsInP4NotCheckedOut = State == EPerforceState::ReadOnly || State == EPerforceState::Branched;
We’ve had a few test scenarios with this and it seems to be working fairly well. We do have the following known issues:
- History from the Editor does not work until the renamed file is submitted. Annoying, but it really is a P4 limitation (filelog won’t work on files that have not yet been submitted).
- Unreal Engine does a lot of P4 batching for various scenarios. I’m using batching for CheckOutFiles (instead of CheckOutFile after each call to branch), but would be nice to have batching for BranchPackage too.
- We made some minor changes to the RenamingSlowTask. The branching takes long so I steal some time from elsewhere to be able to update the task after each branch.
- With this change, it exposed an issue in SBlueprintRevisionMenu::OnSourceControlQueryComplete. The iteration here is purely on history, without taking branches into account like “Right click on asset -> Revision Control -> History” does. The aesthetic fix is straightforward (check if there is a branch, and if so also iterate over the branch and its history - and keep doing so until no more branches/revisions). Unfortunately from what I saw in OnDiffRevisionPicked, it uses the file name from the blueprint object (instead of by parameter from RevisionInfo), so changes aren’t as non-trivial anymore.
- Renaming onto a file that was previously deleted in P4 ends up in a strange state where the renamed/‘revived’ file ends up as a delete of a deleted file. I would fix this, I just haven’t looked into it yet.
I was running low on characters, but I left all my changes to the two functions mentioned so others can try them if maintaining history is worth the known issues. I decided against a pull request since the question was permanently closed and I wasn’t sure whether you wanted to approach the problem with integrate instead. Thoughts?