1515#include " SourceControlHelpers.h"
1616#include " Logging/MessageLog.h"
1717#include " Misc/MessageDialog.h"
18+ #include " HAL/FileManager.h"
1819#include " HAL/PlatformProcess.h"
1920#include " GenericPlatform/GenericPlatformFile.h"
2021#if ENGINE_MAJOR_VERSION >= 5
@@ -470,41 +471,41 @@ bool FGitDeleteWorker::UpdateStates() const
470471}
471472
472473
473- // Get lists of Missing files (ie "deleted"), Modified files, and "other than Added" Existing files
474- void GetMissingVsExistingFiles (const TArray<FString>& InFiles, TArray<FString>& OutMissingFiles, TArray<FString>& OutAllExistingFiles, TArray<FString>& OutOtherThanAddedExistingFiles)
474+ void GroupFileCommandsForRevert (const TArray<FString>& InFiles, TArray<FString>& FilesToRemove, TArray<FString>& FilesToCheckout, TArray<FString>& FilesToReset, TArray<FString>& FilesToDelete)
475475{
476476 FGitSourceControlModule& GitSourceControl = FGitSourceControlModule::Get ();
477477 FGitSourceControlProvider& Provider = GitSourceControl.GetProvider ();
478478
479- const TArray<FString> Files = (InFiles.Num () > 0 ) ? (InFiles) : (Provider.GetFilesInCache ());
480-
481479 TArray<TSharedRef<ISourceControlState, ESPMode::ThreadSafe>> LocalStates;
482- Provider.GetState (Files , LocalStates, EStateCacheUsage::Use);
480+ Provider.GetState (InFiles , LocalStates, EStateCacheUsage::Use);
483481 for (const auto & State : LocalStates)
484482 {
485- if (FPaths::FileExists ( State->GetFilename () ))
483+ if (State->IsAdded ( ))
486484 {
487- if (State->IsAdded ())
488- {
489- OutAllExistingFiles.Add (State->GetFilename ());
490- }
491- else if (State->IsModified ())
485+ if (FPaths::FileExists (State->GetFilename ()))
492486 {
493- OutOtherThanAddedExistingFiles.Add (State->GetFilename ());
494- OutAllExistingFiles.Add (State->GetFilename ());
487+ // Git rm won't delete the file because the engine still has it in use, and reset won't work on a file which doesn't exist on disk
488+ // so we have to delete it ourselves, and then remove it from the index.
489+ if (USourceControlPreferences::ShouldDeleteNewFilesOnRevert ())
490+ {
491+ FilesToDelete.Add (State->GetFilename ());
492+ FilesToRemove.Add (State->GetFilename ());
493+ }
494+ else
495+ {
496+ FilesToReset.Add (State->GetFilename ());
497+ }
495498 }
496- else if (State-> CanRevert ()) // for locked but unmodified files
499+ else
497500 {
498- OutOtherThanAddedExistingFiles.Add (State->GetFilename ());
501+ // When you delete a file through content browser, UE will send a revert command to allow us to clean up the stage state.
502+ FilesToRemove.Add (State->GetFilename ());
499503 }
500504 }
501- else
505+ // Checkout to head will reset the file back to what it is in your current commit, and reset the index.
506+ else if (State->CanRevert ())
502507 {
503- // If already queued for deletion, don't try to delete again
504- if (State->IsSourceControlled () && !State->IsDeleted ())
505- {
506- OutMissingFiles.Add (State->GetFilename ());
507- }
508+ FilesToCheckout.Add (State->GetFilename ());
508509 }
509510 }
510511}
@@ -519,63 +520,62 @@ bool FGitRevertWorker::Execute(FGitSourceControlCommand& InCommand)
519520 InCommand.bCommandSuccessful = true ;
520521
521522 // Filter files by status
522- TArray<FString> MissingFiles;
523- TArray<FString> AllExistingFiles;
524- TArray<FString> OtherThanAddedExistingFiles;
525- GetMissingVsExistingFiles (InCommand.Files , MissingFiles, AllExistingFiles, OtherThanAddedExistingFiles);
526-
527- const bool bRevertAll = InCommand.Files .Num () < 1 ;
523+ const bool bRevertAll = InCommand.Files .Num () == 0 ;
528524 if (bRevertAll)
529525 {
530- TArray<FString> Parms ;
531- Parms .Add (TEXT (" --hard" ));
532- InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" reset" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , Parms , FGitSourceControlModule::GetEmptyStringArray (), InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
526+ TArray<FString> Params ;
527+ Params .Add (TEXT (" --hard" ));
528+ InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" reset" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , Params , FGitSourceControlModule::GetEmptyStringArray (), InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
533529
534- Parms .Reset (2 );
535- Parms .Add (TEXT (" -f" )); // force
536- Parms .Add (TEXT (" -d" )); // remove directories
537- InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" clean" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , Parms , FGitSourceControlModule::GetEmptyStringArray (), InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
530+ Params .Reset (2 );
531+ Params .Add (TEXT (" -f" )); // force
532+ Params .Add (TEXT (" -d" )); // remove directories
533+ InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" clean" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , Params , FGitSourceControlModule::GetEmptyStringArray (), InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
538534 }
539535 else
540536 {
541- if (MissingFiles.Num () > 0 )
537+ TArray<FString> FilesToRemove;
538+ TArray<FString> FilesToCheckout;
539+ TArray<FString> FilesToReset;
540+ TArray<FString> FilesToDelete;
541+ GroupFileCommandsForRevert (InCommand.Files , FilesToRemove, FilesToCheckout, FilesToReset, FilesToDelete);
542+
543+ // Verify we haven't missed performing an operation on any file passed on for revert
544+ ensure (FilesToRemove.Num () + FilesToCheckout.Num () + FilesToReset.Num () == InCommand.Files .Num ());
545+
546+ for (const FString& FileName : FilesToDelete)
542547 {
543- // "Added" files that have been deleted needs to be removed from revision control
544- InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" rm" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , FGitSourceControlModule::GetEmptyStringArray (), MissingFiles, InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
548+ bool RequireExists = true ;
549+ bool EvenReadOnly = true ;
550+ IFileManager::Get ().Delete (*FileName, RequireExists, EvenReadOnly);
545551 }
546- if (AllExistingFiles .Num () > 0 )
552+ if (FilesToReset .Num () > 0 )
547553 {
548- // reset and revert any changes already added to the index
549- InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" reset" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , FGitSourceControlModule::GetEmptyStringArray (), AllExistingFiles, InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
550- InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" checkout" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , FGitSourceControlModule::GetEmptyStringArray (), AllExistingFiles, InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
554+ InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" reset" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , FGitSourceControlModule::GetEmptyStringArray (), FilesToReset, InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
551555 }
552- if (OtherThanAddedExistingFiles .Num () > 0 )
556+ if (FilesToRemove .Num () > 0 )
553557 {
554- // revert any changes in working copy (this would fails if the asset was in "Added" state, since after "reset" it is now "untracked")
555- // may need to try a few times due to file locks from prior operations
556- bool CheckoutSuccess = false ;
557- int32 Attempts = 10 ;
558- while ( Attempts-- > 0 )
559- {
560- CheckoutSuccess = GitSourceControlUtils::RunCommand (TEXT (" checkout" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , FGitSourceControlModule::GetEmptyStringArray (), OtherThanAddedExistingFiles, InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
561- if (CheckoutSuccess)
562- {
563- break ;
564- }
565-
566- FPlatformProcess::Sleep (0 .1f );
567- }
568-
569- InCommand.bCommandSuccessful &= CheckoutSuccess;
558+ // "Added" files that have been deleted needs to be removed from revision control
559+ InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" rm" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , FGitSourceControlModule::GetEmptyStringArray (), FilesToRemove, InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
560+ }
561+ if (FilesToCheckout.Num () > 0 )
562+ {
563+ // HEAD param allows us to re-pull files which have been deleted.
564+ TArray<FString> Params;
565+ Params.Add (TEXT (" HEAD" ));
566+ // Checkout back to the last commit for any modified files.
567+ InCommand.bCommandSuccessful &= GitSourceControlUtils::RunCommand (TEXT (" checkout" ), InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , Params, FilesToCheckout, InCommand.ResultInfo .InfoMessages , InCommand.ResultInfo .ErrorMessages );
570568 }
571569 }
572570
571+ // This is all the files we "asked" to revert, in the case of InCommand.Files everything *should* be changed
572+ // in the case where we didn't pass in any files, we ran a revert on the repository root, so we should refresh everything
573+ const TArray<FString>& RequestedReverts = bRevertAll ? FGitSourceControlModule::Get ().GetProvider ().GetFilesInCache () : InCommand.Files ;
573574 if (InCommand.bUsingGitLfsLocking )
574575 {
575576 // unlock files: execute the LFS command on relative filenames
576- // (unlock only locked files, that is, not Added files)
577577 TArray<FString> LockedFiles;
578- GitSourceControlUtils::GetLockedFiles (OtherThanAddedExistingFiles , LockedFiles);
578+ GitSourceControlUtils::GetLockedFiles (RequestedReverts , LockedFiles);
579579 if (LockedFiles.Num () > 0 )
580580 {
581581 const TArray<FString>& RelativeFiles = GitSourceControlUtils::RelativeFilenames (LockedFiles, InCommand.PathToGitRoot );
@@ -591,19 +591,9 @@ bool FGitRevertWorker::Execute(FGitSourceControlCommand& InCommand)
591591 }
592592 }
593593
594- // If no files were specified (full revert), refresh all relevant files instead of the specified files (which is an empty list in full revert)
595- // This is required so that files that were "Marked for add" have their status updated after a full revert.
596- TArray<FString> FilesToUpdate = InCommand.Files ;
597- if (InCommand.Files .Num () <= 0 )
598- {
599- for (const auto & File : MissingFiles) FilesToUpdate.Add (File);
600- for (const auto & File : AllExistingFiles) FilesToUpdate.Add (File);
601- for (const auto & File : OtherThanAddedExistingFiles) FilesToUpdate.Add (File);
602- }
603-
604594 // now update the status of our files
605595 TMap<FString, FGitSourceControlState> UpdatedStates;
606- bool bSuccess = GitSourceControlUtils::RunUpdateStatus (InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , InCommand.bUsingGitLfsLocking , FilesToUpdate , InCommand.ResultInfo .ErrorMessages , UpdatedStates);
596+ bool bSuccess = GitSourceControlUtils::RunUpdateStatus (InCommand.PathToGitBinary , InCommand.PathToRepositoryRoot , InCommand.bUsingGitLfsLocking , RequestedReverts , InCommand.ResultInfo .ErrorMessages , UpdatedStates);
607597 if (bSuccess)
608598 {
609599 GitSourceControlUtils::CollectNewStates (UpdatedStates, States);
@@ -856,7 +846,6 @@ bool FGitResolveWorker::UpdateStates() const
856846 return GitSourceControlUtils::UpdateCachedStates (States);
857847}
858848
859- #if ENGINE_MAJOR_VERSION == 5
860849FName FGitMoveToChangelistWorker::GetName () const
861850{
862851 return " MoveToChangelist" ;
@@ -906,6 +895,5 @@ bool FGitUpdateStagingWorker::UpdateStates() const
906895{
907896 return true ;
908897}
909- #endif
910898
911- #undef LOCTEXT_NAMESPACE
899+ #undef LOCTEXT_NAMESPACE
0 commit comments