Git for Unity: Copy-Paste .gitignore and .gitattributes, LFS and Smart Merge

Git version control for Unity projects

If you’re not using version control for your Unity project yet, this is the single highest-leverage habit you can build as a developer, solo or on a team. It gives you a full undo history beyond Ctrl+Z, safe experimentation on branches, and a real backup that isn’t “hope the hard drive doesn’t die.” Unity projects have a few quirks that trip up newcomers to Git: gigabytes of generated cache, .meta files that must never go missing, and large binary art. The order of the setup steps matters, so follow them top to bottom.

Quick answer

Just need the files? From the Unity project root, run curl -o .gitignore https://raw.githubusercontent.com/github/gitignore/main/Unity.gitignore, or copy our anchored Unity .gitignore and LFS-ready .gitattributes below. Add both files before your first git add ., or Git starts tracking the multi-gigabyte Library folder.

๐Ÿ›  Setting up a project structure too?

Git works best when the project already has a consistent layout. Our naming reference covers folder structure, asset naming, and the .editorconfig that keeps a team’s code consistent โ€” and the full naming style guide explains the reasoning.

Open the Naming Convention Reference →

Step 0: Install Git and Git LFS

  • Windows: install Git for Windows. Git LFS is bundled with it.
  • macOS: brew install git git-lfs (or install the Xcode command line tools for Git, plus Git LFS from git-lfs.com).
  • Linux: install git and git-lfs from your package manager.

Check both from a terminal:

git --version
git lfs version

Prefer a GUI? GitHub Desktop, Fork and Sourcetree all support LFS and work fine with this setup. The files you create below (.gitignore, .gitattributes) are what make it work, not the client.

Step 1: Check Unity’s Version Control Settings

Open the project in Unity and confirm two settings. Recent Unity versions default to both, but projects upgraded from old versions or copied from templates sometimes aren’t.

  1. Edit > Project Settings > Version Control > Mode = Visible Meta Files. (In Unity 2019 and older this lived under Project Settings > Editor.) Every asset has a .meta file storing its GUID, and scenes and prefabs reference scripts and assets by that GUID. Lose or regenerate a .meta and every reference to that asset breaks. That’s the #1 cause of missing script references in team projects.
  2. Edit > Project Settings > Editor > Asset Serialization > Mode = Force Text. Scenes, prefabs and other assets save as readable YAML instead of binary, so Git can diff and merge them.

Then use File > Save Project so the settings are written to disk before your first commit.

Step 2: Create the Repository and Add .gitignore Before Anything Else

This order is the most common setup mistake. If you run git add . before the .gitignore exists, Git starts tracking the Library folder, Unity’s multi-gigabyte local cache, and adding a .gitignore afterwards doesn’t untrack files that are already committed. So create the ignore file first.

From the Unity project root (the folder containing Assets, Packages and ProjectSettings):

git init
# Download GitHub's maintained Unity template (curl ships with Windows 10+ and macOS)
curl -o .gitignore https://raw.githubusercontent.com/github/gitignore/main/Unity.gitignore

Or create .gitignore by hand with this content. It’s a trimmed version of that template with a few OS and IDE extras:

# Unity-generated folders. The leading slash means "only at the project root".
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/
/[Mm]emoryCaptures/
/[Rr]ecordings/

# Never ignore .meta files for assets you keep
!/[Aa]ssets/**/*.meta

# Rider's auto-generated Unity plugin
/[Aa]ssets/Plugins/Editor/JetBrains*

# IDE / OS clutter
.vs/
.idea/
.DS_Store
Thumbs.db

# Generated project and solution files (Unity regenerates these)
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
*.pidb.meta
*.pdb.meta
*.mdb.meta

# Crash reports and build outputs
sysinfo.txt
crashlytics-build.properties
*.apk
*.aab
*.app
*.unitypackage

# Addressables build output
/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
/[Aa]ssets/[Ss]treamingAssets/aa.meta
/[Aa]ssets/[Ss]treamingAssets/aa/*

Why the leading slashes matter: an unanchored pattern like [Bb]uild/ ignores every folder named Build or build anywhere in the project, including Assets/Scripts/Build/. Scripts in there silently never get committed, and your teammates get compile errors you can’t reproduce. The leading / anchors each pattern to the folder the .gitignore lives in.

If your repository root is above the Unity project (e.g. repo/Game/Assets with docs or a server alongside it), put this .gitignore inside the Unity project folder, not the repo root. Otherwise the anchored paths point at the wrong place and nothing gets ignored.

The Library folder is regenerated automatically the next time anyone opens the project. A fresh clone takes a few minutes longer to open the first time; that’s expected, not a sign something is missing.

Illustration of a git branching commit graph for a Unity game project

Step 3: Set Up Git LFS and a Unity .gitattributes File (Still Before the First Commit)

Git stores a full copy of every version of every file in history. That’s fine for code, but a 40 MB texture edited twenty times becomes 800 MB that every clone downloads forever. Git LFS (Large File Storage) keeps the big files on a separate server and commits a tiny pointer in their place.

LFS only applies to files that match a tracked pattern when they’re added, so it has to be configured before the first commit:

git lfs install          # once per machine; also installs this repo's hooks
git lfs track "*.psd"    # each track command appends a line to .gitattributes

Rather than running dozens of track commands, create .gitattributes in the same folder as .gitignore:

# Let Git normalize line endings for text files
* text=auto

# Unity YAML and code: always LF, so Windows and macOS don't fight over line endings
*.unity      text eol=lf
*.prefab     text eol=lf
*.asset      text eol=lf
*.mat        text eol=lf
*.anim       text eol=lf
*.controller text eol=lf
*.meta       text eol=lf
*.cs         text eol=lf diff=csharp

# Images
*.png  filter=lfs diff=lfs merge=lfs -text
*.jpg  filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.psd  filter=lfs diff=lfs merge=lfs -text
*.tga  filter=lfs diff=lfs merge=lfs -text
*.tif  filter=lfs diff=lfs merge=lfs -text
*.exr  filter=lfs diff=lfs merge=lfs -text
*.hdr  filter=lfs diff=lfs merge=lfs -text

# 3D models
*.fbx   filter=lfs diff=lfs merge=lfs -text
*.obj   filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text

# Audio and video
*.wav filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text

# Fonts and native plugins
*.ttf filter=lfs diff=lfs merge=lfs -text
*.otf filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.so  filter=lfs diff=lfs merge=lfs -text

# Baked lighting data is binary even with Force Text
LightingData.asset filter=lfs diff=lfs merge=lfs -text

Notice what’s not in LFS: .unity, .prefab, .mat and most .asset files. With Force Text they’re YAML, and keeping them as normal Git text is what lets you diff and merge them.

Step 4: First Commit, Verified, Then Push

Now stage everything and check before committing:

git add .gitignore .gitattributes
git add .
git status                # must NOT list Library/, Temp/, Logs/ or obj/
git lfs ls-files          # should list your textures, models and audio
git commit -m "Initial commit"

If a folder you expected to be ignored shows up, git check-ignore -v <path> shows which rule (if any) matches it. Fix .gitignore, run git rm -r --cached <folder>, and check again, all before committing.

Then create an empty repository on GitHub, GitLab or Bitbucket (no README or .gitignore, since you already have them) and push:

git branch -M main
git remote add origin https://github.com/your-name/your-game.git
git push -u origin main

Local commits protect you from mistakes, but only a remote protects you from a dead drive or a stolen laptop. A private repository on a free tier is plenty for a solo project. Check your host’s current LFS storage and bandwidth allowance, since art-heavy projects can outgrow free LFS quotas long before they outgrow the repository limit.

Step 5: Configure UnityYAMLMerge (Smart Merge)

When two branches both change a scene, Git’s line-based merge often produces a file Unity can’t load. Unity ships UnityYAMLMerge, a merge tool that understands scene and prefab structure. It’s installed with every Editor version:

  • Windows: C:\Program Files\Unity\Hub\Editor\<version>\Editor\Data\Tools\UnityYAMLMerge.exe
  • macOS: /Applications/Unity/Hub/Editor/<version>/Unity.app/Contents/Tools/UnityYAMLMerge

Add this to your global Git config (git config --global --edit) or the repo’s .git/config, replacing the path with your own. Forward slashes work on Windows:

[merge]
    tool = unityyamlmerge

[mergetool "unityyamlmerge"]
    trustExitCode = false
    cmd = 'C:/Program Files/Unity/Hub/Editor/<version>/Editor/Data/Tools/UnityYAMLMerge.exe' merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"

When a merge reports conflicts in .unity or .prefab files, run git mergetool. UnityYAMLMerge resolves what it can automatically and hands genuinely conflicting values to the fallback tool listed in mergespecfile.txt, which sits next to the executable. Remember to update the path when you upgrade Unity and remove the old Editor.

Step 6: Working With Scenes and Prefabs on a Team

Smart Merge reduces the pain but doesn’t remove it. The workflow habits that matter more:

  • Don’t have two people edit the same scene at the same time. Split big levels into several additively loaded scenes (environment, lighting, gameplay, UI), and move reusable pieces into prefabs. Nested prefabs let people work on parts of a level independently.
  • Keep data in ScriptableObjects instead of scene objects where you can. Small separate asset files merge far more cleanly than one huge scene.
  • Lock binary files you’re editing. Art like .psd files can’t be merged at all. Mark them lockable (git lfs track "*.psd" --lockable), then git lfs lock Assets/Art/Hero.psd before editing and git lfs unlock when you push. GitHub and GitLab both support LFS locks.
  • Always commit an asset and its .meta together, and move or rename assets inside Unity, never in Explorer or Finder.
  • Branch for experiments, commit at the end of every meaningful chunk of work, and write short, specific messages (“Add dash cooldown to PlayerController”, not “stuff”).

๐Ÿ“ฆ About to import paid assets?

Commit first and import on a branch, so a bad package is a one-command revert. If you’re still choosing what to buy, our Asset Store roundup covers the 10 tools we think are worth the money.

See the best Asset Store tools →

Troubleshooting

“this exceeds GitHub’s file size limit of 100.00 MB”

The push is rejected with remote: error: GH001: Large files detected because a big file was committed as a normal Git object. Adding an LFS rule now doesn’t fix commits that already exist. Rewrite them so the file becomes an LFS pointer:

git lfs migrate import --include="*.fbx,*.wav" --everything
git push --force-with-lease origin main

This rewrites history. It’s painless if the commits were never pushed, but if teammates already have them, coordinate first: everyone should push their work, then re-clone after the rewrite.

I already committed the Library folder

Add the .gitignore from Step 2, then stop tracking the generated folders (list only the ones that were actually committed, or Git errors with pathspec did not match any files):

git rm -r --cached Library Temp Logs obj UserSettings
git commit -m "Stop tracking Unity generated folders"

This removes them from future commits but not from history, so the repo stays large. On a young project with no collaborators it’s often cleaner to delete the .git folder and redo Steps 2โ€“4.

“A meta data file (.meta) exists but its asset โ€ฆ can’t be found”

Someone deleted or moved an asset outside Unity, or committed the asset and its .meta separately. Restore the missing half from history, or delete the orphaned .meta if the asset really is gone, then commit asset and meta together from now on.

Missing scripts or pink materials after cloning or pulling

Almost always missing .meta files: either Visible Meta Files was off when they were committed, or a .gitignore rule excluded them. Count the committed meta files with git ls-files "*.meta" | wc -l (Git Bash, macOS or Linux). The number should be roughly equal to your asset count. Our missing script guide shows how to recover the lost GUIDs.

Textures show up as tiny text files after cloning

If a .png opens as a few lines starting with version https://git-lfs.github.com/spec/v1, that machine cloned without Git LFS installed. Run:

git lfs install
git lfs pull

“Encountered N file(s) that should have been pointers, but weren’t”

Files matching an LFS pattern were committed as regular files, usually because .gitattributes was added after them. Convert them in a new commit, without rewriting history:

git lfs migrate import --no-rewrite path/to/file.png path/to/other.fbx

Also check for uppercase extensions. On case-sensitive systems *.png doesn’t match HERO.PNG, so add patterns like *.PNG if your artists export them.

Merge conflict in a scene you just want to overwrite

If one side’s version of a scene should simply win, skip merging:

git checkout --theirs -- Assets/Scenes/Level1.unity   # keep the incoming branch's version
git checkout --ours   -- Assets/Scenes/Level1.unity   # keep your version
git add Assets/Scenes/Level1.unity

During a rebase, “ours” and “theirs” are swapped: “ours” is the branch you’re rebasing onto. Double-check in Unity before committing.

“LF will be replaced by CRLF the next time Git touches it”

A harmless line-ending warning on Windows. The .gitattributes above pins Unity’s YAML and C# files to LF, which stops the churn. For files committed before the attributes existed, run git add --renormalize . once and commit.

FAQ

Which Unity folders should be committed?

Commit Assets, Packages (especially manifest.json and packages-lock.json) and ProjectSettings. Everything else in the project root (Library, Temp, Logs, obj, UserSettings, build folders) is generated or per-user and should be ignored.

Should I use Git or Unity Version Control (Plastic SCM)?

Git is the industry default, free to host, works with every CI service, and is what most tutorials and employers expect. Unity Version Control handles very large binary-heavy projects and artist workflows well and is integrated into the Editor. For solo developers and small, code-heavy teams, Git with LFS is the simpler, more portable choice.

Do I need Git LFS for a small project?

If your project is mostly code with a handful of small sprites, you can start without it. But adding LFS later means rewriting history, and setting it up now takes two minutes. If you’ll have any real art, audio or 3D models, set it up from day one.

Can I use GitHub Desktop instead of the command line?

Yes. GitHub Desktop, Fork and Sourcetree all respect .gitignore, .gitattributes and LFS. You still need to create those two files yourself, and the command line remains handy for the troubleshooting fixes above.

Should Rider or VS Code settings folders be committed?

Usually not. .idea/ and .vs/ hold per-user state. If your team wants shared editor settings, commit an .editorconfig instead, which every major IDE reads.

Where is GitHub’s official Unity .gitignore?

It lives in the github/gitignore repository as Unity.gitignore. Download it straight into your project root with curl -o .gitignore https://raw.githubusercontent.com/github/gitignore/main/Unity.gitignore, or pick the Unity template when you create the repository on GitHub.

What should a Unity .gitattributes file contain?

Three parts: * text=auto for line endings, merge=unityyamlmerge on .unity, .prefab and .asset files so Smart Merge can resolve scene conflicts, and filter=lfs lines for binary assets (textures, audio, models, videos). The copy-paste version is in Step 3.

Quick Setup Checklist

  • Git and Git LFS installed (git lfs version works)
  • Version Control mode = Visible Meta Files; Asset Serialization = Force Text
  • .gitignore with anchored paths in the Unity project root, created before the first git add
  • .gitattributes with LFS rules for images, models, audio and video, plus LF for Unity YAML
  • git status shows no Library/ and git lfs ls-files lists your art before the first commit
  • UnityYAMLMerge configured as your mergetool
  • Remote repository set up and pushed to regularly

Getting this right at the start of a project takes about fifteen minutes and saves you from the most common and most painful Unity-specific Git problems: bloated repos, broken references and unmergeable scenes.

Comments

2 responses to “Git for Unity: Copy-Paste .gitignore and .gitattributes, LFS and Smart Merge”

  1. […] part only does something once each developer configures the merge driver below. The git setup guide has a full .gitignore and […]

  2. […] Library folder, cause slowdowns, lock files and corrupt the cache. Use git for backups instead; the git setup guide shows […]

Leave a Reply

Your email address will not be published. Required fields are marked *