Categories
Tutorials

Working with Unreal Engine Source in Git and Perforce

The creation of a maintainable Perforce (P4) depot that houses any number of game projects and includes the Unreal Engine source code from GitHub.

Over time, I’ve developed a simple method for handling a Git-based Unreal Engine source. In this method, the source is mirrored into a Perforce workspace. Epic Pro customers have access to Epic’s perforce-controlled version of Unreal Engine. Still, I’ve found that I prefer working with the source in this way. This has been tested in both studio and personal environments and has proven rather robust in solving the upgrade problem. It’s not for everyone, but here’s a general rundown of the setup and upgrading.

As of March 2026, I’ve had this post in a draft form for well over a year and a half. As I come back to just pushing it out, noticeably not much has changed with the setup.

Assumptions

  • You have already created a depot in Perforce. You have also set up streams (optional) and have decided on your depot layout.
  • You have created a local workspace for your Perforce depot/stream.
  • Your familiar with Epic’s documentation around using Perforce as a source control.
  • You have Beyond Compare. It’s not entirely necessary. Nevertheless, you will have to substitute in functional equivalents in the mirroring process.
  • I’m not going to deal with how to layout your project or workspace. This is outside of the immediate needs of handling the Unreal Engine source code task.
  • I have tested this format with the Engine source in a unique folder in the workspace. I don’t suggest it. It makes the number of changes exponential as you start using different parts of the engine, like Horde.
  • DETHOL is my Perforce server’s depot.

Getting Started

Git Fork

The first step is to fork a branch from the Unreal Engine source code. I typically am using the release in a studio environment, but will use ue5-main for personal projects.

It is easiest to use a fresh clone. This approach ensures we get the minimal amount of files that need to be mirrored into the Perforce depot.

Your cloned repository should be placed somewhere outside of where you plan on building your P4 workspace. It will be handy to keep around later, but not necessary.

Clone
git clone https://github.com/dotBunny/UnrealEngine.git D:\Repositories\dotBunny\UnrealEngine

Typemap Definition

Now is a good time to make sure your Perforce depot’s typemap is set up appropriately. Check this before we start adding content. Here is a starter definition specifically for Unreal Engine.

Typemap
binary+w //DETHOL/....exe
binary+w //DETHOL/....dll
binary+w //DETHOL/....exp
binary+w //DETHOL/....lib
binary+w //DETHOL/....app
binary+w //DETHOL/....dylib
binary+w //DETHOL/....stub
binary+w //DETHOL/....ipa
binary //DETHOL/....bmp
binary //DETHOL/....rc
text //DETHOL/....ini
text //DETHOL/....config
text //DETHOL/....cpp
text //DETHOL/....h
text //DETHOL/....c
text //DETHOL/....cc
text //DETHOL/....cs
text //DETHOL/....m
text //DETHOL/....mm
text //DETHOL/....py
text //DETHOL/....html
text //DETHOL/....dart
text //DETHOL/....LICENSE
text //DETHOL/....md
text //DETHOL/....txt
text //DETHOL/....json
text //DETHOL/....pem
text //DETHOL/....transform
text //DETHOL/....xml
text+x //DETHOL/....sh
text+x //DETHOL/....command
text+w //DETHOL/....exe.config
text+w //DETHOL/....dll.config
binary+l //DETHOL/....uasset
binary+l //DETHOL/....umap
binary+l //DETHOL/....upk
binary+l //DETHOL/....udk
binary+l //DETHOL/....ubulk

You’ll need to be a Perforce admin to issue the p4 typemap command locally to edit the applicable typemap.

Git Dependencies

It’s time to get those things that aren’t brought down when you clone the Unreal Engine repository, mostly third-party libraries. This can be done by running:

Dependencies
Engine/Binaries/DotNET/GitDependencies/win-x64/GitDependencies.exe

Setting Up The Mirror

This process is built around utilizing Beyond Compare to mirror the repository into your workspace, with a set of rules. Setting up this workflow now is important as it will be used for upgrades as well.

New Session

If you haven’t already setup a session for mirroring the source code, lets remedy that right now.

Create a new Folder Sync session.
Switch the operation mode to Mirror to Right.
On the left-hand side select your cloned repository location, on the right-hand side select your workspace root.

Filters

The next step is to add in the filters. These filters are used to ignore specific files and folders. We do not want to remove these in the workspace when we do our syncs.

Filters
-.\Default.uprojectdirs;-.\.vsconfig;-.\p4config.txt;-.\UE5.sln;-.\p4.log;-.\p4ignore.txt;-p4passwd.txt;-.\.git\;-.\.ugs\;-.\.vscode\;-.\.vs\;-.\Staging\;-.\Projects\;-.\dotBunny\;-.\K9\
ItemDescription
.\Default.uprojectdirsWe want to keep the project definitions in the workspace.
.\.vsconfigNo need to replace this IDE config file.
.\p4config.txtOften used to store local Perforce workspace credentials/definitions.
.\UE5.slnThis gets generated automatically later, ignored for good measure.
.\p4.logThis is the log file our perforce commands are going to pipe too, so leave it alone.
.\p4ignore.txtThis is the P4IGNORE that I typically use.
.\p4passwd.txtThis is the P4PASSWD file I often use.
.\.git\We don’t want to sync the Git related files.
.\.ugs\No need to wipe out any existing UnrealGameSync settings.
.\.vscode\Leave the VSCode settings alone.
.\.vs\Leave the Visual Studio settings alone.
.\Staging\This is a folder for staging a lot of our build related things. I usually leave it untouched.
.\Projects\This is where your Unreal Projects are going to be stored. We don’t want to sync them against the Git repository.
.\dotBunny\This is just a company folder which lives in my workspace where often shared data is located.
.\K9\This is where the K9 utilities get cloned automatically.

Rules

There’s a little button sitting between Operations and Filters that looks like a referee. You can click it to open the session settings. But, there are other ways to get there.

Comparison Settings
Handling Settings

Copy Time

Once you have completed all this setup, you can now hit the Auto Sync button. Let Beyond Compare do its thing.

To build muscle memory, I let Beyond Compare copy the files into the empty workspace using the sync method. This is the same mechanism that will be used to upgrade the workspace in the future.

The repository must be synced over to the workspace first. After this, we need to reconcile the entire workspace. This process will add these files to Perforce. I strongly suggest creating a changelist ahead of time that you can target with the next command:

Workspace
p4 reconcile -eadfm -c <CHANGELIST> d:\Workspaces\dotBunny\UE5\... > p4.log

You can watch the p4.log file to see the status of the reconcile. Once it is done, you should have a changelist. You can commit this changelist with your first engine add.

Now its up to you to build/make your project!


Divergences

To manage future upgrades, it’s important to markup your changes to the source clearly. This allows them to be easily found and reasoned about.

I’ve long since debated if the changes should be pushed back to the private-fork of the Unreal Engine source. So far, I have kept modifications inside of Perforce-only. The benefits will become obvious when having to merge an upgrade.

I use a format like this when making surgical changes:

WinPlatform.Automation.cs
C#
public override string GetPlatformPakCommandLine(ProjectParams Params, DeploymentContext SC)
{
// #DIVERGENCE-START matthew.davey #STEAM
// Steamworks recommended alignment for optimal patching
// https://partner.steamgames.com/doc/sdk/uploading
//string PakParams = " -patchpaddingalign=2048";
string PakParams = " -patchpaddingalign=1048576 -blocksize=1048576";
// #DIVERGENCE-END matthew.davey #STEAM

For rather large developments, I prefer to make them a plugin. This allows them to live in the projects themselves while strictly keeping the source changes minimal. There is not too much you can’t do as a plugin with enough creativity.

Create a shelved changelist of all of your divergences.

Upgrading Unreal Engine

This is the part where I hear the most complaints about working with the Unreal Engine; the dreaded upgrade. I have done complicated upgrades in both Unreal Engine and Unity. They both have their challenges, but much of the complication comes down to your preparation. It also depends on your ability to understand the code and reason about changes.

Let’s start with some preparation.

Sync Remote Fork

Assuming you have a private-fork of Epic’s UnrealEngine repository; first you must sync your local fork to the upstream. The fancy “Sync fork” button will help you navigate those waters on GitHub.

You may need to do this operation locally to resolve any conflicts. This is one of the first reasons I try to keep my changes in Perforce.

Clean Local Repository

If you didn’t keep the local clone from the first creation of the workspace, don’t worry. You can just checkout a new clone.

As we are going to use the mirror-sync inside Beyond Compare. We want to make sure the left-hand side source is as clean as possible. This ensures we don’t have any extra files hanging around.

First, we want to clean all of the existing downloaded third-party assets. We also need to remove anything that was generated earlier.

From the local UnrealEngine repository, D:\Repositories\dotBunny\UnrealEngine:

Cleanup
git clean -dfx

Update Local Repository

At this point your local repository of the Unreal Engine source code should be pristine. There should be no extra files outside of what is found in the repository. It is ready for an upgrade. That is unless you just checked out a fresh clone.

Update
git pull --rebase=false origin --prune

Refresh Git Dependencies

As with the first setup, we aim to grab the latest dependencies. Use the console application found in the repository to do this.

Dependencies
Engine/Binaries/DotNET/GitDependencies/win-x64/GitDependencies.exe

Mirror Changes

Now, hopefully you get to benefit from the fruits of your earlier labor. If everything was set up correctly, open Beyond Compare. Then, select the existing session where you set up the mirroring.

You just need to wait for the application to finish finding all of the differences. In the header the “Stop” button will stop flashing. This process can take a while.

When you are ready, press the “Auto Sync” button and watch everything get moved over to the right-hand side. You will encounter a few dialogs. They will ask if you wish to overwrite read-only files because they are read-only in your Perforce workspace. I respond “Yes-to-All” to these.

This mirror will wipe out any of your changes to the Unreal Engine source. This is why I keep a shelf of the divergences. I will reapply them after this step.

Build Changelists

Just like during the initial setup, you are going to want to pre-make a changelist to target reconciling towards. You can make multiple for each major folder, or use one monolithic changelist. It’s entirely up to you!

I choose to split the reconciling across different commands. I base this split on top-level folders. You really can do this however you want.

Reconcile
p4 reconcile -eadfm -c <CL> d:\Workspaces\dotBunny\UE5\Engine\... > p4.log
p4 reconcile -eadfm -c <CL> d:\Workspaces\dotBunny\UE5\FeaturePacks\... > p4.log
p4 reconcile -eadfm -c <CL> d:\Workspaces\dotBunny\UE5\Samples\... > p4.log
p4 reconcile -eadfm -c <CL> d:\Workspaces\dotBunny\UE5\Templates\... > p4.log
p4 reconcile -eadfm -c <CL> d:\Workspaces\dotBunny\UE5\.uedependencies > p4.log

Restoring Divergences

This is where that shelf of divergences is important. The earlier mirroring process overwrites everything. If you don’t have the divergence shelf, you must pay significantly more attention during the mirror. You need to find files that have been marked up with #DIVERGENCE instead of this post-processing.

Assuming you have the shelf, you now have a list of files. You can diff the workspace version with what is shelved. This lets you reason about and apply changes. I can’t specifically guide you on how to do this efficiently. I just treat it like a normal merge diff.

Once you’ve finished resolving the divergences and made your local tests. It is incredibly important to then update the divergences shelf

Testing Locally

Every project will have its own validation requirements and / or process. This is the time to go and check to ensure everything still works. Alternatively, verify that it is in a good-enough state to commit the upgrade without blocking others.

Make builds and test different types of packaged builds on your given platforms. Do this before going any further.

Serialize Assets

You probably won’t need to re-serialize all your assets right away. It’s the best practice to do so eventually. I make sure things work locally. Then, I coordinate with my team. We must decide when to take that time hit, which occurs when everyone has to download all the content changes.

Submitting To Perforce

Ensure you are content and prepared to accept the risk involved. Then, make the commit via your shell. P4V is slower.

Submit
p4 submit -c <CL> --parallel=threads=5

Fixing Unicode Types

If your Perforce server has Unicode enabled you are going to have a world of fun. Once it has been turned on, it cannot be turned off. If you are making that decision, please ensure you have a reason for it.

K9.Unreal.PerforceTypes is a tool that is part of K9. It will carry out a deep check of all files in the workspace. It automatically builds out the changelist with the updated types. Use it instead of what’s next!

There is a command which will look at the workspace and find all of the generic Unicode type files and output their path to a file:

Submit
p4 fstat -F "headType=unicode" -T clientFile //DETHOL/... > unicode.txt

You then can take the generated unicode.txt file, open it and replaces the insides to that each line looks something like:

Line
p4 edit -t text -c <CL> "D:\Workspaces\dotBunny\UE5\Engine\Source\ThirdParty\ShaderConductor\ShaderConductor\External\SPIRV-Tools\utils\vscode\src\lsp\protocol\tsprotocol.go"

Each line has been prefixed with the edit command, and the path has been surrounded in quotes. Now you can copy the entire text file. Then, paste it into your shell. This will execute all of the lines as individual commands.

Leave a comment